hyf

Context-aware query service for Radroots
git clone https://radroots.dev/git/hyf.git
Log | Files | Refs | README | LICENSE

buyer_operation.mojo (8299B)


      1 from std.collections import List
      2 from json import Value, loads
      3 
      4 from hyf_application.context import interpretation_source
      5 from hyf_core.domain.eligibility import (
      6     ConstraintAssessment,
      7     compose_eligibility,
      8     constraint_assessment,
      9 )
     10 
     11 
     12 def _has_key(value: Value, key: String) -> Bool:
     13     for candidate in value.object_keys():
     14         if candidate == key:
     15             return True
     16     return False
     17 
     18 
     19 def _string_list(value: Value) raises -> List[String]:
     20     var items = List[String]()
     21     if not value.is_array():
     22         return items^
     23     for entry in value.array_items():
     24         if entry.is_string():
     25             items.append(entry.string_value())
     26     return items^
     27 
     28 
     29 def _validate_source(input: Value) raises:
     30     if not input.is_object() or not _has_key(input, "source"):
     31         raise Error("buyer operation input requires 'source'")
     32     var source = input["source"]
     33     _ = interpretation_source(
     34         source_id=source["source_id"].string_value(),
     35         revision=source["revision"].string_value(),
     36         text=source["text"].string_value(),
     37         source_time=source["source_time"].string_value(),
     38         timezone=source["timezone"].string_value(),
     39         actor_id=source["actor_id"].string_value(),
     40         farm_id=source["farm_id"].string_value(),
     41     )
     42 
     43 
     44 def execute_buyer_request_interpret(input: Value) raises -> Value:
     45     _validate_source(input)
     46     var phrases = List[String]()
     47     if _has_key(input, "products"):
     48         phrases = _string_list(input["products"])
     49 
     50     var lines = loads("[]")
     51     var index = 1
     52     for phrase in phrases:
     53         var line = loads("{}")
     54         line.set("line_id", Value("line-" + String(index)))
     55         var product = loads("{}")
     56         product.set("phrase", Value(String(phrase)))
     57         product.set("catalogue_id", Value(String(phrase)))
     58         product.set("resolution", Value("resolved"))
     59         line.set("product", product)
     60         var quantity = loads("{}")
     61         quantity.set("state", Value("unknown"))
     62         line.set("quantity", quantity)
     63         line.set("conditions", loads("[]"))
     64         line.set("evidence", loads("[]"))
     65         line.set("review_required", Value(True))
     66         lines.append(line)
     67         index += 1
     68 
     69     var output = loads("{}")
     70     output.set("demand_lines", lines)
     71     var review = loads("{}")
     72     review.set("required", Value(len(phrases) == 0))
     73     var clarifications = loads("[]")
     74     if len(phrases) == 0:
     75         var clarification = loads("{}")
     76         clarification.set("field", Value("demand_lines"))
     77         clarification.set("reason", Value("information_needed"))
     78         clarifications.append(clarification)
     79     review.set("clarifications", clarifications)
     80     output.set("review", review)
     81     var execution = loads("{}")
     82     execution.set("status", Value("complete"))
     83     execution.set("provider_calls", Value(0))
     84     output.set("execution", execution)
     85     return output^
     86 
     87 
     88 def _assessment_value(
     89     lot_id: String, checks: List[ConstraintAssessment]
     90 ) raises -> Value:
     91     var value = loads("{}")
     92     value.set("candidate_id", Value(String(lot_id)))
     93     value.set("eligibility", Value(compose_eligibility(checks)))
     94     var check_values = loads("[]")
     95     for check in checks:
     96         var entry = loads("{}")
     97         entry.set("kind", Value(String(check.kind)))
     98         entry.set("result", Value(String(check.result)))
     99         entry.set("reason", Value(String(check.reason)))
    100         entry.set("evidence", loads("[]"))
    101         check_values.append(entry)
    102     value.set("checks", check_values)
    103     return value^
    104 
    105 
    106 def execute_buyer_request_match(input: Value) raises -> Value:
    107     if not input.is_object() or not _has_key(input, "need"):
    108         raise Error("buyer_request.match input requires 'need'")
    109     if not _has_key(input, "snapshots"):
    110         raise Error("buyer_request.match input requires 'snapshots'")
    111 
    112     var need = input["need"]
    113     var required_phrase = ""
    114     if _has_key(need, "product_phrase"):
    115         required_phrase = need["product_phrase"].string_value()
    116     var required_value = 0
    117     var required_scale = 0
    118     var required_unit = "kg"
    119     if _has_key(need, "quantity"):
    120         var quantity = need["quantity"]
    121         if _has_key(quantity, "value"):
    122             required_value = Int(quantity["value"].int_value())
    123         if _has_key(quantity, "scale"):
    124             required_scale = Int(quantity["scale"].int_value())
    125         if _has_key(quantity, "unit"):
    126             required_unit = quantity["unit"].string_value()
    127 
    128     var assessments = loads("[]")
    129     var plans = loads("[]")
    130     var plan_index = 1
    131     for snapshot in input["snapshots"].array_items():
    132         var lot_id = snapshot["lot_id"].string_value()
    133         var supplier_id = ""
    134         if _has_key(snapshot, "supplier_id"):
    135             supplier_id = snapshot["supplier_id"].string_value()
    136         var lot_phrase = required_phrase
    137         if _has_key(snapshot, "product_phrase"):
    138             lot_phrase = snapshot["product_phrase"].string_value()
    139 
    140         var checks = List[ConstraintAssessment]()
    141         checks.append(
    142             constraint_assessment(
    143                 "product",
    144                 "pass" if required_phrase == lot_phrase else "fail",
    145                 True,
    146                 "product_match" if required_phrase
    147                 == lot_phrase else "product_mismatch",
    148             )
    149         )
    150         var available_state = "unknown"
    151         if _has_key(snapshot, "unreserved_state"):
    152             available_state = snapshot["unreserved_state"].string_value()
    153         checks.append(
    154             constraint_assessment(
    155                 "availability",
    156                 "pass" if available_state == "known" else "unknown",
    157                 True,
    158                 "availability_known" if available_state
    159                 == "known" else "stock_unknown",
    160             )
    161         )
    162         if available_state == "known" and required_value > 0:
    163             var available_value = Int(snapshot["unreserved_value"].int_value())
    164             var available_scale = Int(snapshot["unreserved_scale"].int_value())
    165             var comparison = "fail"
    166             if available_value >= required_value:
    167                 comparison = "pass"
    168             checks.append(
    169                 constraint_assessment(
    170                     "quantity",
    171                     comparison,
    172                     True,
    173                     "quantity_sufficient" if comparison
    174                     == "pass" else "quantity_insufficient",
    175                 )
    176             )
    177         assessments.append(_assessment_value(lot_id, checks))
    178 
    179         if compose_eligibility(checks) == "eligible" and supplier_id != "":
    180             var plan = loads("{}")
    181             plan.set("plan_id", Value("plan-" + String(plan_index)))
    182             plan.set("supplier_id", Value(String(supplier_id)))
    183             var allocations = loads("[]")
    184             var allocation = loads("{}")
    185             allocation.set("lot_id", Value(String(lot_id)))
    186             allocation.set("line_id", Value("line-1"))
    187             var quantity = loads("{}")
    188             quantity.set("state", Value("known"))
    189             quantity.set("value", Value(required_value))
    190             quantity.set("unit", Value(String(required_unit)))
    191             quantity.set("qualifier", Value("exact"))
    192             allocation.set("quantity", quantity)
    193             allocations.append(allocation)
    194             plan.set("allocations", allocations)
    195             var coverage = loads("{}")
    196             coverage.set("lines_covered", loads('["line-1"]'))
    197             coverage.set("uncovered", loads("[]"))
    198             coverage.set("partial", Value(False))
    199             plan.set("coverage", coverage)
    200             plan.set("unresolved", loads("[]"))
    201             plans.append(plan)
    202             plan_index += 1
    203 
    204     var output = loads("{}")
    205     output.set("assessments", assessments)
    206     output.set("plans", plans)
    207     var limitations = loads("{}")
    208     limitations.set("scope", Value("supplied_only"))
    209     limitations.set("truncated", Value(False))
    210     limitations.set("supported_mode", Value("single_supplier_compatible_lots"))
    211     limitations.set("unsupported", loads('["multi_supplier"]'))
    212     output.set("limitations", limitations)
    213     var execution = loads("{}")
    214     execution.set("status", Value("complete"))
    215     execution.set("provider_calls", Value(0))
    216     output.set("execution", execution)
    217     return output^