Esta página fue traducida por una máquina y aún no ha sido revisada por una persona. El inglés es la referencia; las correcciones son bienvenidas en GitHub. GitHub

Cookwala / SDK y escenarios / 068

Check the Cairo food bank's recorded offer against the rule packs

The food-bank-cairo flow records a supermarket offer of tomatoes, yogurt and bread with a fridge reading of 3.8 °C. Check it with the basic pack and with the care pack added, validate it, and parse the SMS the offer came from.

Audiencia: food bank · Objetivo: Ayudar a acabar con el hambre · Nivel: beginner

Leer primero: /docs/HUMANITARIAN-PROFILE/ /humanitarian/

Pasos

  1. The basic WHO/Codex pack finds nothing: the yogurt reading is under 5 °C and every date mark is in the future. humanitarianCheck

  2. Adding the care pack for vulnerable groups changes nothing for this offer. humanitarianCheck

  3. The document validates as a Humanitarian Profile document. validate

  4. The yogurt line as it was sent by SMS, per the offer's note: chilled at 3.8 °C, use by 12 November, no gateway finding. parseSms

Resultado

You have checked a real example document against two packs and seen a clean result. Next: scenario 070 checks an offer that fails.

Línea de comandos

cookwala humanitarian examples/humanitarian/flows/food-bank-cairo/offer.json
cookwala humanitarian --pack profiles/humanitarian/basic-nutrition-food-safety.rulepack.json --pack profiles/humanitarian/care-vulnerable-groups.rulepack.json examples/humanitarian/flows/food-bank-cairo/offer.json
cookwala sms "OFFER 24KG YOGURT C 3.8C UB1211"

Salida grabada

Estado: ok

[1] humanitarianCheck: {"results": [{"id": "of-2026-11-09-012", "kind": "Offer", "findings": []}]}
[2] humanitarianCheck: {"results": [{"id": "of-2026-11-09-012", "kind": "Offer", "findings": []}]}
[3] validate: {"ok": true, "errors": []}
[4] 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": []}

Código

Ejecutar: python scenarios/out/068-check-the-cairo-food-banks-offer/python.py

# Scenario 068: Check the Cairo food bank's recorded offer against the rule packs
# The food-bank-cairo flow records a supermarket offer of tomatoes, yogurt and bread with a fridge reading of 3.8 °C. Check it with the basic pack and with the care pack added, validate it, and parse the SMS the offer came from.
# 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 basic WHO/Codex pack finds nothing: the yogurt reading is under 5 °C and every date mark is in the future.
basic = 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(basic, "results[0].id") == "of-2026-11-09-012", pick(basic, "results[0].id")
print("ok", "results[0].id", "=", "of-2026-11-09-012")
assert pick(basic, "results[0].kind") == "Offer", pick(basic, "results[0].kind")
print("ok", "results[0].kind", "=", "Offer")
assert pick(basic, "results[0].findings.length") == 0, pick(basic, "results[0].findings.length")
print("ok", "results[0].findings.length", "=", 0)

# Step 2: Adding the care pack for vulnerable groups changes nothing for this offer.
care = 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", "care-vulnerable-groups"])
assert pick(care, "results[0].findings.length") == 0, pick(care, "results[0].findings.length")
print("ok", "results[0].findings.length", "=", 0)

# Step 3: The document validates as a Humanitarian Profile document.
valid = c.validate("humanitarian", load("examples/humanitarian/flows/food-bank-cairo/offer.json"))
assert pick(valid, "ok") == True, pick(valid, "ok")
print("ok", "ok", "=", True)
assert pick(valid, "errors.length") == 0, pick(valid, "errors.length")
print("ok", "errors.length", "=", 0)

# Step 4: The yogurt line as it was sent by SMS, per the offer's note: chilled at 3.8 °C, use by 12 November, no gateway finding.
yogurt = c.parse_sms("OFFER 24KG YOGURT C 3.8C UB1211")
assert pick(yogurt, "tempC") == 3.8, pick(yogurt, "tempC")
print("ok", "tempC", "=", 3.8)
assert pick(yogurt, "dateMark.dayMonth") == "12-11", pick(yogurt, "dateMark.dayMonth")
print("ok", "dateMark.dayMonth", "=", "12-11")
assert pick(yogurt, "findings.length") == 0, pick(yogurt, "findings.length")
print("ok", "findings.length", "=", 0)

print("scenario complete")

scenarios/068-check-the-cairo-food-banks-offer.json

Anterior: 067 Siguiente: 069