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.

Audience: regulator · Objectif: Aider à éradiquer la faim, Rendre les gens en meilleure santé · Niveau: beginner

Lire d'abord: /docs/HUMANITARIAN-PROFILE/ /humanitarian/

Étapes

  1. The supermarket's first line: tomatoes, ambient, best before 11 November. parseSms

  2. The second line: yogurt, chilled at 3.8 °C. parseSms

  3. The food bank claims the grouped offer. parseSms

  4. At pickup 74 kg are accepted and 6 kg of tomatoes rejected for damaged packaging; the yogurt reads 4.4 °C. parseSms

  5. The kitchen reports the next day's distribution. parseSms

  6. The offer the gateway wrote, checked with the basic pack: no findings. humanitarianCheck

  7. The 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/*.json

Sortie 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

Précédent: 078 Suivant: 080