80 lines
3.0 KiB
Python
80 lines
3.0 KiB
Python
"""发布:组装 ImportProductsV3 items[0] + 必填校验 + 轮询回填。"""
|
||
from __future__ import annotations
|
||
|
||
from models import Product
|
||
|
||
|
||
def _fmt(v) -> str:
|
||
if v is None:
|
||
return ""
|
||
return str(v)
|
||
|
||
|
||
def validate_ready(product: Product) -> list[str]:
|
||
"""返回缺失/非法必填项的中文提示列表;空列表表示可发布。"""
|
||
missing: list[str] = []
|
||
if not product.offer_id.strip():
|
||
missing.append("货号 offer_id")
|
||
if not product.name.strip():
|
||
missing.append("商品名 name")
|
||
if not product.description.strip():
|
||
missing.append("描述 description")
|
||
if not product.description_category_id:
|
||
missing.append("类目 description_category_id")
|
||
if product.price is None or product.price <= 0:
|
||
missing.append("售价 price")
|
||
if not product.weight or product.weight <= 0:
|
||
missing.append("重量 weight")
|
||
for label, val in (("长 depth", product.depth), ("宽 width", product.width), ("高 height", product.height)):
|
||
if not val or val <= 0:
|
||
missing.append(label)
|
||
if not product.images:
|
||
missing.append("主图 images(至少 1 张)")
|
||
elif any(u and u.startswith("http://") for u in product.images):
|
||
missing.append("图片链接必须使用 https(Ozon 不接受 http 直链)")
|
||
return missing
|
||
|
||
|
||
def _with_model_name(product: Product) -> list:
|
||
"""把 raw.model_name 自动注入为 attribute 9048(型号名称),用于多变体合并。"""
|
||
attrs = list(product.attributes or [])
|
||
model_name = (product.raw or {}).get("model_name") if product.raw else None
|
||
if not model_name:
|
||
return attrs
|
||
# 已手动映射 9048 就不重复添加
|
||
for a in attrs:
|
||
if isinstance(a, dict) and a.get("id") == 9048:
|
||
return attrs
|
||
attrs.append({"complex_id": 0, "id": 9048, "values": [{"value": model_name}]})
|
||
return attrs
|
||
|
||
|
||
def build_import_item(product: Product) -> dict:
|
||
item: dict = {
|
||
"offer_id": product.offer_id,
|
||
"name": product.name,
|
||
"description": product.description,
|
||
"description_category_id": product.description_category_id,
|
||
"price": _fmt(product.price),
|
||
"old_price": _fmt(product.old_price),
|
||
"currency_code": product.currency_code or "CNY",
|
||
"vat": product.vat or "0",
|
||
"depth": product.depth,
|
||
"width": product.width,
|
||
"height": product.height,
|
||
"dimension_unit": product.dimension_unit or "mm",
|
||
"weight": product.weight,
|
||
"weight_unit": product.weight_unit or "g",
|
||
"images": product.images or [],
|
||
"primary_image": product.primary_image or "",
|
||
"images360": product.images360 or [],
|
||
"color_image": product.color_image or "",
|
||
"attributes": _with_model_name(product),
|
||
"complex_attributes": product.complex_attributes or [],
|
||
}
|
||
if product.type_id:
|
||
item["type_id"] = product.type_id
|
||
if product.barcode:
|
||
item["barcode"] = product.barcode
|
||
return item
|