61 lines
1.7 KiB
Python
61 lines
1.7 KiB
Python
from dataclasses import dataclass
|
|
|
|
from commerce.models import Product, ProductBinding, SourceSystem
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ProductMatch:
|
|
product: Product | None
|
|
method: str | None
|
|
|
|
@property
|
|
def matched(self) -> bool:
|
|
return self.product is not None
|
|
|
|
|
|
def _normalized(value: str | None) -> str:
|
|
return (value or "").strip()
|
|
|
|
|
|
def match_product(
|
|
*,
|
|
source: SourceSystem,
|
|
external_id: str | None = None,
|
|
external_sku: str | None = None,
|
|
barcode: str | None = None,
|
|
) -> ProductMatch:
|
|
"""Resolve a source product using explicit bindings before safe identifiers."""
|
|
|
|
external_id = _normalized(external_id)
|
|
external_sku = _normalized(external_sku)
|
|
barcode = _normalized(barcode)
|
|
|
|
if external_id:
|
|
binding = (
|
|
ProductBinding.objects.select_related("product")
|
|
.filter(source=source, external_id=external_id)
|
|
.first()
|
|
)
|
|
if binding:
|
|
return ProductMatch(binding.product, "external_id")
|
|
|
|
if external_sku:
|
|
bindings = list(
|
|
ProductBinding.objects.select_related("product").filter(
|
|
source=source, external_sku__iexact=external_sku
|
|
)[:2]
|
|
)
|
|
if len(bindings) == 1:
|
|
return ProductMatch(bindings[0].product, "external_sku")
|
|
|
|
products = list(Product.objects.filter(sku__iexact=external_sku)[:2])
|
|
if len(products) == 1:
|
|
return ProductMatch(products[0], "canonical_sku")
|
|
|
|
if barcode:
|
|
products = list(Product.objects.filter(barcode=barcode)[:2])
|
|
if len(products) == 1:
|
|
return ProductMatch(products[0], "barcode")
|
|
|
|
return ProductMatch(None, None)
|