Cette page a été traduite par une machine et n'a pas encore été révisée par une personne. L'anglais est la référence ; les corrections sont les bienvenues sur GitHub. GitHub
Cookwala / SDK et scénarios / 079
A food bank's day as the Cairo flow records it: offer, claim, handover, distribution
Follow the food-bank-cairo example flow through its SMS messages, then check and validate the documents the gateway wrote from them. Nothing here is a real program; it is the example flow in the repository.
Lire d'abord: /docs/HUMANITARIAN-PROFILE/ /humanitarian/
Étapes
The supermarket's first line: tomatoes, ambient, best before 11 November.
parseSmsThe second line: yogurt, chilled at 3.8 °C.
parseSmsThe food bank claims the grouped offer.
parseSmsAt pickup 74 kg are accepted and 6 kg of tomatoes rejected for damaged packaging; the yogurt reads 4.4 °C.
parseSmsThe kitchen reports the next day's distribution.
parseSmsThe offer the gateway wrote, checked with the basic pack: no findings.
humanitarianCheckThe recorded distribution, with its audience groups and an empty findings list, validates.
validate
Résultat
You have read one example day end to end and know which document each message becomes. Next: scenario 075 shows the month's impact summary computed from such days.
Ligne de commande
cookwala sms "OFFER 80KG TOMATOES A BB1111"
cookwala sms "HAND 012 74 REJ 6 PACK T4.4"
cookwala humanitarian examples/humanitarian/flows/food-bank-cairo/*.jsonSortie enregistrée
Statut: ok
[1] parseSms: {"ok": true, "command": "OFFER", "kg": 80.0, "item": "tomatoes", "storage": "ambient", "dateMark": {"kind": "best_before", "dayMonth": "11-11"}, "findings": []}
[2] parseSms: {"ok": true, "command": "OFFER", "kg": 24.0, "item": "yogurt", "storage": "chilled", "tempC": 3.8, "dateMark": {"kind": "use_by", "dayMonth": "12-11"}, "foodClasses": ["dairy"], "findings": []}
[3] parseSms: {"ok": true, "command": "CLAIM", "offer": "012", "all": true, "findings": []}
[4] parseSms: {"ok": true, "command": "HAND", "offer": "012", "kgAccepted": 74.0, "kgRejected": 6.0, "reason": "packaging_damaged", "reasonCode": "PACK", "tempC": 4.4, "findings": []}
[5] parseSms: {"ok": true, "command": "DIST", "meals": 410, "people": 410, "kg": 96.0, "findings": []}
[6] humanitarianCheck: {"results": [{"id": "of-2026-11-09-012", "kind": "Offer", "findings": []}]}
[7] validate: {"ok": true, "errors": []}Code
Exécuter: python scenarios/out/079-a-food-bank-day-from-offer-to-distribution/python.py
# Scenario 079: A food bank's day as the Cairo flow records it: offer, claim, handover, distribution
# Follow the food-bank-cairo example flow through its SMS messages, then check and validate the documents the gateway wrote from them. Nothing here is a real program; it is the example flow in the repository.
# Run a hub first: python hub/cookwala_hub.py --recipes examples
import json, os
from cookwala.client import CookwalaClient, CookwalaProblem
def load(path):
with open(path, encoding="utf-8") as f:
return json.load(f)
def pick(obj, path):
for part in path.replace("]", "").replace("[", ".").split("."):
obj = obj[int(part)] if part.isdigit() else (len(obj) if part == "length" else obj.get(part))
return obj
c = CookwalaClient(os.environ.get("COOKWALA_HUB", "http://localhost:7878"))
# Step 1: The supermarket's first line: tomatoes, ambient, best before 11 November.
tomatoes = c.parse_sms("OFFER 80KG TOMATOES A BB1111")
assert pick(tomatoes, "ok") == True, pick(tomatoes, "ok")
print("ok", "ok", "=", True)
assert pick(tomatoes, "dateMark.dayMonth") == "11-11", pick(tomatoes, "dateMark.dayMonth")
print("ok", "dateMark.dayMonth", "=", "11-11")
assert pick(tomatoes, "findings.length") == 0, pick(tomatoes, "findings.length")
print("ok", "findings.length", "=", 0)
# Step 2: The second line: yogurt, chilled at 3.8 °C.
yogurt = c.parse_sms("OFFER 24KG YOGURT C 3.8C UB1211")
assert pick(yogurt, "storage") == "chilled", pick(yogurt, "storage")
print("ok", "storage", "=", "chilled")
assert pick(yogurt, "tempC") == 3.8, pick(yogurt, "tempC")
print("ok", "tempC", "=", 3.8)
assert pick(yogurt, "findings.length") == 0, pick(yogurt, "findings.length")
print("ok", "findings.length", "=", 0)
# Step 3: The food bank claims the grouped offer.
claim = c.parse_sms("CLAIM 012 ALL")
assert pick(claim, "command") == "CLAIM", pick(claim, "command")
print("ok", "command", "=", "CLAIM")
assert pick(claim, "all") == True, pick(claim, "all")
print("ok", "all", "=", True)
# Step 4: At pickup 74 kg are accepted and 6 kg of tomatoes rejected for damaged packaging; the yogurt reads 4.4 °C.
hand = c.parse_sms("HAND 012 74 REJ 6 PACK T4.4")
assert pick(hand, "kgAccepted") == 74.0, pick(hand, "kgAccepted")
print("ok", "kgAccepted", "=", 74.0)
assert pick(hand, "kgRejected") == 6.0, pick(hand, "kgRejected")
print("ok", "kgRejected", "=", 6.0)
assert pick(hand, "reason") == "packaging_damaged", pick(hand, "reason")
print("ok", "reason", "=", "packaging_damaged")
assert pick(hand, "tempC") == 4.4, pick(hand, "tempC")
print("ok", "tempC", "=", 4.4)
# Step 5: The kitchen reports the next day's distribution.
dist = c.parse_sms("DIST 410 MEALS 410 PEOPLE 96KG")
assert pick(dist, "meals") == 410, pick(dist, "meals")
print("ok", "meals", "=", 410)
assert pick(dist, "kg") == 96.0, pick(dist, "kg")
print("ok", "kg", "=", 96.0)
# Step 6: The offer the gateway wrote, checked with the basic pack: no findings.
checked = c.humanitarian_check([{"profile": "0.2.0", "kind": "Offer", "id": "of-2026-11-09-012", "donor": "did:web:supermarket.example", "createdAt": "2026-11-09T17:40:00+02:00", "items": [{"lineId": "1", "name": "Tomatoes", "ingredientId": "cw.ing.tomato", "kg": 80, "storage": "ambient", "origin": "retail", "dateMark": {"kind": "best_before", "date": "2026-11-11"}, "allergens": []}, {"lineId": "2", "name": "Yogurt cups", "gtin": "6221234567890", "kg": 24, "units": 160, "storage": "chilled", "origin": "retail", "dateMark": {"kind": "use_by", "date": "2026-11-12"}, "allergens": ["milk"]}, {"lineId": "3", "name": "Bread", "kg": 30, "storage": "ambient", "origin": "retail", "dateMark": {"kind": "best_before", "date": "2026-11-10"}, "allergens": ["cereals_gluten"]}], "window": {"from": "2026-11-09T18:00:00+02:00", "to": "2026-11-10T08:00:00+02:00"}, "site": {"country": "EG", "admin1": "Cairo", "admin2": "Nasr City", "siteName": "Supermarket loading bay"}, "readings": [{"at": "2026-11-09T17:35:00+02:00", "tempC": 3.8, "method": "fridge_display", "lineId": "2"}], "needs": ["refrigerated_vehicle"], "state": "distributed", "version": 5, "note": "Sent by SMS: OFFER 80KG TOMATOES A BB1111; OFFER 24KG YOGURT C 3.8C UB1211; OFFER 30KG BREAD A BB1011. Gateway grouped them under one offer id."}], ["basic-nutrition-food-safety"])
assert pick(checked, "results[0].findings.length") == 0, pick(checked, "results[0].findings.length")
print("ok", "results[0].findings.length", "=", 0)
# Step 7: The recorded distribution, with its audience groups and an empty findings list, validates.
dist2 = c.validate("humanitarian", load("examples/humanitarian/flows/food-bank-cairo/distribution.json"))
assert pick(dist2, "ok") == True, pick(dist2, "ok")
print("ok", "ok", "=", True)
print("scenario complete")
scenarios/079-a-food-bank-day-from-offer-to-distribution.json