60 lines
3.1 KiB
Python
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')
|