add product
This commit is contained in:
1 parent
423d4cf40e
commit
c8d45dd07c
58 files changed
+8309
-674
No files matched your search
@@ -0,0 +1,113 @@
|
||||
import json
|
||||
|
||||
from django import forms
|
||||
from django.core.exceptions import PermissionDenied, ValidationError
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.template.response import TemplateResponse
|
||||
from django.urls import path
|
||||
|
||||
from apps.shop.import_models import ProductImportBatch
|
||||
from apps.shop.product_import import HEADERS, parse_workbook
|
||||
from apps.shop.import_batches import preview_batch, confirm_batch
|
||||
from apps.workspace.models import Workspace
|
||||
from utils.admin_excel import excel_response
|
||||
|
||||
|
||||
class ProductImportForm(forms.Form):
|
||||
workspace = forms.ModelChoiceField(label='فضای کاری مقصد', queryset=Workspace.objects.all())
|
||||
file = forms.FileField(label='فایل xlsx')
|
||||
sheet = forms.CharField(label='نام برگه (خالی = اولین برگه)', required=False)
|
||||
header_row = forms.IntegerField(label='شماره ردیف سرستون', min_value=1, max_value=100, initial=1)
|
||||
mode = forms.ChoiceField(label='نوع ورود', choices=(('create', 'فقط ایجاد'), ('upsert', 'ایجاد و بهروزرسانی'), ('update', 'فقط بهروزرسانی')))
|
||||
create_categories = forms.BooleanField(label='ساخت دستههای ناموجود', required=False, initial=True)
|
||||
errors = forms.ChoiceField(label='مدیریت خطا', choices=(('atomic', 'در صورت هر خطا، هیچ ردیفی ثبت نشود'), ('skip', 'فقط ردیفهای معتبر ثبت شوند')))
|
||||
ordering = forms.ChoiceField(label='ترتیب نمایش محصولات', choices=(('preserve', 'مقادیر فایل؛ خالی = حفظ مقدار فعلی'), ('rows', 'ترتیب ردیف فایل برای مقادیر خالی'), ('append', 'محصول جدید در انتهای دسته')))
|
||||
mapping = forms.CharField(label='نگاشت اختیاری ستونها (JSON)', required=False, widget=forms.Textarea(attrs={'rows': 3}),
|
||||
help_text='مثال: {"name": "عنوان کالا", "category": "گروه", "acc_code": "شناسه"}')
|
||||
|
||||
def clean_mapping(self):
|
||||
try:
|
||||
value = json.loads(self.cleaned_data['mapping'] or '{}')
|
||||
if not isinstance(value, dict) or not all(isinstance(key, str) and isinstance(item, str) for key, item in value.items()):
|
||||
raise ValueError
|
||||
return value
|
||||
except ValueError:
|
||||
raise forms.ValidationError('یک شیء JSON با کلید و مقدار متنی وارد کنید.')
|
||||
|
||||
|
||||
class ProductImportAdminMixin:
|
||||
change_list_template = 'admin/shop/product/change_list.html'
|
||||
|
||||
def import_allowed(self, request):
|
||||
return (self.has_add_permission(request) and self.has_change_permission(request)
|
||||
and request.user.has_perm('shop.view_productcategory'))
|
||||
|
||||
def get_urls(self):
|
||||
return [path('import-excel/', self.admin_site.admin_view(self.import_view), name='shop_product_import'),
|
||||
path('import-template/', self.admin_site.admin_view(self.import_template), name='shop_product_import_template'),
|
||||
path('import-report/<int:batch_id>/', self.admin_site.admin_view(self.import_report), name='shop_product_import_report')] + super().get_urls()
|
||||
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
return super().changelist_view(request, dict(extra_context or {}, can_import=self.import_allowed(request)))
|
||||
|
||||
def import_template(self, request):
|
||||
if not self.import_allowed(request):
|
||||
raise PermissionDenied
|
||||
return excel_response(HEADERS.keys(), [('محصول نمونه', 'دسته اصلی/زیردسته', 'CODE-001', 1000, 1, 1, 1, 1, False, '{}', 'عدد')], 'product-import-template.xlsx')
|
||||
|
||||
def import_report(self, request, batch_id):
|
||||
if not self.import_allowed(request):
|
||||
raise PermissionDenied
|
||||
batch = get_object_or_404(ProductImportBatch, pk=batch_id, created_by=request.user)
|
||||
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_view(self, request):
|
||||
if not self.import_allowed(request):
|
||||
raise PermissionDenied
|
||||
form = ProductImportForm(request.POST or None, request.FILES or None)
|
||||
batch, problem = None, None
|
||||
if request.method == 'POST':
|
||||
if request.POST.get('confirm'):
|
||||
try:
|
||||
batch = self.confirm_import(request)
|
||||
except ValidationError as error:
|
||||
problem = '؛ '.join(error.messages)
|
||||
elif form.is_valid():
|
||||
try:
|
||||
batch = self.preview_import(request, form.cleaned_data)
|
||||
except ValidationError as error:
|
||||
form.add_error(None, error)
|
||||
context = dict(self.admin_site.each_context(request), opts=self.model._meta, title='ورود محصولات از اکسل',
|
||||
form=form, batch=batch, problem=problem,
|
||||
result=batch.result if batch else None, can_confirm=batch and not batch.confirmed_at
|
||||
and (batch.payload['options']['errors'] == 'skip' or not batch.result['errors']))
|
||||
return TemplateResponse(request, 'admin/shop/product/import.html', context)
|
||||
|
||||
def preview_import(self, request, data):
|
||||
if data['create_categories'] and not request.user.has_perm('shop.add_productcategory'):
|
||||
raise PermissionDenied
|
||||
# Category-order permission is checked against the parsed file before preview writes.
|
||||
rows = parse_workbook(data['file'], data['sheet'], data['header_row'], data['mapping'])
|
||||
if any(row['values'].get(key) for row in rows for key in ('order_cat', 'category_excel_order')):
|
||||
if not request.user.has_perm('shop.change_productcategory'):
|
||||
raise PermissionDenied
|
||||
data['file'].seek(0)
|
||||
options = {key: data[key] for key in ('mode', 'create_categories', 'errors', 'ordering')}
|
||||
return preview_batch(request.user, data['workspace'], data['file'], options,
|
||||
data['sheet'], data['header_row'], data['mapping'])
|
||||
|
||||
def confirm_import(self, request):
|
||||
try:
|
||||
batch_id = int(request.POST['batch_id'])
|
||||
except (KeyError, ValueError, TypeError):
|
||||
raise ValidationError('شناسه پیشنمایش معتبر نیست.')
|
||||
batch = get_object_or_404(ProductImportBatch, pk=batch_id, created_by=request.user)
|
||||
options = batch.payload['options']
|
||||
if options['create_categories'] and not request.user.has_perm('shop.add_productcategory'):
|
||||
raise PermissionDenied
|
||||
if any(row['values'].get(key) for row in batch.payload['rows'] for key in ('order_cat', 'category_excel_order')):
|
||||
if not request.user.has_perm('shop.change_productcategory'):
|
||||
raise PermissionDenied
|
||||
return confirm_batch(batch_id, request.user)
|
||||
Reference in new issue
Block a user