diff --git a/apps/product/services/excel/__init__.py b/apps/product/services/excel/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/product/services/excel/excel_processing.py b/apps/product/services/excel/excel_processing.py index e69de29..560e848 100644 --- a/apps/product/services/excel/excel_processing.py +++ b/apps/product/services/excel/excel_processing.py @@ -0,0 +1,158 @@ +from io import BytesIO + +from django.db.models import Q +from django.http import HttpResponse +from openpyxl import Workbook +from rest_framework import viewsets +from rest_framework.decorators import action + +from apps.product import models as product_models +from apps.product.web.api.v1.serializers import quota_distribution_serializers as distribution_serializers +from common.helper_excel import create_header, excel_description, create_header_freez, create_value, shamsi_date, \ + convert_str_to_date +from common.helpers import get_organization_by_user + + +class QuotaDistributionExcelViewSet(viewsets.ModelViewSet): + queryset = product_models.QuotaDistribution.objects.all() + serializer_class = distribution_serializers.QuotaDistributionSerializer + + @action( + methods=['get'], + detail=False, + url_path='my_distributions_excel', + url_name='my_distributions_excel', + name='my_distributions_excel' + ) + def my_distributions_excel(self, request): + output = BytesIO() + workbook = Workbook() + worksheet = workbook.active + worksheet.sheet_view.rightToLeft = True + worksheet.insert_rows(1) + + product = self.queryset + query = request.query_params + organization = get_organization_by_user(request.user) + + if query.get('param') == 'assigned': + product = product.filter( + Q(assigned_organization=organization) + ).order_by('-modify_date') + + elif query.get('param') == 'assigner': + product = product.filter( + Q(assigner_organization=organization) + ).order_by('-modify_date') + + elif query.get('param') == 'all': + product = product.filter( + Q(assigner_organization=organization) | + Q(assigned_organization=organization) + ).order_by('-modify_date') + ser_data = distribution_serializers.QuotaDistributionSerializer(product, many=True).data + + excel_options = [ + "ردیف", + "شناسه توزیع", + "شناسه سهمیه", + "تاریخ ثبت", + "توزیع کننده", + "دریافت کننده", + "وزن", + "وزن توزیع شده", + "وزن باقیمانده", + "وزن فروش رفته", + "مانده انبار", + "ورودی به انبار", + "توضیحات", + ] + + header_list = [ + "وزن", + "وزن توزیع شده", + "وزن باقیمانده", + "وزن فروش رفته", + "مانده انبار", + "ورودی به انبار", + + ] + + create_header(worksheet, header_list, 5, 2, height=20, border_style='thin') + + excel_description(worksheet, 'B1', f'سهمیه', row2='C3') + + create_header_freez(worksheet, excel_options, 1, 6, 7, height=22, width=20) + + l = 6 + m = 1 + if ser_data: + for data in ser_data: + list1 = [ + m, + data['distribution_id'] or '', + str(data['quota']['quota_id']) if data.get('quota') and data['quota'].get('quota_id') else '', + str(shamsi_date(convert_str_to_date(data['create_date']), in_value=True)) if data.get( + 'create_date') else '', + data[ + 'assigner_organization'].get('organization') or '-', + data[ + 'assigned_organization'].get('organization') or '-', + data.get('weight') or 0, + data.get('distributed') or 0, + data.get('remaining_weight') or 0, + data.get('been_sold') or 0, + data.get('warehouse_balance') or 0, + data.get('warehouse_entry') or 0, + data.get('description') or '-' + ] + create_value(worksheet, list1, l + 1, 1, m=m) + + m += 1 + l += 1 + + weight = sum((data['weight'] or 0) for data in ser_data) + distributed = sum((data['distributed'] or 0) for data in ser_data) + remaining_weight = sum((data['remaining_weight'] or 0) for data in ser_data) + been_sold = sum((data['been_sold'] or 0) for data in ser_data) + warehouse_balance = sum((data['warehouse_balance'] or 0) for data in ser_data) + warehouse_entry = sum((data['warehouse_entry'] or 0) for data in ser_data) + + value_list = [ + weight, + distributed, + remaining_weight, + been_sold, + warehouse_balance, + warehouse_entry, + ] + create_value(worksheet, value_list, 3, 5, border_style='thin') + + list2 = [ + 'مجموع==>', + '', + '', + '', + '', + '', + weight, + distributed, + remaining_weight, + been_sold, + warehouse_balance, + warehouse_entry, + '', + + ] + create_value(worksheet, list2, l + 3, 1, color='gray') + + workbook.save(output) + output.seek(0) + + response = HttpResponse( + content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') + response[ + 'Content-Disposition'] = f'attachment; filename="اختلاف کشتار.xlsx"'.encode( + 'utf-8') + response.write(output.getvalue()) + return response diff --git a/apps/product/services/excel/urls.py b/apps/product/services/excel/urls.py new file mode 100644 index 0000000..bcf55d2 --- /dev/null +++ b/apps/product/services/excel/urls.py @@ -0,0 +1,13 @@ +from django.urls import path, include +from rest_framework.routers import DefaultRouter + +from apps.product.services.excel.excel_processing import QuotaDistributionExcelViewSet + +router = DefaultRouter() +router.register(r'', QuotaDistributionExcelViewSet, basename='quota_distribution_excel') + + +urlpatterns = [ + path('', include(router.urls)), + # path('my_distributions_excel/', my_distributions_excel), +] diff --git a/apps/product/urls.py b/apps/product/urls.py index 3afe724..a64041d 100644 --- a/apps/product/urls.py +++ b/apps/product/urls.py @@ -1,5 +1,6 @@ from django.urls import path, include urlpatterns = [ - path('web/api/', include('apps.product.web.api.v1.urls')) + path('web/api/', include('apps.product.web.api.v1.urls')), + path('excel/', include('apps.product.services.excel.urls')), ] diff --git a/apps/warehouse/services/excel/excel_processing.py b/apps/warehouse/services/excel/excel_processing.py index ab1bb15..2443be6 100644 --- a/apps/warehouse/services/excel/excel_processing.py +++ b/apps/warehouse/services/excel/excel_processing.py @@ -1,78 +1,259 @@ from io import BytesIO - +from django.db.models import Q from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt from openpyxl import Workbook -from openpyxl.styles import Alignment -from rest_framework import viewsets -from rest_framework.decorators import action, api_view, permission_classes -from rest_framework.permissions import AllowAny , IsAuthenticated +from rest_framework.decorators import api_view, permission_classes +from rest_framework.permissions import IsAuthenticated +from common.helpers import get_organization_by_user +from apps.product import models as product_models +from apps.product.web.api.v1.serializers import quota_distribution_serializers as distribution_serializers from apps.warehouse import models as warehouse_models from apps.warehouse.web.api.v1 import serializers as warehouse_serializers -from common.helper_excel import create_header, excel_description, create_header_freez, create_value +from common.helper_excel import create_header, excel_description, create_header_freez, create_value, shamsi_date, \ + convert_str_to_date +from io import BytesIO + +from django.db.models import Q +from django.http import HttpResponse +from django.views.decorators.csrf import csrf_exempt +from openpyxl import Workbook +from rest_framework.decorators import api_view, permission_classes +from rest_framework.permissions import IsAuthenticated + +from apps.product import models as product_models +from apps.product.web.api.v1.serializers import quota_distribution_serializers as distribution_serializers +from apps.warehouse import models as warehouse_models +from apps.warehouse.web.api.v1 import serializers as warehouse_serializers +from common.helper_excel import create_header, excel_description, create_header_freez, create_value, shamsi_date, \ + convert_str_to_date +from common.helpers import get_organization_by_user @api_view(["GET"]) @permission_classes([IsAuthenticated]) @csrf_exempt def warehouse_excel(request): - - excel_options = [ - 'ردیف', - 'وضعیت', - 'ثبت کننده', - 'تاریخ ثبت', - 'مرغدار', - 'کشتارگاه', - 'حجم', - 'حجم کم شده از سالن مرغدار', - 'وزن تقریبی کشتار(کیلوگرم)', - 'حجم سفارشات دریافتی توسط کشتارگاه', - 'اختلاف کشتار(حجم)', + sheet_names = [ + 'سهمیه', + 'ورودی به انبار', ] - - output = BytesIO() workbook = Workbook() worksheet = workbook.active - worksheet.sheet_view.rightToLeft = True - worksheet.insert_rows(1) - cell = worksheet.cell(row=1, column=1) - cell.alignment = Alignment(horizontal='center', vertical='center') + workbook.remove(worksheet) + for name in sheet_names: + sheet_name = name + worksheet = workbook.create_sheet(sheet_name) + worksheet.sheet_view.rightToLeft = True + worksheet.insert_rows(1) + if sheet_name == 'سهمیه': + product = product_models.QuotaDistribution.objects.all() + query = request.query_params + organization = get_organization_by_user(request.user) - header_list = [ - 'حجم', - 'حجم کم شده از سالن مرغدار', - 'وزن تقریبی کشتار(کیلوگرم)', - 'حجم سفارشات دریافتی توسط کشتارگاه', - 'اختلاف کشتار(حجم)', + if query.get('param') == 'assigned': + product = product.filter( + Q(assigned_organization=organization) + ).order_by('-modify_date') - ] + elif query.get('param') == 'assigner': + product = product.filter( + Q(assigner_organization=organization) + ).order_by('-modify_date') - create_header(worksheet, header_list, 5, 2, height=20) + elif query.get('param') == 'all': + product = product.filter( + Q(assigner_organization=organization) | + Q(assigned_organization=organization) + ).order_by('-modify_date') + ser_data = distribution_serializers.QuotaDistributionSerializer(product, many=True).data - excel_description(worksheet, 'B1', f'اختلاف کشتار ', color='red', row2='C3') + excel_options = [ + "ردیف", + "شناسه توزیع", + "شناسه سهمیه", + "تاریخ ثبت", + "توزیع کننده", + "دریافت کننده", + "وزن", + "وزن توزیع شده", + "وزن باقیمانده", + "وزن فروش رفته", + "مانده انبار", + "ورودی به انبار", + "توضیحات", + ] - create_header_freez(worksheet, excel_options, 1, 6, 7, height=22) + header_list = [ + "وزن", + "وزن توزیع شده", + "وزن باقیمانده", + "وزن فروش رفته", + "مانده انبار", + "ورودی به انبار", - l = 5 - m = 1 + ] + + create_header(worksheet, header_list, 5, 2, height=20, border_style='thin') + + excel_description(worksheet, 'B1', f'سهمیه', row2='C3') + + create_header_freez(worksheet, excel_options, 1, 6, 7, height=22, width=20) + + l = 6 + m = 1 + if ser_data: + for data in ser_data: + list1 = [ + m, + data['distribution_id'] or '', + str(data['quota']['quota_id']) if data.get('quota') and data['quota'].get('quota_id') else '', + str(shamsi_date(convert_str_to_date(data['create_date']), in_value=True)) if data.get( + 'create_date') else '', + data[ + 'assigner_organization'].get('organization') or '-', + data[ + 'assigned_organization'].get('organization') or '-', + data.get('weight') or 0, + data.get('distributed') or 0, + data.get('remaining_weight') or 0, + data.get('been_sold') or 0, + data.get('warehouse_balance') or 0, + data.get('warehouse_entry') or 0, + data.get('description') or '-' + ] + create_value(worksheet, list1, l + 1, 1, m=m) + + m += 1 + l += 1 + + weight = sum((data['weight'] or 0) for data in ser_data) + distributed = sum((data['distributed'] or 0) for data in ser_data) + remaining_weight = sum((data['remaining_weight'] or 0) for data in ser_data) + been_sold = sum((data['been_sold'] or 0) for data in ser_data) + warehouse_balance = sum((data['warehouse_balance'] or 0) for data in ser_data) + warehouse_entry = sum((data['warehouse_entry'] or 0) for data in ser_data) + + value_list = [ + weight, + distributed, + remaining_weight, + been_sold, + warehouse_balance, + warehouse_entry, + ] + create_value(worksheet, value_list, 3, 5, border_style='thin') + + list2 = [ + 'مجموع==>', + '', + '', + '', + '', + '', + weight, + distributed, + remaining_weight, + been_sold, + warehouse_balance, + warehouse_entry, + '', + + ] + create_value(worksheet, list2, l + 3, 1, color='gray') + else: + entries = warehouse_models.InventoryEntry.objects.filter( + organization=get_organization_by_user(request.user)) + ser_data = warehouse_serializers.InventoryEntrySerializer(entries, many=True).data + + excel_options = [ + "ردیف", + "تاریخ ورود به انبار", + "شماره سهمیه", + "وزن", + "بارنامه", + "محل دریافت", + "سند", + "سند", + "توضیحات", + ] + + header_list = [ + "وزن", + ] - list2 = [ - 'مجموع==>', - '', - '', - '', - '', - '', + create_header(worksheet, header_list, 5, 2, height=20, border_style='thin') + excel_description(worksheet, 'B1', f'ورودی به انبار', row2='C3') - ] - create_value(worksheet, list2, l + 3, 1, color='green') + create_header_freez(worksheet, excel_options, 1, 6, 7, height=22, width=20) + + l = 6 + m = 1 + if ser_data: + for data in ser_data: + list1 = [ + m, + data['distribution_id'] or '', + str(data['quota']['quota_id']) if data.get('quota') and data['quota'].get('quota_id') else '', + str(shamsi_date(convert_str_to_date(data['create_date']), in_value=True)) if data.get( + 'create_date') else '', + data[ + 'assigner_organization'].get('organization') or '-', + data[ + 'assigned_organization'].get('organization') or '-', + data.get('weight') or 0, + data.get('distributed') or 0, + data.get('remaining_weight') or 0, + data.get('been_sold') or 0, + data.get('warehouse_balance') or 0, + data.get('warehouse_entry') or 0, + data.get('description') or '-' + ] + create_value(worksheet, list1, l + 1, 1, m=m) + + m += 1 + l += 1 + + weight = sum((data['weight'] or 0) for data in ser_data) + distributed = sum((data['distributed'] or 0) for data in ser_data) + remaining_weight = sum((data['remaining_weight'] or 0) for data in ser_data) + been_sold = sum((data['been_sold'] or 0) for data in ser_data) + warehouse_balance = sum((data['warehouse_balance'] or 0) for data in ser_data) + warehouse_entry = sum((data['warehouse_entry'] or 0) for data in ser_data) + + value_list = [ + weight, + distributed, + remaining_weight, + been_sold, + warehouse_balance, + warehouse_entry, + ] + create_value(worksheet, value_list, 3, 5, border_style='thin') + + list2 = [ + 'مجموع==>', + '', + '', + '', + '', + '', + weight, + distributed, + remaining_weight, + been_sold, + warehouse_balance, + warehouse_entry, + '', + + ] + create_value(worksheet, list2, l + 3, 1, color='gray') workbook.save(output) output.seek(0) diff --git a/common/helper_excel.py b/common/helper_excel.py index e7d4e4a..5ca0352 100644 --- a/common/helper_excel.py +++ b/common/helper_excel.py @@ -19,6 +19,9 @@ ORANGE_CELL = PatternFill(start_color="FFC000", fill_type="solid") BLUE_CELL = PatternFill(start_color="538DD5", fill_type="solid") LIGHT_GREEN_CELL = PatternFill(start_color="92D050", fill_type="solid") VERY_LIGHT_GREEN_CELL = PatternFill(start_color="5AFC56", fill_type="solid") +GRAY_CELL = PatternFill(start_color="B0B0B0", fill_type="solid") +CREAM_CELL = PatternFill(start_color="D8AA72", fill_type="solid") +LIGHT_CREAM_CELL = PatternFill(start_color="E8C6A0", fill_type="solid") def shamsi_date(date, in_value=None): @@ -55,7 +58,7 @@ def create_header(worksheet, list, num, row, height=None, width=None, color=None else: cell.fill = PatternFill(start_color=color, fill_type="solid") else: - cell.fill = blue_fill + cell.fill = CREAM_CELL if text_color is not None: cell.font = Font(size=9, bold=True, color=text_color) else: @@ -79,8 +82,8 @@ def create_header_freez(worksheet, list, num, row, header_row, height=None, widt col_letter = get_column_letter(col_num) cell = worksheet.cell(row=row, column=col_num, value=option) cell.alignment = Alignment_CELL - cell.fill = blue_fill - cell.font = Font(size=10, bold=True, color='D9FFFFFF') + cell.fill = LIGHT_CREAM_CELL + cell.font = Font(size=10, bold=True, color='404040') if height is not None: worksheet.row_dimensions[row].height = height @@ -123,7 +126,8 @@ def create_value(worksheet, list, l, num, border_style=None, m=None, height=None 'blue': BLUE_CELL, 'red': RED_CELL, 'light_green': LIGHT_GREEN_CELL, - 'very_light_green': VERY_LIGHT_GREEN_CELL + 'very_light_green': VERY_LIGHT_GREEN_CELL, + 'gray': GRAY_CELL } for item in range(len(list)): @@ -147,7 +151,7 @@ def create_value(worksheet, list, l, num, border_style=None, m=None, height=None cell.font = Font(size=10, bold=True) if m is not None and m % 2 != 0: - cell.fill = PatternFill(start_color="D6F6FE", fill_type="solid") + cell.fill = PatternFill(start_color="FAF0E7", fill_type="solid") if height is not None: worksheet.row_dimensions[l + 1].height = height @@ -291,4 +295,11 @@ def to_locale_str(a): def convert_str_to_date(string): - return datetime.strptime(str(string), '%Y-%m-%d').date() + string = str(string).strip() + try: + return datetime.strptime(string, '%Y-%m-%dT%H:%M:%S.%fZ').date() + except ValueError: + try: + return datetime.strptime(string, '%Y-%m-%d').date() + except ValueError: + return None \ No newline at end of file