import json from django.core.management.base import BaseCommand from api_v1.external_datetime import parse_external_china_datetime from printing.models import PrintingOrder class Command(BaseCommand): help = '从 PrintingOrder.external_raw.first_record.KdRiQi 批量回填或修正 kd_riqi' def add_arguments(self, parser): parser.add_argument('--dry-run', action='store_true', help='只统计不写入') parser.add_argument('--batch-size', type=int, default=1000, help='批量处理大小') parser.add_argument('--limit', type=int, default=None, help='最多处理多少条候选记录') parser.add_argument('--merchant-id', type=int, default=None, help='限定商户ID') parser.add_argument('--external-order-id', default=None, help='限定外部订单编号') parser.add_argument('--overwrite', action='store_true', help='覆盖已有 kd_riqi,用于修正历史错误值') parser.add_argument('--update-outgoing-date', action='store_true', help='同时用 KdRiQi 修正 outgoing_date') def handle(self, *args, **options): dry_run = bool(options['dry_run']) batch_size = max(1, int(options['batch_size'] or 1000)) limit = options.get('limit') overwrite = bool(options['overwrite']) update_outgoing_date = bool(options['update_outgoing_date']) queryset = PrintingOrder.objects.exclude(external_raw={}) if not overwrite: queryset = queryset.filter(kd_riqi__isnull=True) merchant_id = options.get('merchant_id') if merchant_id: queryset = queryset.filter(merchant_id=merchant_id) external_order_id = (options.get('external_order_id') or '').strip() if external_order_id: queryset = queryset.filter(external_order_id=external_order_id) queryset = queryset.order_by('id').only('id', 'external_raw', 'kd_riqi', 'outgoing_date') if limit is not None: queryset = queryset[: max(0, int(limit))] matched = 0 updated = 0 skipped_missing = 0 skipped_invalid = 0 pending_updates = [] update_fields = ['kd_riqi'] if update_outgoing_date: update_fields.append('outgoing_date') for order in queryset.iterator(chunk_size=batch_size): matched += 1 try: first_record = (order.external_raw or {}).get('first_record') or {} raw_value = first_record.get('KdRiQi') except AttributeError: raw_value = None if not raw_value: skipped_missing += 1 continue parsed = parse_external_china_datetime(raw_value) if parsed is None: skipped_invalid += 1 continue order.kd_riqi = parsed if update_outgoing_date: order.outgoing_date = parsed updated += 1 if dry_run: continue pending_updates.append(order) if len(pending_updates) >= batch_size: PrintingOrder.objects.bulk_update(pending_updates, update_fields) pending_updates = [] if pending_updates: PrintingOrder.objects.bulk_update(pending_updates, update_fields) payload = { 'dry_run': dry_run, 'matched': matched, 'updated': 0 if dry_run else updated, 'would_update': updated if dry_run else 0, 'skipped_missing': skipped_missing, 'skipped_invalid': skipped_invalid, 'overwrite': overwrite, 'update_outgoing_date': update_outgoing_date, } self.stdout.write(self.style.SUCCESS(json.dumps(payload, ensure_ascii=False)))