import json from pathlib import Path import unittest from app.market import MarketService from app.market.models import InquiryRequest from app.repository import RDFRepository ROOT = Path(__file__).resolve().parents[1] HAIER = "https://gesli.example/sample#Haier" HISENSE = "https://gesli.example/sample#Hisense" class MarketEngineTest(unittest.TestCase): def setUp(self): self.service = MarketService(ROOT, RDFRepository(ROOT)) def test_default_inquiry_builds_three_ranked_solutions(self): result = self.service.recommend(InquiryRequest(customer=HAIER)) self.assertEqual( result["pipeline"], { "discovered": 9, "rejected": 6, "feasible": 3, "generated_solutions": 3, }, ) self.assertEqual(result["recommendation"]["solution_type"], "均衡方案") self.assertEqual(result["recommendation"]["supplier_name"], "马士基青岛分支机构") self.assertEqual( {candidate["solution_type"] for candidate in result["candidates"]}, {"经济方案", "均衡方案", "时效方案"}, ) def test_form_only_exposes_routes_with_market_context(self): options = self.service.form_options() self.assertEqual(options["origins"], ["青岛港", "青岛胶东机场"]) self.assertEqual(options["destinations"], ["汉堡港", "法兰克福机场", "洛杉矶港"]) self.assertEqual(options["route_types"], ["中转", "直航", "直达"]) self.assertEqual(len(options["routes"]), 3) def test_customer_profile_changes_recommendation(self): haier = self.service.recommend(InquiryRequest(customer=HAIER)) hisense = self.service.recommend(InquiryRequest(customer=HISENSE)) self.assertEqual(haier["recommendation"]["solution_type"], "均衡方案") self.assertEqual(hisense["recommendation"]["solution_type"], "经济方案") self.assertNotEqual( haier["recommendation"]["final_quote_amount"], hisense["recommendation"]["final_quote_amount"], ) def test_expired_quotes_are_rejected_with_reasons(self): result = self.service.recommend(InquiryRequest(customer=HAIER)) rejected = {item["quote_no"]: item for item in result["rejected_candidates"]} self.assertIn("SQ-EGL-20260710-EXPIRED", rejected) self.assertTrue( any("报价已于2026-07-18失效" in reason for reason in rejected["SQ-EGL-20260710-EXPIRED"]["reasons"]) ) def test_dangerous_goods_uses_only_specialized_candidates(self): inquiry = InquiryRequest( customer="https://gesli.example/sample#Sailun", dangerous_goods=True, ) result = self.service.recommend(inquiry) self.assertEqual(result["pipeline"]["feasible"], 3) self.assertTrue( all("危险品" in candidate["product_name"] for candidate in result["candidates"]) ) def test_hamburg_route_builds_three_solutions(self): result = self.service.recommend(InquiryRequest( customer="https://gesli.example/sample#Midea", destination="汉堡港", requested_departure_date="2026-07-28", max_transit_days=36, target_amount=42500, )) self.assertEqual(result["pipeline"]["feasible"], 3) self.assertEqual(result["pipeline"]["rejected"], 1) def test_time_sensitive_air_customer_gets_express_solution(self): result = self.service.recommend(InquiryRequest( customer="https://gesli.example/sample#QingdaoMedTech", origin="青岛胶东机场", destination="法兰克福机场", requested_departure_date="2026-07-27", max_transit_days=6, target_amount=68000, preferred_route_type="直达", )) self.assertEqual(result["recommendation"]["solution_type"], "时效方案") self.assertEqual(result["recommendation"]["supplier_name"], "汉莎货运青岛代理") def test_sales_response_does_not_expose_supplier_cost(self): result = self.service.recommend(InquiryRequest(customer=HAIER)) serialized = json.dumps(result, ensure_ascii=False) self.assertNotIn("supplier_cost", serialized) self.assertNotIn("supplierCostAmount", serialized) self.assertIn("cost_risk_status", serialized) def test_decision_audit_is_recorded_as_rdf_assertions(self): result = self.service.recommend(InquiryRequest(customer=HAIER)) audit = self.service.get_audit(result["run_id"]) self.assertIsNotNone(audit) self.assertEqual(audit["candidate_count"], 3) self.assertGreaterEqual(audit["rdf_assertions"], 9) if __name__ == "__main__": unittest.main()