fix(price): normalize cantitate_roa < 1 in price comparison (false mismatch)
Kit detection only checked cantitate_roa > 1, missing fractional values like 0.5 (GoMag 50buc/set → ROA 100buc/set). This caused false price difference alerts (e.g. GoMag 7.00 vs ROA 14.00 for order #481595156). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -705,7 +705,7 @@ def get_prices_for_order(items: list[dict], app_settings: dict, conn=None) -> di
|
|||||||
|
|
||||||
is_kit = len(codmat_details) > 1 or (
|
is_kit = len(codmat_details) > 1 or (
|
||||||
len(codmat_details) == 1
|
len(codmat_details) == 1
|
||||||
and float(codmat_details[0].get("cantitate_roa") or 1) > 1
|
and float(codmat_details[0].get("cantitate_roa") or 1) != 1
|
||||||
)
|
)
|
||||||
|
|
||||||
pret_roa_total = 0.0
|
pret_roa_total = 0.0
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ def make_order(items, discount_total=0.0, delivery_cost=0.0, discount_vat=None):
|
|||||||
def is_kit(comps):
|
def is_kit(comps):
|
||||||
"""Kit detection pattern used in validation_service and price_sync_service."""
|
"""Kit detection pattern used in validation_service and price_sync_service."""
|
||||||
return len(comps) > 1 or (
|
return len(comps) > 1 or (
|
||||||
len(comps) == 1 and (comps[0].get("cantitate_roa") or 1) > 1
|
len(comps) == 1 and (comps[0].get("cantitate_roa") or 1) != 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -492,3 +492,126 @@ class TestResolveCodmatIds:
|
|||||||
codmats = [c["codmat"] for c in result["SKU1"]]
|
codmats = [c["codmat"] for c in result["SKU1"]]
|
||||||
assert "COD1" in codmats
|
assert "COD1" in codmats
|
||||||
assert "COD2" in codmats
|
assert "COD2" in codmats
|
||||||
|
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# Group 6: get_prices_for_order() — cantitate_roa price normalization
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
from app.services.validation_service import get_prices_for_order
|
||||||
|
|
||||||
|
|
||||||
|
def _mock_oracle_conn(pol_cu_tva=False, price_map=None):
|
||||||
|
"""Build a mock Oracle connection for get_prices_for_order.
|
||||||
|
|
||||||
|
price_map: {id_articol: (pret, proc_tvav)}
|
||||||
|
"""
|
||||||
|
if price_map is None:
|
||||||
|
price_map = {}
|
||||||
|
conn = MagicMock()
|
||||||
|
|
||||||
|
def cursor_ctx():
|
||||||
|
cur = MagicMock()
|
||||||
|
# CRM_POLITICI_PRETURI — PRETURI_CU_TVA flag
|
||||||
|
cu_tva_row = [1 if pol_cu_tva else 0]
|
||||||
|
# CRM_POLITICI_PRET_ART — prices
|
||||||
|
price_rows = [
|
||||||
|
(1, id_art, pret, proc_tvav)
|
||||||
|
for id_art, (pret, proc_tvav) in price_map.items()
|
||||||
|
]
|
||||||
|
# fetchone for PRETURI_CU_TVA, __iter__ for price rows
|
||||||
|
cur.fetchone = MagicMock(return_value=cu_tva_row)
|
||||||
|
cur.__iter__ = MagicMock(return_value=iter(price_rows))
|
||||||
|
return cur
|
||||||
|
|
||||||
|
cm = MagicMock()
|
||||||
|
cm.__enter__ = MagicMock(side_effect=cursor_ctx)
|
||||||
|
cm.__exit__ = MagicMock(return_value=False)
|
||||||
|
conn.cursor.return_value = cm
|
||||||
|
return conn
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetPricesForOrderCantitateRoa:
|
||||||
|
"""Regression: cantitate_roa < 1 must be treated as kit for price normalization.
|
||||||
|
|
||||||
|
Bug: SKU with cantitate_roa=0.5 (GoMag 50buc=7lei, ROA 100buc=14lei)
|
||||||
|
was reported as price mismatch because is_kit only checked > 1.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_cantitate_roa_half_matches(self):
|
||||||
|
"""cantitate_roa=0.5: ROA price 14.00 * 0.5 = 7.00 should match GoMag 7.00."""
|
||||||
|
items = [{
|
||||||
|
"sku": "1057308134545",
|
||||||
|
"price": 7.00,
|
||||||
|
"quantity": 60,
|
||||||
|
"codmat_details": [{
|
||||||
|
"codmat": "8OZLRLP",
|
||||||
|
"cantitate_roa": 0.5,
|
||||||
|
"id_articol": 100,
|
||||||
|
"cont": "345",
|
||||||
|
}],
|
||||||
|
}]
|
||||||
|
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["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."""
|
||||||
|
items = [{
|
||||||
|
"sku": "SKU-HALF",
|
||||||
|
"price": 7.00,
|
||||||
|
"quantity": 1,
|
||||||
|
"codmat_details": [{
|
||||||
|
"codmat": "COD1",
|
||||||
|
"cantitate_roa": 0.5,
|
||||||
|
"id_articol": 200,
|
||||||
|
"cont": "345",
|
||||||
|
}],
|
||||||
|
}]
|
||||||
|
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
|
||||||
|
|
||||||
|
def test_cantitate_roa_one_simple_item(self):
|
||||||
|
"""cantitate_roa=1 (default): simple item, direct price comparison."""
|
||||||
|
items = [{
|
||||||
|
"sku": "SKU-SIMPLE",
|
||||||
|
"price": 63.79,
|
||||||
|
"quantity": 8,
|
||||||
|
"codmat_details": [{
|
||||||
|
"codmat": "COD-DIRECT",
|
||||||
|
"cantitate_roa": 1,
|
||||||
|
"id_articol": 300,
|
||||||
|
"cont": "345",
|
||||||
|
}],
|
||||||
|
}]
|
||||||
|
conn = _mock_oracle_conn(pol_cu_tva=True, price_map={300: (63.79, 1.19)})
|
||||||
|
result = get_prices_for_order(items, {"id_pol": "1"}, conn=conn)
|
||||||
|
|
||||||
|
assert result["items"][0]["match"] is True
|
||||||
|
assert result["summary"]["mismatches"] == 0
|
||||||
|
|
||||||
|
def test_cantitate_roa_gt1_kit(self):
|
||||||
|
"""cantitate_roa=2: kit with 2 ROA units per GoMag unit."""
|
||||||
|
items = [{
|
||||||
|
"sku": "SKU-KIT2",
|
||||||
|
"price": 20.00,
|
||||||
|
"quantity": 1,
|
||||||
|
"codmat_details": [{
|
||||||
|
"codmat": "COD-KIT",
|
||||||
|
"cantitate_roa": 2,
|
||||||
|
"id_articol": 400,
|
||||||
|
"cont": "345",
|
||||||
|
}],
|
||||||
|
}]
|
||||||
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user