update torob api
This commit is contained in:
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import parse_qs, urlparse
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -80,6 +80,18 @@ def _extract_slug_from_url(value: str) -> str | None:
|
|||||||
return path.split("/")[-1]
|
return path.split("/")[-1]
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_variant_id_from_url(value: str) -> str | None:
|
||||||
|
query = urlparse(value).query
|
||||||
|
if not query:
|
||||||
|
return None
|
||||||
|
params = parse_qs(query)
|
||||||
|
variant_values = params.get("variant") or []
|
||||||
|
if not variant_values:
|
||||||
|
return None
|
||||||
|
candidate = variant_values[0].strip()
|
||||||
|
return candidate or None
|
||||||
|
|
||||||
|
|
||||||
def _variant_page_unique(product: ProductModel, variant: ProductVariant) -> str:
|
def _variant_page_unique(product: ProductModel, variant: ProductVariant) -> str:
|
||||||
return f"{product.pk}_{variant.pk}"
|
return f"{product.pk}_{variant.pk}"
|
||||||
|
|
||||||
@@ -109,13 +121,15 @@ def _absolute_url(request, value: str) -> str:
|
|||||||
return request.build_absolute_uri(value)
|
return request.build_absolute_uri(value)
|
||||||
|
|
||||||
|
|
||||||
def _shop_product_url(request, product: ProductModel) -> str:
|
def _shop_product_url(request, product: ProductModel, variant: ProductVariant | None = None) -> str:
|
||||||
domain = getattr(settings, "DOMAIN", None) or getattr(settings, "API_DOMAIN", None) or request.get_host()
|
domain = getattr(settings, "DOMAIN", None) or getattr(settings, "API_DOMAIN", None) or request.get_host()
|
||||||
if domain.startswith("http://") or domain.startswith("https://"):
|
if domain.startswith("http://") or domain.startswith("https://"):
|
||||||
base = domain.rstrip("/")
|
base = domain.rstrip("/")
|
||||||
else:
|
else:
|
||||||
base = f"https://{domain}".rstrip("/")
|
base = f"https://{domain}".rstrip("/")
|
||||||
url = f"{base}/product/{product.slug}/"
|
url = f"{base}/product/{product.slug}/"
|
||||||
|
if variant is not None:
|
||||||
|
url = f"{url}?variant={variant.pk}"
|
||||||
# Per spec: page_url max 1500 chars
|
# Per spec: page_url max 1500 chars
|
||||||
return url[:1500]
|
return url[:1500]
|
||||||
|
|
||||||
@@ -140,9 +154,6 @@ def _variant_spec(variant: ProductVariant | None) -> dict:
|
|||||||
if variant.color:
|
if variant.color:
|
||||||
spec.setdefault("color", variant.color)
|
spec.setdefault("color", variant.color)
|
||||||
|
|
||||||
if variant.in_stock is not None:
|
|
||||||
spec.setdefault("in_stock", variant.in_stock)
|
|
||||||
|
|
||||||
return spec
|
return spec
|
||||||
|
|
||||||
|
|
||||||
@@ -213,7 +224,7 @@ def _serialize_variant(request, product: ProductModel, variant: ProductVariant)
|
|||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
"page_unique": _variant_page_unique(product, variant),
|
"page_unique": _variant_page_unique(product, variant),
|
||||||
"page_url": _shop_product_url(request, product),
|
"page_url": _shop_product_url(request, product, variant),
|
||||||
"product_group_id": str(product.pk),
|
"product_group_id": str(product.pk),
|
||||||
"title": _truncate_text(product.name, 500),
|
"title": _truncate_text(product.name, 500),
|
||||||
"subtitle": _truncate_text(product.meta_description, 500),
|
"subtitle": _truncate_text(product.meta_description, 500),
|
||||||
@@ -222,11 +233,11 @@ def _serialize_variant(request, product: ProductModel, variant: ProductVariant)
|
|||||||
"category_name": _truncate_text(product.category.name if product.category else None, 200),
|
"category_name": _truncate_text(product.category.name if product.category else None, 200),
|
||||||
"image_links": _product_image_links(request, product, variant),
|
"image_links": _product_image_links(request, product, variant),
|
||||||
"spec": _variant_spec(variant),
|
"spec": _variant_spec(variant),
|
||||||
"guarantee": None,
|
"guarantee": _truncate_text(variant.guarantee, 200),
|
||||||
"short_desc": _truncate_text(product.description, 500),
|
"short_desc": _truncate_text(product.description, 500),
|
||||||
"date_added": _variant_date_added(product, variant),
|
"date_added": _variant_date_added(product, variant),
|
||||||
"date_updated": _variant_date_updated(product, variant),
|
"date_updated": _variant_date_updated(product, variant),
|
||||||
"seller_name": product.shop.shop_name if product.shop else None,
|
# "seller_name": product.shop.shop_name if product.shop else None,
|
||||||
}
|
}
|
||||||
|
|
||||||
if old_price is not None and old_price > current_price:
|
if old_price is not None and old_price > current_price:
|
||||||
@@ -336,27 +347,49 @@ class TorobProductSyncView(APIView):
|
|||||||
for product in products
|
for product in products
|
||||||
}
|
}
|
||||||
|
|
||||||
ordered_products = []
|
ordered_lookups: list[tuple[ProductModel, str | None]] = []
|
||||||
for url in requested_urls:
|
for url in requested_urls:
|
||||||
slug = _extract_slug_from_url(url)
|
slug = _extract_slug_from_url(url)
|
||||||
normalized_url = _normalize_url(url)
|
normalized_url = _normalize_url(url)
|
||||||
|
variant_id = _extract_variant_id_from_url(url)
|
||||||
product = product_by_slug.get(slug) if slug else None
|
product = product_by_slug.get(slug) if slug else None
|
||||||
if product is None:
|
if product is None:
|
||||||
product = product_by_url.get(normalized_url)
|
product = product_by_url.get(normalized_url)
|
||||||
if product is not None and product not in ordered_products:
|
if product is None:
|
||||||
ordered_products.append(product)
|
continue
|
||||||
|
ordered_lookups.append((product, variant_id))
|
||||||
|
|
||||||
serialized_products = []
|
serialized_products = []
|
||||||
for product in ordered_products:
|
seen: set[str] = set()
|
||||||
|
for product, variant_id in ordered_lookups:
|
||||||
variants = list(product.variants.all())
|
variants = list(product.variants.all())
|
||||||
if not variants:
|
if not variants:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if variant_id:
|
||||||
|
variant = next((v for v in variants if str(v.pk) == variant_id), None)
|
||||||
|
if not variant:
|
||||||
|
continue
|
||||||
|
image_links = _product_image_links(request, product, variant)
|
||||||
|
if not image_links:
|
||||||
|
continue
|
||||||
|
page_unique = _variant_page_unique(product, variant)
|
||||||
|
if page_unique in seen:
|
||||||
|
continue
|
||||||
|
seen.add(page_unique)
|
||||||
|
serialized_products.append(_serialize_variant(request, product, variant))
|
||||||
|
continue
|
||||||
|
|
||||||
variants.sort(key=_variant_sort_key)
|
variants.sort(key=_variant_sort_key)
|
||||||
for variant in variants:
|
for variant in variants:
|
||||||
image_links = _product_image_links(request, product, variant)
|
image_links = _product_image_links(request, product, variant)
|
||||||
# Skip variants without images as per spec requirement
|
# Skip variants without images as per spec requirement
|
||||||
if not image_links:
|
if not image_links:
|
||||||
continue
|
continue
|
||||||
|
page_unique = _variant_page_unique(product, variant)
|
||||||
|
if page_unique in seen:
|
||||||
|
continue
|
||||||
|
seen.add(page_unique)
|
||||||
serialized_products.append(_serialize_variant(request, product, variant))
|
serialized_products.append(_serialize_variant(request, product, variant))
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
|
|||||||
Reference in New Issue
Block a user