forked from erp-dev/erp
feat: backfill external order image upgrade to beat schedule by 1 hour
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db.models import Q
|
||||
|
||||
from api_v1.external_product_image_backfill import run_external_product_image_backfill
|
||||
from api_v1.tasks import _fetch_external_product_image, _upload_product_image
|
||||
from printing.models import PrintingJob
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
@@ -18,114 +17,25 @@ class Command(BaseCommand):
|
||||
help='仅输出将处理的产品,不实际请求外部 API 或写库',
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
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 handle(self, *args, **options):
|
||||
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')
|
||||
)
|
||||
|
||||
merchant_id = options.get('merchant_id')
|
||||
if merchant_id:
|
||||
queryset = queryset.filter(product__merchant_id=merchant_id)
|
||||
|
||||
product_id = options.get('product_id')
|
||||
if product_id:
|
||||
queryset = queryset.filter(product_id=product_id)
|
||||
|
||||
limit = options.get('limit')
|
||||
if limit is not None:
|
||||
if int(limit) <= 0:
|
||||
raise CommandError('--limit 必须大于 0')
|
||||
limit = int(limit)
|
||||
|
||||
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
|
||||
dry_run = bool(options.get('dry_run'))
|
||||
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 = self._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:
|
||||
self.stdout.write(
|
||||
'[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_external_product_image(request_name)
|
||||
_upload_product_image(product, image_payload)
|
||||
except Exception as exc:
|
||||
failed_count += 1
|
||||
self.stderr.write(
|
||||
self.style.ERROR(
|
||||
f'补图失败: job_id={job.id} product_id={product.id} merchant_id={product.merchant_id} '
|
||||
f'product_name={product.name} request_name={request_name} error={exc}'
|
||||
)
|
||||
)
|
||||
else:
|
||||
success_count += 1
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
f'补图成功: job_id={job.id} product_id={product.id} merchant_id={product.merchant_id} '
|
||||
f'product_name={product.name} request_name={request_name}'
|
||||
)
|
||||
)
|
||||
|
||||
if limit is not None and selected_count >= limit:
|
||||
break
|
||||
|
||||
if dry_run:
|
||||
self.stdout.write(self.style.SUCCESS('dry-run 完成'))
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
'完成: '
|
||||
f'scanned={scanned_count} '
|
||||
f'selected={selected_count} '
|
||||
f'success={success_count} '
|
||||
f'failed={failed_count} '
|
||||
f'skipped_with_image={skipped_with_image_count} '
|
||||
f'skipped_without_request_name={skipped_without_request_name_count} '
|
||||
f'skipped_duplicate_product={skipped_duplicate_product_count}'
|
||||
)
|
||||
payload = run_external_product_image_backfill(
|
||||
fetch_image=_fetch_external_product_image,
|
||||
upload_image=_upload_product_image,
|
||||
merchant_id=merchant_id,
|
||||
product_id=product_id,
|
||||
limit=limit,
|
||||
dry_run=bool(options.get('dry_run')),
|
||||
on_success=lambda message: self.stdout.write(self.style.SUCCESS(message)),
|
||||
on_error=lambda message: self.stderr.write(self.style.ERROR(message)),
|
||||
on_info=lambda message: self.stdout.write(message),
|
||||
)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f'完成: {payload}'))
|
||||
|
||||
Reference in New Issue
Block a user