fix(growth): normalize nested marketplace packs
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
This commit is contained in:
@@ -858,6 +858,8 @@ PRODUCT_TYPES = {
|
||||
COUNT_UNITS = {"入", "組", "瓶", "支", "條", "盒", "包", "袋", "片", "顆", "粒", "錠", "枚", "件", "罐", "杯", "本", "刀把", "刀片", "刀頭", "蕊"}
|
||||
COUNT_UNIT_PATTERN = r"(?:刀把|刀片|刀頭|入|組|瓶|支|條|盒|包|袋|片|張|顆|粒|錠|枚|件|罐|杯|本|蕊)"
|
||||
PIECE_UNITS = {"包", "袋", "片", "張", "顆", "粒", "錠", "枚"}
|
||||
ATOMIC_PIECE_UNITS = {"片", "張", "顆", "粒", "錠", "枚"}
|
||||
PACK_MULTIPLIER_UNITS = {"包", "袋"}
|
||||
CONTAINER_UNITS = {"入", "組", "盒", "罐", "杯", "本", "瓶", "支", "條", "件"}
|
||||
COUNT_UNIT_FAMILIES = {
|
||||
"刀片": "blade",
|
||||
@@ -1210,14 +1212,32 @@ def _extract_specs(
|
||||
counts.append((2, "入"))
|
||||
|
||||
total_piece_count = None
|
||||
explicit_total = re.search(r"共\s*(\d+)\s*([包袋片顆粒錠枚])", text)
|
||||
explicit_total = re.search(r"共\s*(\d+)\s*([包袋片張顆粒錠枚])", text)
|
||||
if explicit_total:
|
||||
total_piece_count = int(explicit_total.group(1))
|
||||
else:
|
||||
atomic_piece_counts = [
|
||||
count for count, unit in counts if unit in ATOMIC_PIECE_UNITS
|
||||
]
|
||||
piece_counts = [count for count, unit in counts if unit in PIECE_UNITS]
|
||||
container_counts = [count for count, unit in counts if unit in CONTAINER_UNITS]
|
||||
if piece_counts and container_counts:
|
||||
total_piece_count = max(piece_counts) * max(container_counts)
|
||||
container_multiplier_by_unit = {
|
||||
unit: max(count for count, candidate_unit in counts if candidate_unit == unit)
|
||||
for unit in CONTAINER_UNITS
|
||||
if any(candidate_unit == unit for _, candidate_unit in counts)
|
||||
}
|
||||
multiplier_by_unit = {
|
||||
unit: max(count for count, candidate_unit in counts if candidate_unit == unit)
|
||||
for unit in PACK_MULTIPLIER_UNITS | CONTAINER_UNITS
|
||||
if any(candidate_unit == unit for _, candidate_unit in counts)
|
||||
}
|
||||
if atomic_piece_counts and multiplier_by_unit:
|
||||
total_piece_count = max(atomic_piece_counts)
|
||||
for multiplier in multiplier_by_unit.values():
|
||||
total_piece_count *= multiplier
|
||||
elif piece_counts and container_multiplier_by_unit:
|
||||
total_piece_count = max(piece_counts)
|
||||
for multiplier in container_multiplier_by_unit.values():
|
||||
total_piece_count *= multiplier
|
||||
elif piece_counts:
|
||||
total_piece_count = max(piece_counts)
|
||||
|
||||
@@ -1782,6 +1802,17 @@ def _has_overlapping_base_spec(left: ProductIdentity, right: ProductIdentity) ->
|
||||
return False
|
||||
return _close_number(left_weights[0], right_weights[0])
|
||||
|
||||
if left.total_piece_count or right.total_piece_count:
|
||||
if not left.total_piece_count or not right.total_piece_count:
|
||||
return False
|
||||
left_units = {
|
||||
unit for _, unit in left.counts if unit in ATOMIC_PIECE_UNITS
|
||||
}
|
||||
right_units = {
|
||||
unit for _, unit in right.counts if unit in ATOMIC_PIECE_UNITS
|
||||
}
|
||||
return bool(left_units & right_units)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@@ -1798,7 +1829,11 @@ def _single_unit_total(identity: ProductIdentity) -> tuple[Optional[str], Option
|
||||
multiplier = identity.total_piece_count or _pack_multiplier(identity)
|
||||
return "g", weights[0] * multiplier, "ok"
|
||||
if identity.total_piece_count:
|
||||
return "入", float(identity.total_piece_count), "ok"
|
||||
atomic_units = {
|
||||
unit for _, unit in identity.counts if unit in ATOMIC_PIECE_UNITS
|
||||
}
|
||||
unit = next(iter(atomic_units)) if len(atomic_units) == 1 else "入"
|
||||
return unit, float(identity.total_piece_count), "ok"
|
||||
return None, None, "missing_single_unit"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user