Files
crmApi/apps/shop/import_batches.py
T
2026-10-08 16:37:45 +03:30

60 lines
3.1 KiB
Python

"""Shared import lifecycle; callers enforce their own admin permission boundary."""
import json
from datetime import timedelta
from django.contrib.admin.models import LogEntry, ADDITION
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.db import transaction
from django.shortcuts import get_object_or_404
from django.utils import timezone
from apps.shop.import_models import ProductImportBatch
from apps.shop.models import Product
from apps.shop.product_import import parse_workbook, import_products, catalog_fingerprint, lock_catalog, HEADERS
from utils.admin_excel import excel_response
@transaction.atomic
def preview_batch(owner, workspace, upload, options, sheet='', header_row=1, mapping=None):
rows = parse_workbook(upload, sheet, header_row, mapping)
lock_catalog(workspace)
fingerprint = catalog_fingerprint(workspace)
result = import_products(workspace, rows, options, dry_run=True)
return ProductImportBatch.objects.create(sys_ws=workspace, created_by=owner,
expires_at=timezone.now()+timedelta(minutes=30), filename=upload.name[:255],
fingerprint=fingerprint, payload={'rows': rows, 'options': options}, result=result)
@transaction.atomic
def confirm_batch(batch_id, owner, workspace=None):
queryset = ProductImportBatch.objects.select_for_update().filter(created_by=owner)
if workspace is not None:
queryset = queryset.filter(sys_ws=workspace)
batch = get_object_or_404(queryset, pk=batch_id)
if batch.confirmed_at:
return batch
if batch.expires_at <= timezone.now():
raise ValidationError('پیش‌نمایش منقضی شده؛ فایل را دوباره اعتبارسنجی کنید.')
lock_catalog(batch.sys_ws)
if catalog_fingerprint(batch.sys_ws) != batch.fingerprint:
raise ValidationError('محصولات یا دسته‌ها پس از پیش‌نمایش تغییر کرده‌اند؛ پیش‌نمایش تازه بسازید.')
result = import_products(batch.sys_ws, batch.payload['rows'], batch.payload['options'])
batch.result = result
if result['committed']:
batch.confirmed_at = timezone.now()
LogEntry.objects.log_action(user_id=owner.pk, content_type_id=ContentType.objects.get_for_model(Product).pk,
object_id=None, object_repr=f'Excel import #{batch.pk}', action_flag=ADDITION,
change_message=json.dumps({'import': batch.pk, 'created': result['created'], 'updated': result['updated'], 'errors': result['errors']}))
batch.save(update_fields=('result', 'confirmed_at'))
return batch
def batch_report(batch):
rows = ((row['row'], *(row['values'].get(key) for key in HEADERS), row['status'], row['errors'])
for row in batch.result.get('rows', []))
return excel_response(('ردیف', *HEADERS, 'وضعیت', 'خطاها'), rows, f'import-report-{batch.pk}.xlsx')
def import_template():
return excel_response(HEADERS.keys(), [('محصول نمونه', 'دسته اصلی/زیردسته', 'CODE-001', 1000, 1, 1, 1, 1, False, '{}', 'عدد')], 'product-import-template.xlsx')