add product
This commit is contained in:
1 parent
423d4cf40e
commit
c8d45dd07c
58 files changed
+8309
-674
No files matched your search
@@ -5,45 +5,34 @@ from apps.shop.models import Product as ProductModel, ProductCategory as Product
|
||||
from apps.workspace.models import Workspace as WorkspaceModel, City as CityModel
|
||||
from apps.customer.models import Customer as CustomerModel
|
||||
from apps.customer.models import ResponsibleGroup as ResponsibleGroupModel
|
||||
import os
|
||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||
from django.db import IntegrityError, transaction
|
||||
from rest_framework import exceptions
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from utils import custom_permissions
|
||||
from utils.get_user_workspace import get_user_workspace
|
||||
from utils.validations.mobile import normalize_mobile
|
||||
|
||||
|
||||
class ImportExcelView(APIView):
|
||||
permission_classes = (IsAuthenticated, custom_permissions.WorkspaceAdminPermission)
|
||||
|
||||
def get(self, request):
|
||||
|
||||
df = pd.read_excel('pe.xlsx')
|
||||
for index, row in df.iterrows():
|
||||
cate_name = row['cate_name']
|
||||
#order_cat = row['order_cat']
|
||||
acc_code = row['acc_code']
|
||||
prd_name = row['name']
|
||||
order_prd = row['size']
|
||||
vahed = row['vahed']
|
||||
|
||||
workspace = WorkspaceModel.objects.get(id=2)
|
||||
try:
|
||||
prd_ct = ProductCategoryModel.objects.get(name=cate_name, sys_ws=workspace)
|
||||
except ProductCategoryModel.DoesNotExist as exp:
|
||||
prd_ct = ProductCategoryModel.objects.create(name=cate_name, sys_ws=workspace)
|
||||
|
||||
if ProductModel.objects.filter(acc_code=acc_code).exists() == False:
|
||||
new_product = ProductModel()
|
||||
new_product.name = prd_name
|
||||
new_product.price = 0
|
||||
new_product.category = ProductCategoryModel.objects.get(id=prd_ct.id)
|
||||
new_product.acc_code = acc_code
|
||||
new_product.order_prd = order_prd
|
||||
new_product.view_only = True
|
||||
new_product.attr = {"acc_vahed": vahed}
|
||||
new_product.sys_ws = workspace
|
||||
new_product.save()
|
||||
else:
|
||||
up_product = ProductModel.objects.get(acc_code=acc_code)
|
||||
up_product.name = prd_name
|
||||
up_product.save()
|
||||
|
||||
return Response(data={"result": 'ok'})
|
||||
# Keep the legacy URL and filename, but use the same validated importer as Admin.
|
||||
from django.core.files import File
|
||||
from apps.shop.product_import import parse_workbook, import_products
|
||||
try:
|
||||
with open('pe.xlsx', 'rb') as source:
|
||||
rows = parse_workbook(File(source, name='pe.xlsx'))
|
||||
for row in rows:
|
||||
row['values'].setdefault('view_only', 'true')
|
||||
result = import_products(get_user_workspace(request), rows,
|
||||
{'mode': 'upsert', 'create_categories': True, 'errors': 'atomic', 'ordering': 'preserve'})
|
||||
except (OSError, DjangoValidationError) as error:
|
||||
raise exceptions.ValidationError(getattr(error, 'messages', ['فایل اکسل محصولات خوانده نشد.']))
|
||||
if not result['committed']:
|
||||
raise exceptions.ValidationError(result)
|
||||
return Response(data={'result': 'ok', 'imported': result['created'] + result['updated']})
|
||||
|
||||
|
||||
class ImportExcelCitysView(APIView):
|
||||
@@ -72,43 +61,46 @@ class ImportExcelCitysView(APIView):
|
||||
return Response(data={"result": 'ok'})
|
||||
|
||||
|
||||
def customer_from_excel(row, workspace):
|
||||
mobile = row['mobile']
|
||||
if pd.isna(mobile) or pd.isna(row['name']):
|
||||
raise exceptions.ValidationError('نام و شماره موبایل مشتری الزامی است.')
|
||||
if isinstance(mobile, float) and mobile.is_integer():
|
||||
mobile = int(mobile)
|
||||
city = CityModel.objects.filter(name=row['shar'], ostan__name=row['ostan'], ostan__is_ostan=True).first()
|
||||
city = city or CityModel.objects.filter(pk=1229).first()
|
||||
if not city:
|
||||
raise exceptions.ValidationError('شهر مشتری در فایل پیدا نشد.')
|
||||
group = ResponsibleGroupModel.objects.filter(pk=row['id_mantaghe'], sys_ws=workspace).first()
|
||||
if not group:
|
||||
raise exceptions.ValidationError('گروه مسئول متعلق به این فضای کاری نیست.')
|
||||
customer = CustomerModel(name_family=row['name'], mobile=normalize_mobile(mobile), city=city,
|
||||
responsible_group=group, sys_ws=workspace,
|
||||
phone=None if pd.isna(row['phone']) else row['phone'],
|
||||
address=None if pd.isna(row['address']) else row['address'])
|
||||
customer.full_clean()
|
||||
customer.save()
|
||||
|
||||
|
||||
class ImportExcelCustomersView(APIView):
|
||||
permission_classes = (IsAuthenticated, custom_permissions.WorkspaceAdminPermission)
|
||||
|
||||
@transaction.atomic
|
||||
def get(self, request):
|
||||
|
||||
df = pd.read_excel('customersData.xlsx')
|
||||
for index, row in df.iterrows():
|
||||
name = row['name']
|
||||
mobile = row['mobile']
|
||||
|
||||
if name and mobile:
|
||||
|
||||
phone = row['phone']
|
||||
address = row['address']
|
||||
ostan = row['ostan']
|
||||
shahr = row['shar']
|
||||
mantaghe = row['id_mantaghe']
|
||||
|
||||
try:
|
||||
ostan_obj = CityModel.objects.get(name=ostan, is_ostan=True)
|
||||
shahr_obj = CityModel.objects.get(name=shahr, ostan=ostan_obj)
|
||||
except Exception as exp:
|
||||
shahr_obj = CityModel.objects.get(id=1229)
|
||||
|
||||
try:
|
||||
cs = CustomerModel()
|
||||
cs.name_family = name
|
||||
cs.mobile = mobile
|
||||
if phone:
|
||||
cs.phone = phone
|
||||
|
||||
cs.city = shahr_obj
|
||||
if address:
|
||||
cs.address = address
|
||||
cs.responsible_group = ResponsibleGroupModel.objects.get(id=mantaghe)
|
||||
cs.sys_ws = WorkspaceModel.objects.get(id=2)
|
||||
cs.save()
|
||||
except Exception as exp:
|
||||
print(name)
|
||||
|
||||
return Response(data={"result": 'ok'})
|
||||
workspace = get_user_workspace(request)
|
||||
try:
|
||||
data = pd.read_excel('customersData.xlsx')
|
||||
except (OSError, ValueError):
|
||||
raise exceptions.ValidationError('فایل اکسل مشتریان خوانده نشد.')
|
||||
for index, row in data.iterrows():
|
||||
try:
|
||||
customer_from_excel(row, workspace)
|
||||
except DjangoValidationError as error:
|
||||
raise exceptions.ValidationError({'row': int(index)+2, 'errors': error.message_dict})
|
||||
except IntegrityError:
|
||||
raise exceptions.ValidationError({'row': int(index)+2, 'mobile': 'شماره موبایل مشتری تکراری است.'})
|
||||
except exceptions.ValidationError as error:
|
||||
raise exceptions.ValidationError({'row': int(index)+2, 'errors': error.detail})
|
||||
except (KeyError, TypeError, ValueError):
|
||||
raise exceptions.ValidationError({'row': int(index)+2, 'error': 'اطلاعات این ردیف معتبر نیست.'})
|
||||
return Response(data={'result': 'ok', 'imported': len(data)})
|
||||
@@ -0,0 +1,293 @@
|
||||
"""JWT-protected workspace administration for the CRM product pages."""
|
||||
from django.core.exceptions import ValidationError as ModelValidationError
|
||||
from django.db import DataError, IntegrityError, transaction
|
||||
from django.db.models import Count, Q
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils import timezone
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import APIException, ValidationError
|
||||
from rest_framework.pagination import PageNumberPagination
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from apps.shop.import_batches import preview_batch, confirm_batch, batch_report, import_template
|
||||
from apps.shop.import_models import ProductImportBatch
|
||||
from apps.shop.management_serializers import ProductManagementSerializer, CategoryManagementSerializer, ImportOptionsSerializer
|
||||
from apps.shop.models import Product, ProductCategory, Cart, OrderItem
|
||||
from apps.shop.ordering import product_ordering
|
||||
from apps.workspace.models import Workspace
|
||||
from utils.custom_permissions import WorkspaceAdminPermission
|
||||
from utils.get_user_workspace import get_user_workspace
|
||||
|
||||
|
||||
class CatalogConflict(APIException):
|
||||
status_code = 409
|
||||
default_detail = 'این عملیات با دادههای فعلی سازگار نیست.'
|
||||
|
||||
|
||||
def ensure_product_deletable(product):
|
||||
if OrderItem.objects.filter(product=product).exists() or Cart.objects.filter(product=product).exists():
|
||||
raise CatalogConflict('محصول در سفارش یا سبد استفاده شده است؛ برای حفظ سوابق امکان حذف ندارد.')
|
||||
|
||||
|
||||
def ensure_category_deletable(category):
|
||||
if Product.objects.filter(category=category).exists() or ProductCategory.objects.filter(parent=category).exists():
|
||||
raise CatalogConflict('دسته دارای محصول یا زیردسته است؛ ابتدا محصولات و زیردستهها را منتقل کنید.')
|
||||
|
||||
|
||||
class ManagementPagination(PageNumberPagination):
|
||||
page_size = 25
|
||||
page_size_query_param = 'page_size'
|
||||
max_page_size = 100
|
||||
|
||||
|
||||
class ManagementApi(APIView):
|
||||
permission_classes = (IsAuthenticated, WorkspaceAdminPermission)
|
||||
|
||||
def initial(self, request, *args, **kwargs):
|
||||
super().initial(request, *args, **kwargs)
|
||||
self.workspace = get_user_workspace(request)
|
||||
|
||||
def handle_exception(self, exc):
|
||||
if isinstance(exc, ModelValidationError):
|
||||
exc = ValidationError(exc.message_dict if hasattr(exc, 'message_dict') else {'detail': exc.messages})
|
||||
elif isinstance(exc, (DataError, IntegrityError)):
|
||||
exc = CatalogConflict('دادهها با محدودیتهای دیتابیس سازگار نیستند یا همزمان تغییر کردهاند؛ اطلاعات را تازه کنید.')
|
||||
return super().handle_exception(exc)
|
||||
|
||||
def serializer_context(self):
|
||||
return {'request': self.request, 'workspace': self.workspace}
|
||||
|
||||
def lock_workspace(self):
|
||||
Workspace.objects.select_for_update().get(pk=self.workspace.pk)
|
||||
|
||||
|
||||
class ProductFilters(serializers.Serializer):
|
||||
search = serializers.CharField(required=False, allow_blank=True, max_length=200)
|
||||
category = serializers.IntegerField(required=False, min_value=1)
|
||||
view_only = serializers.BooleanField(required=False)
|
||||
price_min = serializers.IntegerField(required=False, min_value=0)
|
||||
price_max = serializers.IntegerField(required=False, min_value=0)
|
||||
ordering = serializers.ChoiceField(choices=('display', 'excel', 'name', '-name', 'price', '-price', '-created_at'), default='display')
|
||||
|
||||
def validate(self, attrs):
|
||||
if attrs.get('price_min', 0) > attrs.get('price_max', 9223372036854775807):
|
||||
raise ValidationError({'price_max': 'حداکثر قیمت باید از حداقل کمتر نباشد.'})
|
||||
return attrs
|
||||
|
||||
|
||||
def filtered_products(workspace, parameters):
|
||||
serializer = ProductFilters(data=parameters)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
data = serializer.validated_data
|
||||
queryset = Product.objects.filter(sys_ws=workspace).select_related('category')
|
||||
if data.get('search'):
|
||||
queryset = queryset.filter(Q(name__icontains=data['search']) | Q(acc_code__icontains=data['search']) | Q(category__name__icontains=data['search']))
|
||||
if 'category' in data:
|
||||
queryset = queryset.filter(category_id=data['category'])
|
||||
if 'view_only' in data:
|
||||
queryset = queryset.filter(view_only=data['view_only'])
|
||||
for key, lookup in (('price_min', 'price__gte'), ('price_max', 'price__lte')):
|
||||
if key in data:
|
||||
queryset = queryset.filter(**{lookup: data[key]})
|
||||
ordering = data['ordering']
|
||||
return queryset.order_by(*product_ordering(excel=ordering == 'excel')) if ordering in ('display', 'excel') else queryset.order_by(ordering, 'pk')
|
||||
|
||||
|
||||
class ProductManagementListApi(ManagementApi):
|
||||
def get(self, request):
|
||||
pagination = ManagementPagination()
|
||||
rows = pagination.paginate_queryset(filtered_products(self.workspace, request.query_params), request)
|
||||
return pagination.get_paginated_response(ProductManagementSerializer(rows, many=True).data)
|
||||
|
||||
@transaction.atomic
|
||||
def post(self, request):
|
||||
self.lock_workspace()
|
||||
serializer = ProductManagementSerializer(data=request.data, context=self.serializer_context())
|
||||
serializer.is_valid(raise_exception=True)
|
||||
product = Product(sys_ws=self.workspace, **serializer.validated_data)
|
||||
product.full_clean()
|
||||
product.save()
|
||||
return Response(ProductManagementSerializer(product).data, status=201)
|
||||
|
||||
|
||||
class ProductManagementDetailApi(ManagementApi):
|
||||
def get(self, request, pk):
|
||||
product = get_object_or_404(Product, pk=pk, sys_ws=self.workspace)
|
||||
return Response(ProductManagementSerializer(product).data)
|
||||
|
||||
@transaction.atomic
|
||||
def patch(self, request, pk):
|
||||
self.lock_workspace()
|
||||
product = get_object_or_404(Product.objects.select_for_update(), pk=pk, sys_ws=self.workspace)
|
||||
serializer = ProductManagementSerializer(product, data=request.data, partial=True, context=self.serializer_context())
|
||||
serializer.is_valid(raise_exception=True)
|
||||
for name, value in serializer.validated_data.items():
|
||||
setattr(product, name, value)
|
||||
product.full_clean()
|
||||
product.save()
|
||||
return Response(ProductManagementSerializer(product).data)
|
||||
|
||||
put = patch
|
||||
|
||||
@transaction.atomic
|
||||
def delete(self, request, pk):
|
||||
self.lock_workspace()
|
||||
product = get_object_or_404(Product.objects.select_for_update(), pk=pk, sys_ws=self.workspace)
|
||||
ensure_product_deletable(product)
|
||||
product.delete()
|
||||
return Response(status=204)
|
||||
|
||||
|
||||
class CategoryManagementListApi(ManagementApi):
|
||||
def get(self, request):
|
||||
queryset = ProductCategory.objects.filter(sys_ws=self.workspace).annotate(product_count=Count('product', distinct=True), child_count=Count('productcategory', distinct=True))
|
||||
return Response(CategoryManagementSerializer(queryset, many=True, context=self.serializer_context()).data)
|
||||
|
||||
@transaction.atomic
|
||||
def post(self, request):
|
||||
self.lock_workspace()
|
||||
serializer = CategoryManagementSerializer(data=request.data, context=self.serializer_context())
|
||||
serializer.is_valid(raise_exception=True)
|
||||
category = ProductCategory(sys_ws=self.workspace, **serializer.validated_data)
|
||||
category.full_clean()
|
||||
category.save()
|
||||
return Response(CategoryManagementSerializer(category, context=self.serializer_context()).data, status=201)
|
||||
|
||||
|
||||
class CategoryManagementDetailApi(ManagementApi):
|
||||
def get(self, request, pk):
|
||||
category = get_object_or_404(ProductCategory, pk=pk, sys_ws=self.workspace)
|
||||
return Response(CategoryManagementSerializer(category, context=self.serializer_context()).data)
|
||||
|
||||
@transaction.atomic
|
||||
def patch(self, request, pk):
|
||||
self.lock_workspace()
|
||||
category = get_object_or_404(ProductCategory.objects.select_for_update(), pk=pk, sys_ws=self.workspace)
|
||||
serializer = CategoryManagementSerializer(category, data=request.data, partial=True, context=self.serializer_context())
|
||||
serializer.is_valid(raise_exception=True)
|
||||
for name, value in serializer.validated_data.items():
|
||||
setattr(category, name, value)
|
||||
category.full_clean()
|
||||
category.save()
|
||||
return Response(CategoryManagementSerializer(category, context=self.serializer_context()).data)
|
||||
|
||||
put = patch
|
||||
|
||||
@transaction.atomic
|
||||
def delete(self, request, pk):
|
||||
self.lock_workspace()
|
||||
category = get_object_or_404(ProductCategory.objects.select_for_update(), pk=pk, sys_ws=self.workspace)
|
||||
ensure_category_deletable(category)
|
||||
category.delete()
|
||||
return Response(status=204)
|
||||
|
||||
|
||||
class ProductBulkSerializer(serializers.Serializer):
|
||||
ids = serializers.ListField(child=serializers.IntegerField(min_value=1), min_length=1, max_length=100)
|
||||
action = serializers.ChoiceField(choices=('delete', 'move', 'view_only', 'display_order', 'excel_order'))
|
||||
category = serializers.IntegerField(min_value=1, required=False)
|
||||
view_only = serializers.BooleanField(required=False)
|
||||
|
||||
def validate(self, attrs):
|
||||
if len(set(attrs['ids'])) != len(attrs['ids']):
|
||||
raise ValidationError({'ids': 'شناسههای تکراری مجاز نیست.'})
|
||||
for action, key in (('move', 'category'), ('view_only', 'view_only')):
|
||||
if attrs['action'] == action and key not in attrs:
|
||||
raise ValidationError({key: 'این مقدار برای عملیات انتخابشده لازم است.'})
|
||||
return attrs
|
||||
|
||||
|
||||
class ProductBulkApi(ManagementApi):
|
||||
@transaction.atomic
|
||||
def post(self, request):
|
||||
self.lock_workspace()
|
||||
input_serializer = ProductBulkSerializer(data=request.data)
|
||||
input_serializer.is_valid(raise_exception=True)
|
||||
data = input_serializer.validated_data
|
||||
products = {item.pk: item for item in Product.objects.select_for_update().filter(sys_ws=self.workspace, pk__in=data['ids'])}
|
||||
if len(products) != len(data['ids']):
|
||||
raise ValidationError({'ids': 'یک یا چند محصول در فضای کاری شما پیدا نشد.'})
|
||||
for position, pk in enumerate(data['ids'], 1):
|
||||
product = products[pk]
|
||||
if data['action'] == 'delete':
|
||||
ensure_product_deletable(product)
|
||||
product.delete()
|
||||
else:
|
||||
values = bulk_values(data, position)
|
||||
serializer = ProductManagementSerializer(product, data=values, partial=True, context=self.serializer_context())
|
||||
serializer.is_valid(raise_exception=True)
|
||||
for name, value in serializer.validated_data.items():
|
||||
setattr(product, name, value)
|
||||
product.full_clean()
|
||||
product.save()
|
||||
return Response({'updated': len(products), 'action': data['action']})
|
||||
|
||||
|
||||
def bulk_values(data, position):
|
||||
if data['action'] == 'move':
|
||||
return {'category': data['category']}
|
||||
if data['action'] == 'view_only':
|
||||
return {'view_only': data['view_only']}
|
||||
return {'order_prd' if data['action'] == 'display_order' else 'excel_order': position}
|
||||
|
||||
|
||||
class ProductExportApi(ManagementApi):
|
||||
def get(self, request):
|
||||
from apps.shop.admin import export_products
|
||||
return export_products(filtered_products(self.workspace, request.query_params))
|
||||
|
||||
|
||||
def batch_data(batch, page=1):
|
||||
result = batch.result
|
||||
rows = result.get('rows', [])
|
||||
return {'id': batch.pk, 'filename': batch.filename, 'created_at': batch.created_at, 'expires_at': batch.expires_at,
|
||||
'confirmed_at': batch.confirmed_at, 'options': batch.payload['options'],
|
||||
'created': result.get('created', 0), 'updated': result.get('updated', 0), 'errors': result.get('errors', 0),
|
||||
'committed': bool(batch.confirmed_at), 'can_confirm': not batch.confirmed_at and batch.expires_at > timezone.now()
|
||||
and (batch.payload['options']['errors'] == 'skip' or not result.get('errors')),
|
||||
'row_count': len(rows), 'row_page': page, 'rows': rows[(page-1)*100:page*100]}
|
||||
|
||||
|
||||
class ProductImportPreviewApi(ManagementApi):
|
||||
def post(self, request):
|
||||
serializer = ImportOptionsSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
data = serializer.validated_data
|
||||
options = {key: data[key] for key in ('mode', 'create_categories', 'errors', 'ordering')}
|
||||
batch = preview_batch(request.user, self.workspace, data['file'], options, data['sheet'], data['header_row'], data['mapping'])
|
||||
return Response(batch_data(batch), status=201)
|
||||
|
||||
|
||||
class ProductImportListApi(ManagementApi):
|
||||
def get(self, request):
|
||||
queryset = ProductImportBatch.objects.filter(sys_ws=self.workspace, created_by=request.user)
|
||||
pagination = ManagementPagination()
|
||||
rows = pagination.paginate_queryset(queryset, request)
|
||||
results = [{key: value for key, value in batch_data(batch).items() if key != 'rows'} for batch in rows]
|
||||
return pagination.get_paginated_response(results)
|
||||
|
||||
|
||||
class ProductImportDetailApi(ManagementApi):
|
||||
def get(self, request, pk):
|
||||
batch = get_object_or_404(ProductImportBatch, pk=pk, sys_ws=self.workspace, created_by=request.user)
|
||||
page_serializer = serializers.IntegerField(min_value=1, max_value=50)
|
||||
page = page_serializer.run_validation(request.query_params.get('row_page', 1))
|
||||
return Response(batch_data(batch, page))
|
||||
|
||||
|
||||
class ProductImportConfirmApi(ManagementApi):
|
||||
def post(self, request, pk):
|
||||
return Response(batch_data(confirm_batch(pk, request.user, self.workspace)))
|
||||
|
||||
|
||||
class ProductImportReportApi(ManagementApi):
|
||||
def get(self, request, pk):
|
||||
batch = get_object_or_404(ProductImportBatch, pk=pk, sys_ws=self.workspace, created_by=request.user)
|
||||
return batch_report(batch)
|
||||
|
||||
|
||||
class ProductImportTemplateApi(ManagementApi):
|
||||
def get(self, request):
|
||||
return import_template()
|
||||
@@ -11,6 +11,7 @@ from rest_framework import generics
|
||||
from apps.customer.models import Customer as CustomerModel
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from utils import custom_permissions
|
||||
import pandas as pd
|
||||
from utils.tools import inline_serializer
|
||||
from io import BytesIO
|
||||
|
||||
@@ -212,13 +213,14 @@ class OrderRetrieveOperatorApi(APIView):
|
||||
|
||||
|
||||
class OrderRetrieveOperatorExcelApi(APIView):
|
||||
permission_classes = (IsAuthenticated, )
|
||||
permission_classes = (IsAuthenticated, custom_permissions.WorkspaceOperatorPermission)
|
||||
def get(self, request, order_id):
|
||||
|
||||
order_df = retrieve_order_item_excel(request=request, order_id=order_id)
|
||||
|
||||
excel_file = BytesIO()
|
||||
order_df.to_excel(excel_file, engine='xlsxwriter', index=False)
|
||||
with pd.ExcelWriter(excel_file, engine='xlsxwriter', engine_kwargs={'options': {'strings_to_formulas': False, 'strings_to_urls': False}}) as writer:
|
||||
order_df.to_excel(writer, index=False)
|
||||
excel_file.seek(0)
|
||||
|
||||
response = HttpResponse(excel_file.read(), content_type='application/ms-excel')
|
||||
|
||||
@@ -16,11 +16,14 @@ class ProductCreateApi(APIView):
|
||||
permission_classes = (IsAuthenticated, custom_permissions.WorkspaceAdminPermission)
|
||||
|
||||
class InputSerializer(serializers.Serializer):
|
||||
name = serializers.CharField(required=True, max_length=20)
|
||||
price = serializers.DecimalField(required=True, max_digits=20, decimal_places=2)
|
||||
name = serializers.CharField(required=True, max_length=200)
|
||||
price = serializers.IntegerField(required=True, min_value=0, max_value=9223372036854775807)
|
||||
category = serializers.IntegerField(required=True)
|
||||
acc_code = serializers.CharField(required=False)
|
||||
attr = serializers.CharField(required=False)
|
||||
attr = serializers.JSONField(required=False, allow_null=True)
|
||||
order_prd = serializers.IntegerField(required=False, allow_null=True, min_value=0, max_value=2147483647)
|
||||
excel_order = serializers.IntegerField(required=False, allow_null=True, min_value=0, max_value=2147483647)
|
||||
view_only = serializers.BooleanField(required=False)
|
||||
|
||||
class OutputSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
@@ -64,11 +67,14 @@ class ProductUpdateApi(APIView):
|
||||
permission_classes = (IsAuthenticated, custom_permissions.WorkspaceAdminPermission)
|
||||
|
||||
class InputSerializer(serializers.Serializer):
|
||||
name = serializers.CharField(required=True, max_length=20)
|
||||
price = serializers.DecimalField(required=True, max_digits=20, decimal_places=2)
|
||||
name = serializers.CharField(required=True, max_length=200)
|
||||
price = serializers.IntegerField(required=True, min_value=0, max_value=9223372036854775807)
|
||||
category = serializers.IntegerField(required=True)
|
||||
acc_code = serializers.CharField(required=False)
|
||||
attr = serializers.CharField(required=False)
|
||||
attr = serializers.JSONField(required=False, allow_null=True)
|
||||
order_prd = serializers.IntegerField(required=False, allow_null=True, min_value=0, max_value=2147483647)
|
||||
excel_order = serializers.IntegerField(required=False, allow_null=True, min_value=0, max_value=2147483647)
|
||||
view_only = serializers.BooleanField(required=False)
|
||||
|
||||
class OutputSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
@@ -77,7 +83,7 @@ class ProductUpdateApi(APIView):
|
||||
|
||||
def put(self, request, product_id: int):
|
||||
|
||||
serializer = self.InputSerializer(data=request.data)
|
||||
serializer = self.InputSerializer(data=request.data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
user_workspace_uuid = get_user_workspace_uuid(request)
|
||||
@@ -116,7 +122,7 @@ class ProductListApi(generics.ListAPIView):
|
||||
|
||||
class OutputSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ProductCategoryModel
|
||||
model = ProductModel
|
||||
exclude = ('sys_ws', )
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -154,7 +160,7 @@ class ProductListCategoryApi(generics.ListAPIView):
|
||||
)
|
||||
data = {
|
||||
"category_name": category.name,
|
||||
"category_img": category.image.url,
|
||||
"category_img": category.image.url if category.image else None,
|
||||
"products": serializer.data,
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,10 @@ class ProductCategoryCreateApi(APIView):
|
||||
permission_classes = (IsAuthenticated, custom_permissions.WorkspaceAdminPermission)
|
||||
|
||||
class InputSerializer(serializers.Serializer):
|
||||
name = serializers.CharField(required=True, max_length=20)
|
||||
parent = serializers.IntegerField(required=False)
|
||||
name = serializers.CharField(required=True, max_length=60)
|
||||
parent = serializers.IntegerField(required=False, allow_null=True)
|
||||
order_cat = serializers.IntegerField(required=False, allow_null=True, min_value=0, max_value=2147483647)
|
||||
excel_order = serializers.IntegerField(required=False, allow_null=True, min_value=0, max_value=2147483647)
|
||||
|
||||
class OutputSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
@@ -62,7 +64,10 @@ class ProductCategoryUpdateApi(APIView):
|
||||
permission_classes = (IsAuthenticated, custom_permissions.WorkspaceAdminPermission)
|
||||
|
||||
class InputSerializer(serializers.Serializer):
|
||||
name = serializers.CharField(required=True)
|
||||
name = serializers.CharField(required=False, max_length=60)
|
||||
parent = serializers.IntegerField(required=False, allow_null=True)
|
||||
order_cat = serializers.IntegerField(required=False, allow_null=True, min_value=0, max_value=2147483647)
|
||||
excel_order = serializers.IntegerField(required=False, allow_null=True, min_value=0, max_value=2147483647)
|
||||
|
||||
class OutputSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
@@ -74,11 +79,11 @@ class ProductCategoryUpdateApi(APIView):
|
||||
serializer = self.InputSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
name = serializer.validated_data.get
|
||||
name = serializer.validated_data.get("name")
|
||||
|
||||
user_workspace_uuid = get_user_workspace_uuid(request)
|
||||
|
||||
product_category_obj = update_product_category(name=name, category_id=category_id, workspace_uuid=user_workspace_uuid)
|
||||
product_category_obj = update_product_category(category_id=category_id, workspace_uuid=user_workspace_uuid, **serializer.validated_data)
|
||||
|
||||
output = self.OutputSerializer(product_category_obj)
|
||||
|
||||
@@ -146,6 +151,7 @@ class ProductCategoryListApi(generics.ListAPIView):
|
||||
|
||||
|
||||
class ProductsCategoryApi(APIView):
|
||||
permission_classes = (IsAuthenticated, custom_permissions.WorkspaceCustomerPermission)
|
||||
|
||||
class OutputSerializer(serializers.ModelSerializer):
|
||||
product_count = serializers.IntegerField()
|
||||
@@ -156,7 +162,9 @@ class ProductsCategoryApi(APIView):
|
||||
|
||||
def get(self, request):
|
||||
|
||||
p_cate = ProductCategoryModel.objects.annotate(product_count=Count('product')).filter(product_count__gte=1).order_by('order_cat')
|
||||
p_cate = ProductCategoryModel.objects.filter(
|
||||
sys_ws__uuid=get_user_workspace_uuid(request),
|
||||
).annotate(product_count=Count('product')).filter(product_count__gte=1)
|
||||
output = self.OutputSerializer(p_cate, many=True)
|
||||
|
||||
return Response(data=output.data, status=status.HTTP_200_OK)
|
||||
Reference in new issue
Block a user