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^