From ffd4cc08006b136c0aee7e19bd19df1cedab3db6 Mon Sep 17 00:00:00 2001 From: Claude Agent Date: Thu, 2 Apr 2026 13:01:41 +0000 Subject: [PATCH] fix(price): skip price check for kit/complex articles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kit articles (multi-component or cantitate_roa≠1) have expected price differences between GoMag (commercial) and ROA (component sum). Skip comparison entirely, mark with kit=True flag for UI badge. Fix kit detection to use float()!=1 (catches cantitate_roa<1 like 0.5). Update 3 existing tests + add multi-component kit test. Co-Authored-By: Claude Opus 4.6 (1M context) --- api/app/routers/sync.py | 2 ++ api/app/services/validation_service.py | 8 +++++- api/tests/test_business_rules.py | 39 +++++++++++++++++++------- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/api/app/routers/sync.py b/api/app/routers/sync.py index 7e9b6d0..b148a21 100644 --- a/api/app/routers/sync.py +++ b/api/app/routers/sync.py @@ -463,6 +463,8 @@ async def order_detail(order_number: str): if pi: item["pret_roa"] = pi.get("pret_roa") item["price_match"] = pi.get("match") + if pi.get("kit"): + item["kit"] = True order_price_check = price_data.get("summary", {}) # Cache price_match in SQLite if changed if order_price_check.get("oracle_available") is not False: diff --git a/api/app/services/validation_service.py b/api/app/services/validation_service.py index 490e1d0..361b8ca 100644 --- a/api/app/services/validation_service.py +++ b/api/app/services/validation_service.py @@ -544,7 +544,7 @@ def sync_prices_from_order(orders, mapped_codmat_data: dict, direct_id_map: dict # Build set of kit/bax SKUs (>1 component, or single component with cantitate_roa > 1) kit_skus = {sku for sku, comps in mapped_codmat_data.items() - if len(comps) > 1 or (len(comps) == 1 and (comps[0].get("cantitate_roa") or 1) > 1)} + if len(comps) > 1 or (len(comps) == 1 and float(comps[0].get("cantitate_roa") or 1) != 1)} updated = [] own_conn = conn is None @@ -708,6 +708,12 @@ def get_prices_for_order(items: list[dict], app_settings: dict, conn=None) -> di and float(codmat_details[0].get("cantitate_roa") or 1) != 1 ) + if is_kit: + # Kit/pachet: prețul GoMag e comercial, ROA e suma componente din lista + # de prețuri — diferența e gestionată de discount line + result_items[idx]["kit"] = True + continue + pret_roa_total = 0.0 all_resolved = True diff --git a/api/tests/test_business_rules.py b/api/tests/test_business_rules.py index 854a640..d83f600 100644 --- a/api/tests/test_business_rules.py +++ b/api/tests/test_business_rules.py @@ -539,7 +539,7 @@ class TestGetPricesForOrderCantitateRoa: """ def test_cantitate_roa_half_matches(self): - """cantitate_roa=0.5: ROA price 14.00 * 0.5 = 7.00 should match GoMag 7.00.""" + """cantitate_roa=0.5: kit item — price check skipped entirely.""" items = [{ "sku": "1057308134545", "price": 7.00, @@ -554,12 +554,12 @@ class TestGetPricesForOrderCantitateRoa: conn = _mock_oracle_conn(pol_cu_tva=True, price_map={100: (14.00, 1.19)}) result = get_prices_for_order(items, {"id_pol": "1"}, conn=conn) - assert result["items"][0]["match"] is True - assert abs(result["items"][0]["pret_roa"] - 7.00) < 0.01 + assert result["items"][0]["match"] is None + assert result["items"][0]["kit"] is True assert result["summary"]["mismatches"] == 0 def test_cantitate_roa_half_mismatch(self): - """cantitate_roa=0.5: ROA price 10.00 * 0.5 = 5.00 != GoMag 7.00.""" + """cantitate_roa=0.5: kit item — price check skipped even if prices differ.""" items = [{ "sku": "SKU-HALF", "price": 7.00, @@ -574,9 +574,9 @@ class TestGetPricesForOrderCantitateRoa: conn = _mock_oracle_conn(pol_cu_tva=True, price_map={200: (10.00, 1.19)}) result = get_prices_for_order(items, {"id_pol": "1"}, conn=conn) - assert result["items"][0]["match"] is False - assert abs(result["items"][0]["pret_roa"] - 5.00) < 0.01 - assert result["summary"]["mismatches"] == 1 + assert result["items"][0]["match"] is None + assert result["items"][0]["kit"] is True + assert result["summary"]["mismatches"] == 0 def test_cantitate_roa_one_simple_item(self): """cantitate_roa=1 (default): simple item, direct price comparison.""" @@ -598,7 +598,7 @@ class TestGetPricesForOrderCantitateRoa: assert result["summary"]["mismatches"] == 0 def test_cantitate_roa_gt1_kit(self): - """cantitate_roa=2: kit with 2 ROA units per GoMag unit.""" + """cantitate_roa=2: kit item — price check skipped.""" items = [{ "sku": "SKU-KIT2", "price": 20.00, @@ -613,5 +613,24 @@ class TestGetPricesForOrderCantitateRoa: conn = _mock_oracle_conn(pol_cu_tva=True, price_map={400: (10.00, 1.19)}) result = get_prices_for_order(items, {"id_pol": "1"}, conn=conn) - assert result["items"][0]["match"] is True - assert abs(result["items"][0]["pret_roa"] - 20.00) < 0.01 + assert result["items"][0]["match"] is None + assert result["items"][0]["kit"] is True + assert result["summary"]["mismatches"] == 0 + + def test_multi_component_kit_skipped(self): + """Multi-component kit (2 CODMATs): price check skipped, kit=True.""" + items = [{ + "sku": "SKU-MULTI", + "price": 15.00, + "quantity": 1, + "codmat_details": [ + {"codmat": "COMP-A", "cantitate_roa": 1, "id_articol": 500, "cont": "345"}, + {"codmat": "COMP-B", "cantitate_roa": 1, "id_articol": 501, "cont": "345"}, + ], + }] + conn = _mock_oracle_conn(pol_cu_tva=True, price_map={500: (8.00, 1.19), 501: (9.00, 1.19)}) + result = get_prices_for_order(items, {"id_pol": "1"}, conn=conn) + + assert result["items"][0]["match"] is None + assert result["items"][0]["kit"] is True + assert result["summary"]["mismatches"] == 0