forked from erp-dev/erp
feat: backfill external order image upgrade to beat schedule by 1 hour
This commit is contained in:
136
api_v1/external_product_image_backfill.py
Normal file
136
api_v1/external_product_image_backfill.py
Normal file
@@ -0,0 +1,136 @@
|
||||
from collections.abc import Callable
|
||||
|
||||
from django.db.models import Q
|
||||
|
||||
from printing.models import PrintingJob
|
||||
|
||||
|
||||
def extract_request_name(job: PrintingJob) -> str:
|
||||
raw = job.external_raw or {}
|
||||
if isinstance(raw, dict):
|
||||
request_name = str(raw.get("YanSe") or "").strip()
|
||||
if request_name:
|
||||
return request_name
|
||||
return str(job.external_product_name or "").strip()
|
||||
|
||||
|
||||
def run_external_product_image_backfill(
|
||||
*,
|
||||
fetch_image: Callable[[str], dict],
|
||||
upload_image: Callable[[object, dict], None],
|
||||
merchant_id: int | None = None,
|
||||
product_id: int | None = None,
|
||||
limit: int | None = None,
|
||||
dry_run: bool = False,
|
||||
on_success: Callable[[str], None] | None = None,
|
||||
on_error: Callable[[str], None] | None = None,
|
||||
on_info: Callable[[str], None] | None = None,
|
||||
) -> dict:
|
||||
queryset = (
|
||||
PrintingJob.objects.filter(
|
||||
printing_order__external_order_id__isnull=False,
|
||||
)
|
||||
.exclude(printing_order__external_order_id="")
|
||||
.filter(Q(product__image__isnull=True) | Q(product__image=""))
|
||||
.select_related("product", "printing_order", "product__merchant")
|
||||
.order_by("-id")
|
||||
)
|
||||
|
||||
if merchant_id:
|
||||
queryset = queryset.filter(product__merchant_id=merchant_id)
|
||||
|
||||
if product_id:
|
||||
queryset = queryset.filter(product_id=product_id)
|
||||
|
||||
if limit is not None:
|
||||
limit = int(limit)
|
||||
if limit <= 0:
|
||||
raise ValueError("limit must be greater than 0")
|
||||
|
||||
success_count = 0
|
||||
failed_count = 0
|
||||
skipped_with_image_count = 0
|
||||
skipped_without_request_name_count = 0
|
||||
skipped_duplicate_product_count = 0
|
||||
selected_count = 0
|
||||
scanned_count = 0
|
||||
seen_product_ids = set()
|
||||
|
||||
for job in queryset.iterator(chunk_size=1000):
|
||||
scanned_count += 1
|
||||
product = job.product
|
||||
if product.image:
|
||||
skipped_with_image_count += 1
|
||||
continue
|
||||
|
||||
if product.id in seen_product_ids:
|
||||
skipped_duplicate_product_count += 1
|
||||
continue
|
||||
|
||||
request_name = extract_request_name(job)
|
||||
if not request_name:
|
||||
skipped_without_request_name_count += 1
|
||||
continue
|
||||
|
||||
seen_product_ids.add(product.id)
|
||||
selected_count += 1
|
||||
|
||||
if dry_run:
|
||||
if on_info:
|
||||
on_info(
|
||||
"[DRY-RUN] "
|
||||
f"job_id={job.id} "
|
||||
f"product_id={product.id} "
|
||||
f"merchant_id={product.merchant_id} "
|
||||
f"product_name={product.name} "
|
||||
f"request_name={request_name}"
|
||||
)
|
||||
else:
|
||||
try:
|
||||
image_payload = fetch_image(request_name)
|
||||
upload_image(product, image_payload)
|
||||
except Exception as exc:
|
||||
failed_count += 1
|
||||
if on_error:
|
||||
on_error(
|
||||
"补图失败: "
|
||||
f"job_id={job.id} "
|
||||
f"product_id={product.id} "
|
||||
f"merchant_id={product.merchant_id} "
|
||||
f"product_name={product.name} "
|
||||
f"request_name={request_name} "
|
||||
f"error={exc}"
|
||||
)
|
||||
else:
|
||||
success_count += 1
|
||||
if on_success:
|
||||
on_success(
|
||||
"补图成功: "
|
||||
f"job_id={job.id} "
|
||||
f"product_id={product.id} "
|
||||
f"merchant_id={product.merchant_id} "
|
||||
f"product_name={product.name} "
|
||||
f"request_name={request_name}"
|
||||
)
|
||||
|
||||
if limit is not None and selected_count >= limit:
|
||||
break
|
||||
|
||||
payload = {
|
||||
"scanned": scanned_count,
|
||||
"selected": selected_count,
|
||||
"success": success_count,
|
||||
"failed": failed_count,
|
||||
"skipped_with_image": skipped_with_image_count,
|
||||
"skipped_without_request_name": skipped_without_request_name_count,
|
||||
"skipped_duplicate_product": skipped_duplicate_product_count,
|
||||
"merchant_id": merchant_id,
|
||||
"product_id": product_id,
|
||||
"limit": limit,
|
||||
"dry_run": dry_run,
|
||||
}
|
||||
|
||||
if dry_run and on_info:
|
||||
on_info("dry-run 完成")
|
||||
|
||||
return payload
|
||||
Reference in New Issue
Block a user