From f69d0b98a84ce0116da1eaf754ffde8ec0a34ba8 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 8 Jun 2024 22:28:12 +0200 Subject: [PATCH 01/17] Added delivery_cost to serializer, fix views tests --- makedoc/serializers.py | 1 + makedoc/tests/test_views_makedoc.py | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/makedoc/serializers.py b/makedoc/serializers.py index a904bfc..467ba67 100644 --- a/makedoc/serializers.py +++ b/makedoc/serializers.py @@ -14,3 +14,4 @@ class DataDocSerializer(serializers.Serializer[Any]): items = serializers.ListField(child=OrderItemSerializer()) factory_id = serializers.IntegerField() destination = serializers.CharField() + delivery_cost = serializers.IntegerField() diff --git a/makedoc/tests/test_views_makedoc.py b/makedoc/tests/test_views_makedoc.py index 1ae2c8f..84118b7 100644 --- a/makedoc/tests/test_views_makedoc.py +++ b/makedoc/tests/test_views_makedoc.py @@ -8,13 +8,14 @@ def test__data_view__unauthorized_user_cannot_post_data() -> None: client = APIClient() url = reverse("data") data = { - "client_id": 123, + "client_id": 1, "items": [ {"product_id": 1, "quantity": 2, "discount": 10}, {"product_id": 2, "quantity": 5, "discount": 4}, ], "factory_id": 1, "destination": "New York", + "delivery_cost": 2000, } response = client.post(url, data, format="json") assert response.status_code == 401 # Unauthorized @@ -24,13 +25,14 @@ def test__data_view__unauthorized_user_cannot_post_data() -> None: def test__goods__authorized_user_can_post_data(authorized_client) -> None: url = reverse("data") data = { - "client_id": 123, + "client_id": 1, "items": [ {"product_id": 1, "quantity": 2, "discount": 10}, {"product_id": 2, "quantity": 5, "discount": 4}, ], "factory_id": 1, "destination": "New York", + "delivery_cost": 1500, } response = authorized_client.post(url, data, format="json") assert response.status_code == 200 @@ -40,13 +42,14 @@ def test__goods__authorized_user_can_post_data(authorized_client) -> None: def test__goods__authorized_user_post_data_response_is_correct(authorized_client) -> None: url = reverse("data") data = { - "client_id": 123, + "client_id": 1, "items": [ {"product_id": 1, "quantity": 2, "discount": 10}, {"product_id": 2, "quantity": 5, "discount": 4}, ], "factory_id": 1, "destination": "New York", + "delivery_cost": 1500, } response = authorized_client.post(url, data, format="json") assert response.json() == data From ec7ca6a0a6cdc99bf3fac4d910ee685c82843b8b Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 8 Jun 2024 22:30:25 +0200 Subject: [PATCH 02/17] Added class DataService --- makedoc/data_service.py | 7 +++++++ makedoc/views.py | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 makedoc/data_service.py diff --git a/makedoc/data_service.py b/makedoc/data_service.py new file mode 100644 index 0000000..a783d9f --- /dev/null +++ b/makedoc/data_service.py @@ -0,0 +1,7 @@ + + +class DataService: + @staticmethod + def process_data(data): + processed_data = data + return processed_data diff --git a/makedoc/views.py b/makedoc/views.py index 4938e85..2f22c24 100644 --- a/makedoc/views.py +++ b/makedoc/views.py @@ -6,6 +6,7 @@ from rest_framework.response import Response from makedoc.services import Documents +from .data_service import DataService from .serializers import DataDocSerializer @@ -34,4 +35,6 @@ def post(self, request, *args, **kwargs): validated_data = serializer.validated_data - return Response(validated_data, status=status.HTTP_200_OK) + processed_data = DataService.process_data(validated_data) + + return Response(processed_data, status=status.HTTP_200_OK) From 6dc4986f5787edead53e6b2e46f5ad59686dd776 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 8 Jun 2024 22:31:57 +0200 Subject: [PATCH 03/17] Added new method get_client for DataService class --- makedoc/data_service.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/makedoc/data_service.py b/makedoc/data_service.py index a783d9f..2f7ac28 100644 --- a/makedoc/data_service.py +++ b/makedoc/data_service.py @@ -1,3 +1,4 @@ +from clients.models import Client class DataService: @@ -5,3 +6,28 @@ class DataService: def process_data(data): processed_data = data return processed_data + + @staticmethod + def get_client(processed_data): + try: + client_id = processed_data.get("client_id") + client = Client.objects.get(id=client_id) + client_data = { + "client_name": str(client.client_name), + "contract_number": str(client.contract_number), + "contract_date": str(client.contract_date), + "director_position": str(client.director_position), + "director_name": str(client.director_name), + "destination_city": str(client.destination_city), + "railway_station": str(client.railway_station), + "receiver_name": str(client.receiver_name), + "receiver_id": int(client.receiver_id), + "receiver_okpo": int(client.receiver_okpo), + "receiver_adress": str(client.receiver_adress), + "special_marks": str(client.special_marks), + "last_application_number": str(client.last_application_number), + } + + return client_data + except Client.DoesNotExist: + raise Exception("Client not found") From 05212a02d8cc1193f1eed9f9e452f8846bb035d4 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 8 Jun 2024 22:33:23 +0200 Subject: [PATCH 04/17] Added new methods get_products, get_factory for DataService class --- makedoc/data_service.py | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/makedoc/data_service.py b/makedoc/data_service.py index 2f7ac28..a7077dd 100644 --- a/makedoc/data_service.py +++ b/makedoc/data_service.py @@ -1,4 +1,6 @@ from clients.models import Client +from goods.models import Product +from logistics.models import Factory class DataService: @@ -31,3 +33,45 @@ def get_client(processed_data): return client_data except Client.DoesNotExist: raise Exception("Client not found") + + @staticmethod + def get_products(processed_data): + try: + products_data = processed_data.get("items") + results = [] + for item in products_data: + product_id = item.get("product_id") + product = Product.objects.get(id=product_id) + product_data = { + "product": product.id, + "flour_name": str(product.flour_name), + "brand": str(product.brand), + "package": str(product.package.package), + "price": str(product.price), + "quantity": item.get("quantity"), + "discount": item.get("discount"), + } + + results.append(product_data) + return results + except Product.DoesNotExist: + raise Exception("Product not found") + + @staticmethod + def get_factory(processed_data): + try: + factory_id = processed_data.get("factory_id") + factory = Factory.objects.get(id=factory_id) + factory_data = { + "id": int(factory.id), + "full_name": str(factory.full_name), + "short_name": str(factory.short_name), + "full_address": str(factory.full_address), + "departure_city": str(factory.departure_city), + "departure_station_branch": str(factory.departure_station_branch), + "departure_station_id": str(factory.departure_station_id), + "departure_station_name": str(factory.departure_station_name), + } + return factory_data + except Factory.DoesNotExist: + raise Exception("Factory not found") From 54a5d550502055ea750445343d9de6a3b3d07851 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 8 Jun 2024 22:34:04 +0200 Subject: [PATCH 05/17] Added new methods get_delivery_cost, get_city, get_rw for DataService class --- makedoc/data_service.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/makedoc/data_service.py b/makedoc/data_service.py index a7077dd..31cefc6 100644 --- a/makedoc/data_service.py +++ b/makedoc/data_service.py @@ -1,6 +1,6 @@ from clients.models import Client from goods.models import Product -from logistics.models import Factory +from logistics.models import Factory, RailwayStation class DataService: @@ -75,3 +75,32 @@ def get_factory(processed_data): return factory_data except Factory.DoesNotExist: raise Exception("Factory not found") + + @staticmethod + def get_delivery_cost(processed_data): + delivery_cost = processed_data.get("delivery_cost") + if delivery_cost is None: + raise Exception("Delivery cost not found") + return delivery_cost + + @staticmethod + def get_city(processed_data): + city = processed_data.get("destination") + if city is None: + raise Exception("City not found") + return city + + @staticmethod + def get_rw(processed_data): + try: + rw_id = processed_data.get("destination") + rw = RailwayStation.objects.get(id=rw_id) + rw_data = { + "id": int(rw.id), + "station_name": str(rw.station_name), + "station_id": int(rw.station_id), + "station_branch": str(rw.station_branch), + } + return rw_data + except RailwayStation.DoesNotExist: + raise Exception("Railway station not found") From 0375f706d69428088ac06eb2680aa7afc10cce40 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 8 Jun 2024 22:35:39 +0200 Subject: [PATCH 06/17] fix mypy errors --- makedoc/data_service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/makedoc/data_service.py b/makedoc/data_service.py index 31cefc6..6414061 100644 --- a/makedoc/data_service.py +++ b/makedoc/data_service.py @@ -23,8 +23,8 @@ def get_client(processed_data): "destination_city": str(client.destination_city), "railway_station": str(client.railway_station), "receiver_name": str(client.receiver_name), - "receiver_id": int(client.receiver_id), - "receiver_okpo": int(client.receiver_okpo), + "receiver_id": str(client.receiver_id), + "receiver_okpo": str(client.receiver_okpo), "receiver_adress": str(client.receiver_adress), "special_marks": str(client.special_marks), "last_application_number": str(client.last_application_number), From b7cc1893f15f2842d8da835edc4592300e4b14b2 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sun, 9 Jun 2024 22:51:58 +0200 Subject: [PATCH 07/17] Refactor DataService class --- makedoc/data_service.py | 94 +++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 61 deletions(-) diff --git a/makedoc/data_service.py b/makedoc/data_service.py index 6414061..549a010 100644 --- a/makedoc/data_service.py +++ b/makedoc/data_service.py @@ -5,102 +5,74 @@ class DataService: @staticmethod - def process_data(data): - processed_data = data - return processed_data + def get_delivery_type(validated_data): + delivery_type = validated_data.get("delivery_type") + if delivery_type is None: + raise Exception("Type delivery not found") + return delivery_type @staticmethod - def get_client(processed_data): + def get_client(validated_data): try: - client_id = processed_data.get("client_id") + client_id = validated_data.get("client_id") client = Client.objects.get(id=client_id) - client_data = { - "client_name": str(client.client_name), - "contract_number": str(client.contract_number), - "contract_date": str(client.contract_date), - "director_position": str(client.director_position), - "director_name": str(client.director_name), - "destination_city": str(client.destination_city), - "railway_station": str(client.railway_station), - "receiver_name": str(client.receiver_name), - "receiver_id": str(client.receiver_id), - "receiver_okpo": str(client.receiver_okpo), - "receiver_adress": str(client.receiver_adress), - "special_marks": str(client.special_marks), - "last_application_number": str(client.last_application_number), - } - - return client_data + return client except Client.DoesNotExist: raise Exception("Client not found") @staticmethod - def get_products(processed_data): + def get_products(validated_data): try: - products_data = processed_data.get("items") + products_data = validated_data.get("items") results = [] for item in products_data: product_id = item.get("product_id") + product_quantity = item.get("quantity") + product_discount = item.get("discount") product = Product.objects.get(id=product_id) - product_data = { - "product": product.id, - "flour_name": str(product.flour_name), - "brand": str(product.brand), - "package": str(product.package.package), - "price": str(product.price), - "quantity": item.get("quantity"), - "discount": item.get("discount"), - } - - results.append(product_data) + results.append(product) + results.append(product_quantity) + results.append(product_discount) return results except Product.DoesNotExist: raise Exception("Product not found") @staticmethod - def get_factory(processed_data): + def get_factory(validated_data): try: - factory_id = processed_data.get("factory_id") + factory_id = validated_data.get("factory_id") factory = Factory.objects.get(id=factory_id) - factory_data = { - "id": int(factory.id), - "full_name": str(factory.full_name), - "short_name": str(factory.short_name), - "full_address": str(factory.full_address), - "departure_city": str(factory.departure_city), - "departure_station_branch": str(factory.departure_station_branch), - "departure_station_id": str(factory.departure_station_id), - "departure_station_name": str(factory.departure_station_name), - } - return factory_data + return factory except Factory.DoesNotExist: raise Exception("Factory not found") @staticmethod - def get_delivery_cost(processed_data): - delivery_cost = processed_data.get("delivery_cost") + def get_delivery_cost(validated_data): + delivery_cost = validated_data.get("delivery_cost") if delivery_cost is None: raise Exception("Delivery cost not found") return delivery_cost @staticmethod - def get_city(processed_data): - city = processed_data.get("destination") + def get_city(validated_data): + city = validated_data.get("destination") if city is None: raise Exception("City not found") return city @staticmethod - def get_rw(processed_data): + def get_rw(validated_data): try: - rw_id = processed_data.get("destination") + rw_id = validated_data.get("destination") rw = RailwayStation.objects.get(id=rw_id) - rw_data = { - "id": int(rw.id), - "station_name": str(rw.station_name), - "station_id": int(rw.station_id), - "station_branch": str(rw.station_branch), - } - return rw_data + return rw except RailwayStation.DoesNotExist: raise Exception("Railway station not found") + + @staticmethod + def get_user(request): + user = request.user + if user: + return user + else: + raise Exception("User is not authenticated") From 78fe4bfebb05cfca3ef7481181f452b1cda5463c Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sun, 9 Jun 2024 22:53:44 +0200 Subject: [PATCH 08/17] Refactor makedoc views, update makedoc urls --- makedoc/urls.py | 5 ++-- makedoc/views.py | 59 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/makedoc/urls.py b/makedoc/urls.py index db8218a..17de741 100644 --- a/makedoc/urls.py +++ b/makedoc/urls.py @@ -1,9 +1,8 @@ from django.urls import path -from . import views -from .views import DataDocView +from .views import DataDocView, CreateDocsView urlpatterns = [ - path("filemake/", views.create_docs, name="file"), + path("filemake/", CreateDocsView.as_view(), name="file"), path("data/", DataDocView.as_view(), name="data"), ] diff --git a/makedoc/views.py b/makedoc/views.py index 2f22c24..9377082 100644 --- a/makedoc/views.py +++ b/makedoc/views.py @@ -1,28 +1,46 @@ +import json from typing import Any -from django.http import HttpResponse +from django.core.cache import cache from rest_framework import generics, status +from rest_framework.exceptions import ValidationError from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response +from rest_framework.views import APIView from makedoc.services import Documents -from .data_service import DataService from .serializers import DataDocSerializer -def create_docs(request): - docs = Documents() - docs.update_documents(["auto", "rw", "service_note", "transport_sheet"]) - if docs.auto: - docs.form_auto_document(request) - if docs.rw: - docs.form_rw_document(request) - if docs.service_note: - docs.form_service_note(request) - if docs.transport_sheet: - docs.form_transport_sheet(request) +class CreateDocsView(APIView): + permission_classes = [IsAuthenticated] - return HttpResponse("Документы сохранены") + def get(self, request, *args, **kwargs): + cache_key = f"validated_data_{request.user.id}" + validated_data = cache.get(cache_key) + + if validated_data is None: + return Response({"error": "No data found in cache"}, + status=status.HTTP_400_BAD_REQUEST) + + try: + validated_data = json.loads(validated_data) + except json.JSONDecodeError: + return Response({"error": "Invalid data in cache"}, status=status.HTTP_400_BAD_REQUEST) + + docs = Documents(validated_data) + docs.update_documents() + if docs.auto: + docs.form_auto_document(request) + if docs.rw: + docs.form_rw_document(request) + if docs.service_note: + docs.form_service_note(request) + if docs.transport_sheet: + docs.form_transport_sheet(request) + + return Response({"message": "Документы сохранены", "data": validated_data}, + status=status.HTTP_200_OK) class DataDocView(generics.GenericAPIView[Any]): @@ -30,11 +48,16 @@ class DataDocView(generics.GenericAPIView[Any]): permission_classes = (IsAuthenticated,) def post(self, request, *args, **kwargs): - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) + try: + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + except ValidationError as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) validated_data = serializer.validated_data - processed_data = DataService.process_data(validated_data) + # Use a more unique cache key + cache_key = f"validated_data_{request.user.id}" + cache.set(cache_key, json.dumps(validated_data), 120) - return Response(processed_data, status=status.HTTP_200_OK) + return Response({'success': True, 'data': validated_data}, status=status.HTTP_200_OK) From d22be0466c4c4118efe5a4ede5c280b8869e2a10 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sun, 9 Jun 2024 22:55:39 +0200 Subject: [PATCH 09/17] Edit makedoc serializers, services --- makedoc/serializers.py | 5 +- makedoc/services.py | 133 ++++++++++++++++++++++++----------------- 2 files changed, 80 insertions(+), 58 deletions(-) diff --git a/makedoc/serializers.py b/makedoc/serializers.py index 467ba67..5a56dcd 100644 --- a/makedoc/serializers.py +++ b/makedoc/serializers.py @@ -6,12 +6,13 @@ class OrderItemSerializer(serializers.Serializer[Any]): product_id = serializers.IntegerField() quantity = serializers.IntegerField() - discount = serializers.IntegerField(required=False, default=0) + discount = serializers.IntegerField(required=False, default=0, max_value=100) class DataDocSerializer(serializers.Serializer[Any]): + delivery_type = serializers.ListField() client_id = serializers.IntegerField() items = serializers.ListField(child=OrderItemSerializer()) factory_id = serializers.IntegerField() destination = serializers.CharField() - delivery_cost = serializers.IntegerField() + delivery_cost = serializers.IntegerField(min_value=0) diff --git a/makedoc/services.py b/makedoc/services.py index b5fc7d0..723a52c 100644 --- a/makedoc/services.py +++ b/makedoc/services.py @@ -10,6 +10,7 @@ from goods.models import Product from logistics.models import City, RailwayStation, Factory from users.models import CustomUser +from .data_service import DataService morph = pymorphy3.MorphAnalyzer() @@ -45,30 +46,84 @@ def get_formatted_date_shipment(case): class Documents: - def __init__(self): + def __init__(self, validated_data): + self.validated_data = validated_data self.auto = 0 self.rw = 0 self.service_note = 0 self.transport_sheet = 0 - def update_documents(self, documents_list): - if "auto" in documents_list: + def update_documents(self): + delivery_type = DataService.get_delivery_type(self.validated_data) + if delivery_type is None: + raise Exception("Type delivery not found") + if "auto" in delivery_type: self.auto = 1 - if "rw" in documents_list: + if "rw" in delivery_type: self.rw = 1 - if "service_note" in documents_list: + if "service_note" in delivery_type: self.service_note = 1 - if "transport_sheet" in documents_list: + if "transport_sheet" in delivery_type: self.transport_sheet = 1 + def get_user(self, request): + try: + return CustomUser.objects.first() + except CustomUser.DoesNotExist: + raise Exception("User not found") + + def get_client(self, request): + try: + return Client.objects.all().first() + except Client.DoesNotExist: + raise Exception("Client not found") + + def get_product(self, request): + try: + return Product.objects.first() + except Product.DoesNotExist: + raise Exception("Product not found") + + def get_factory(self, request): + try: + return Factory.objects.first() + except Factory.DoesNotExist: + raise Exception("Factory not found") + + def get_rw(self, request): + try: + return RailwayStation.objects.all().first() + except RailwayStation.DoesNotExist: + raise Exception("Railway station not found") + + def get_discount(self, request): + return 15 + + def get_city(self, request): + try: + return City.objects.all().first() + except City.DoesNotExist: + raise Exception("City not found") + + def get_logistics(self, request): + return 2500 + def form_auto_document(self, request): self.docname = "auto" try: - user = self.get_user(request) - client = self.get_client(request) + user = DataService.get_user(request) + client = DataService.get_client(self.validated_data) + + # Список товаров + # Надо сделать DataService.get_products(self.validated_data) + # Выдаст список товаров с количеством каждого товара и скидкой для товара product = self.get_product(request) - factory = self.get_factory(request) - logistics = self.get_logistics(request) + + factory = DataService.get_factory(self.validated_data) + + # logistics = delivery_cost(надо везде поменять) + logistics = DataService.get_delivery_cost(self.validated_data) + except Exception as e: return f"Error fetching data: {e}" @@ -224,57 +279,23 @@ def apply_styles(self, ws): if cell.value is not None: cell.font = Font(bold=True, size=12) - def get_user(self, request): - try: - return CustomUser.objects.first() - except CustomUser.DoesNotExist: - raise Exception("User not found") - - def get_client(self, request): - try: - return Client.objects.all().first() - except Client.DoesNotExist: - raise Exception("Client not found") - - def get_product(self, request): - try: - return Product.objects.first() - except Product.DoesNotExist: - raise Exception("Product not found") - - def get_factory(self, request): - try: - return Factory.objects.first() - except Factory.DoesNotExist: - raise Exception("Factory not found") - - def get_rw(self, request): + def form_rw_document(self, request): + self.docname = "rw" try: - return RailwayStation.objects.all().first() - except RailwayStation.DoesNotExist: - raise Exception("Railway station not found") + user = DataService.get_user(request) + client = DataService.get_client(self.validated_data) - def get_discount(self, request): - return 15 + # Список товаров + # Надо сделать DataService.get_products(self.validated_data) + # Выдаст список товаров с количеством каждого товара и скидкой для товара + product = self.get_product(request) - def get_city(self, request): - try: - return City.objects.all().first() - except City.DoesNotExist: - raise Exception("City not found") + rw = DataService.get_rw(self.validated_data) + factory = DataService.get_factory(self.validated_data) - def get_logistics(self, request): - return 2500 + # logistics = delivery_cost(надо везде поменять) + logistics = DataService.get_delivery_cost(self.validated_data) - def form_rw_document(self, request): - self.docname = "rw" - try: - user = self.get_user(request) - client = self.get_client(request) - product = self.get_product(request) - rw = self.get_rw(request) - factory = self.get_factory(request) - logistics = self.get_logistics(request) except Exception as e: return f"Error fetching data: {e}" From a7579363fb1c41c197bd02885958a7f694ad9578 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sun, 9 Jun 2024 23:07:10 +0200 Subject: [PATCH 10/17] Update docs schema, small fix goods package model, added simple serializer for CreateDocsView(fix docs error) --- docs/schema.json | 19 +++++++++++++++++++ goods/models.py | 2 +- makedoc/serializers.py | 4 ++++ makedoc/views.py | 3 ++- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/schema.json b/docs/schema.json index 4f17d75..b616a11 100644 --- a/docs/schema.json +++ b/docs/schema.json @@ -185,6 +185,16 @@ paths: schema: $ref: '#/components/schemas/DataDoc' description: '' + /api/v1/doc/filemake/: + get: + operationId: v1_doc_filemake_retrieve + tags: + - v1 + security: + - jwtAuth: [] + responses: + '200': + description: No response body /api/v1/goods/: get: operationId: v1_goods_list @@ -1385,6 +1395,9 @@ components: DataDoc: type: object properties: + delivery_type: + type: array + items: {} client_id: type: integer items: @@ -1395,8 +1408,13 @@ components: type: integer destination: type: string + delivery_cost: + type: integer + minimum: 0 required: - client_id + - delivery_cost + - delivery_type - destination - factory_id - items @@ -1551,6 +1569,7 @@ components: type: integer discount: type: integer + maximum: 100 default: 0 required: - product_id diff --git a/goods/models.py b/goods/models.py index 5dc0999..ba9d29d 100644 --- a/goods/models.py +++ b/goods/models.py @@ -59,4 +59,4 @@ class Meta: unique_together = [("package", "factory", "pallet_weight")] def __str__(self) -> str: - return f"{self.package} кг, {self.factory}" + return f"{self.package}" diff --git a/makedoc/serializers.py b/makedoc/serializers.py index 5a56dcd..4b8bcae 100644 --- a/makedoc/serializers.py +++ b/makedoc/serializers.py @@ -3,6 +3,10 @@ from rest_framework import serializers +class DocumentsSimpleSerializer(serializers.Serializer[Any]): + pass + + class OrderItemSerializer(serializers.Serializer[Any]): product_id = serializers.IntegerField() quantity = serializers.IntegerField() diff --git a/makedoc/views.py b/makedoc/views.py index 9377082..016b222 100644 --- a/makedoc/views.py +++ b/makedoc/views.py @@ -9,10 +9,11 @@ from rest_framework.views import APIView from makedoc.services import Documents -from .serializers import DataDocSerializer +from .serializers import DataDocSerializer, DocumentsSimpleSerializer class CreateDocsView(APIView): + serializer_class = DocumentsSimpleSerializer permission_classes = [IsAuthenticated] def get(self, request, *args, **kwargs): From f03c8999d93d4dfb62e3fbca7ece9bea239c4faf Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sun, 9 Jun 2024 23:09:49 +0200 Subject: [PATCH 11/17] make style --- makedoc/services.py | 3 +++ makedoc/views.py | 14 ++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/makedoc/services.py b/makedoc/services.py index 723a52c..daae526 100644 --- a/makedoc/services.py +++ b/makedoc/services.py @@ -54,6 +54,9 @@ def __init__(self, validated_data): self.transport_sheet = 0 def update_documents(self): + # Надо порешать же с service_note или transport_sheet что из них ждало скидку, + # потому что скидка идет с другого места и там уже все сделать красиво, + # взяв ее с моих данных delivery_type = DataService.get_delivery_type(self.validated_data) if delivery_type is None: raise Exception("Type delivery not found") diff --git a/makedoc/views.py b/makedoc/views.py index 016b222..bc75301 100644 --- a/makedoc/views.py +++ b/makedoc/views.py @@ -21,8 +21,9 @@ def get(self, request, *args, **kwargs): validated_data = cache.get(cache_key) if validated_data is None: - return Response({"error": "No data found in cache"}, - status=status.HTTP_400_BAD_REQUEST) + return Response( + {"error": "No data found in cache"}, status=status.HTTP_400_BAD_REQUEST + ) try: validated_data = json.loads(validated_data) @@ -40,8 +41,9 @@ def get(self, request, *args, **kwargs): if docs.transport_sheet: docs.form_transport_sheet(request) - return Response({"message": "Документы сохранены", "data": validated_data}, - status=status.HTTP_200_OK) + return Response( + {"message": "Документы сохранены", "data": validated_data}, status=status.HTTP_200_OK + ) class DataDocView(generics.GenericAPIView[Any]): @@ -53,7 +55,7 @@ def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) except ValidationError as e: - return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) validated_data = serializer.validated_data @@ -61,4 +63,4 @@ def post(self, request, *args, **kwargs): cache_key = f"validated_data_{request.user.id}" cache.set(cache_key, json.dumps(validated_data), 120) - return Response({'success': True, 'data': validated_data}, status=status.HTTP_200_OK) + return Response({"success": True, "data": validated_data}, status=status.HTTP_200_OK) From 078d47b1419c81dc4adea70e33bf8fe961b33198 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Mon, 10 Jun 2024 09:53:50 +0200 Subject: [PATCH 12/17] Fix goods, makedoc tests --- goods/tests/test_models_goods.py | 2 +- makedoc/tests/test_views_makedoc.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/goods/tests/test_models_goods.py b/goods/tests/test_models_goods.py index 094ffe9..c08f397 100644 --- a/goods/tests/test_models_goods.py +++ b/goods/tests/test_models_goods.py @@ -21,7 +21,7 @@ def test__brand__return_valid_str(brand_object): @pytest.mark.django_db def test__package__return_valid_str(package_object, factory_object): - assert str(package_object) == f"{package_object.package} кг, {factory_object.full_name}" + assert str(package_object) == f"{package_object.package}" @pytest.mark.django_db diff --git a/makedoc/tests/test_views_makedoc.py b/makedoc/tests/test_views_makedoc.py index 84118b7..ba7b131 100644 --- a/makedoc/tests/test_views_makedoc.py +++ b/makedoc/tests/test_views_makedoc.py @@ -4,10 +4,11 @@ @pytest.mark.django_db -def test__data_view__unauthorized_user_cannot_post_data() -> None: +def test__data_doc_view__unauthorized_user_cannot_post_data() -> None: client = APIClient() url = reverse("data") data = { + "delivery_type": ["auto", "rw"], "client_id": 1, "items": [ {"product_id": 1, "quantity": 2, "discount": 10}, @@ -15,16 +16,17 @@ def test__data_view__unauthorized_user_cannot_post_data() -> None: ], "factory_id": 1, "destination": "New York", - "delivery_cost": 2000, + "delivery_cost": 1500, } response = client.post(url, data, format="json") assert response.status_code == 401 # Unauthorized @pytest.mark.django_db -def test__goods__authorized_user_can_post_data(authorized_client) -> None: +def test__data_doc_view__authorized_user_can_post_data(authorized_client) -> None: url = reverse("data") data = { + "delivery_type": ["auto", "rw"], "client_id": 1, "items": [ {"product_id": 1, "quantity": 2, "discount": 10}, @@ -39,9 +41,10 @@ def test__goods__authorized_user_can_post_data(authorized_client) -> None: @pytest.mark.django_db -def test__goods__authorized_user_post_data_response_is_correct(authorized_client) -> None: +def test__data_doc_view__authorized_user_post_data_response_is_correct(authorized_client) -> None: url = reverse("data") data = { + "delivery_type": ["auto", "rw"], "client_id": 1, "items": [ {"product_id": 1, "quantity": 2, "discount": 10}, @@ -52,4 +55,4 @@ def test__goods__authorized_user_post_data_response_is_correct(authorized_client "delivery_cost": 1500, } response = authorized_client.post(url, data, format="json") - assert response.json() == data + assert response.json() == {"success": True, "data": data} From 0346d24a76eb7b1bd3c1ea38a13ab5f23b9addea Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Mon, 10 Jun 2024 18:14:17 +0200 Subject: [PATCH 13/17] Fix logistics, goods views, draft services --- goods/views.py | 4 +-- logistics/views.py | 4 +-- makedoc/data_service.py | 54 ++++++++++++++++++++++++++++++----------- makedoc/services.py | 21 ++++++++++++++++ 4 files changed, 65 insertions(+), 18 deletions(-) diff --git a/goods/views.py b/goods/views.py index 9e55029..2a52590 100644 --- a/goods/views.py +++ b/goods/views.py @@ -16,6 +16,6 @@ def get_queryset(self): if cached_goods: return cached_goods else: - goods = super().get_queryset() - cache.set("goods_list", goods, 60 * 15) + goods = list(super().get_queryset()) + cache.set("goods_list", goods, 1800) return goods diff --git a/logistics/views.py b/logistics/views.py index 4fb2298..aa5ba48 100644 --- a/logistics/views.py +++ b/logistics/views.py @@ -47,6 +47,6 @@ def get_queryset(self): if cached_factories: return cached_factories else: - factories = super().get_queryset() - cache.set("factories_list", factories, 60 * 30) + factories = list(super().get_queryset()) + cache.set("factories_list", factories, 3600) return factories diff --git a/makedoc/data_service.py b/makedoc/data_service.py index 549a010..042a620 100644 --- a/makedoc/data_service.py +++ b/makedoc/data_service.py @@ -1,3 +1,5 @@ +from django.core.cache import cache + from clients.models import Client from goods.models import Product from logistics.models import Factory, RailwayStation @@ -22,25 +24,49 @@ def get_client(validated_data): @staticmethod def get_products(validated_data): - try: - products_data = validated_data.get("items") - results = [] - for item in products_data: - product_id = item.get("product_id") - product_quantity = item.get("quantity") - product_discount = item.get("discount") - product = Product.objects.get(id=product_id) - results.append(product) - results.append(product_quantity) - results.append(product_discount) - return results - except Product.DoesNotExist: - raise Exception("Product not found") + products_data = validated_data.get("items") + results = [] + cached_goods = cache.get("goods_list") + if cached_goods is None: + try: + cached_goods = list(Product.objects.all()) + cache.set("goods_list", cached_goods, 1800) + except Exception: + cached_goods = list(Product.objects.all()) + for item in products_data: + product_id = item.get("product_id") + product_quantity = item.get("quantity") + product_discount = item.get("discount") + # Find prod in cache + for product in cached_goods: + if product.id == product_id: + results.append((product, product_quantity, product_discount)) + break + # if product.id == product_id: + # results.append(product) + # results.append(product_quantity) + # results.append(product_discount) + # break + + # for product in cached_goods: + # if product.id == product_id: + # results.append({ + # 'product': product, + # 'quantity': product_quantity, + # 'discount': product_discount + # }) + # break + return results @staticmethod def get_factory(validated_data): try: factory_id = validated_data.get("factory_id") + cached_factories = cache.get("factories_list") + if cached_factories: + for factory in cached_factories: + if factory.id == factory_id: + return factory factory = Factory.objects.get(id=factory_id) return factory except Factory.DoesNotExist: diff --git a/makedoc/services.py b/makedoc/services.py index daae526..5f1b1a5 100644 --- a/makedoc/services.py +++ b/makedoc/services.py @@ -121,6 +121,27 @@ def form_auto_document(self, request): # Надо сделать DataService.get_products(self.validated_data) # Выдаст список товаров с количеством каждого товара и скидкой для товара product = self.get_product(request) + # Сюда прилетят продукты если что, надо заменить у тебя + products = DataService.get_products(self.validated_data) + # print(products) + for produc in products: + print(produc) + # first_product = products[0]['product'] + # first_flour_name = first_product.flour_name + # first_brand = first_product.brand + # first_quantity = products[0]["quantity"] + # first_discount = products[0]["discount"] + # + # print(first_flour_name, first_brand, first_discount, first_quantity) + # + # # Доступ к полям второго товара + # second_product = products[1]['product'] + # second_flour_name = second_product.flour_name + # second_brand = second_product.brand + # second_quantity = products[1]["quantity"] + # second_discount = products[2]["discount"] + # + # print(second_flour_name, second_brand, second_discount, second_quantity) factory = DataService.get_factory(self.validated_data) From 2868b6ba0577664d77f4c76e035effeac3dfacbe Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Mon, 10 Jun 2024 18:15:58 +0200 Subject: [PATCH 14/17] Set Redis max-memory with allkeys-lru eviction policy --- docker-compose.yml | 3 +++ redis.conf | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 redis.conf diff --git a/docker-compose.yml b/docker-compose.yml index f879dc5..0017b2c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -52,6 +52,9 @@ services: hostname: redis ports: - "6379:6379" + volumes: + - ./redis.conf:/usr/local/etc/redis/redis.conf + command: redis-server /usr/local/etc/redis/redis.conf networks: - melnichanka diff --git a/redis.conf b/redis.conf new file mode 100644 index 0000000..b4e46fc --- /dev/null +++ b/redis.conf @@ -0,0 +1,2 @@ +maxmemory 256mb +maxmemory-policy allkeys-lru From 57abfe24d07d93bb190d093ac6b2c7d04575b6ca Mon Sep 17 00:00:00 2001 From: leeroymk Date: Sat, 15 Jun 2024 15:02:58 +0300 Subject: [PATCH 15/17] remake auto and rw documents --- .env.example | 7 +- makedoc/admin.py | 1 - makedoc/data_service.py | 37 ++----- makedoc/models.py | 1 - makedoc/serializers.py | 2 +- makedoc/services.py | 229 +++++++++++----------------------------- makedoc/utils.py | 32 ++++++ nginx.conf | 6 +- scripts/faker_script.py | 10 +- 9 files changed, 118 insertions(+), 207 deletions(-) delete mode 100644 makedoc/admin.py delete mode 100644 makedoc/models.py create mode 100644 makedoc/utils.py diff --git a/.env.example b/.env.example index d353375..e0bd092 100644 --- a/.env.example +++ b/.env.example @@ -16,12 +16,17 @@ DATABASE_PASSWORD = db_password DATABASE_HOST = db DATABASE_PORT = 5432 +# Redis + +REDIS_HOST = localhost +REDIS_PORT = 6379 + # Django secret key SECRET_KEY = django-insecure-your_secret_key # Mail secret key EMAIL_HOST = smtp.mail EMAIL_PORT = port.mail -EMAIL_USE_SSL = True EMAIL_HOST_USER = example@mail.com EMAIL_HOST_PASSWORD = email_password +EMAIL_USE_SSL = True diff --git a/makedoc/admin.py b/makedoc/admin.py deleted file mode 100644 index 846f6b4..0000000 --- a/makedoc/admin.py +++ /dev/null @@ -1 +0,0 @@ -# Register your models here. diff --git a/makedoc/data_service.py b/makedoc/data_service.py index 042a620..54ff035 100644 --- a/makedoc/data_service.py +++ b/makedoc/data_service.py @@ -2,7 +2,7 @@ from clients.models import Client from goods.models import Product -from logistics.models import Factory, RailwayStation +from logistics.models import Factory class DataService: @@ -10,7 +10,7 @@ class DataService: def get_delivery_type(validated_data): delivery_type = validated_data.get("delivery_type") if delivery_type is None: - raise Exception("Type delivery not found") + raise Exception("Delivery type not found") return delivery_type @staticmethod @@ -37,25 +37,17 @@ def get_products(validated_data): product_id = item.get("product_id") product_quantity = item.get("quantity") product_discount = item.get("discount") - # Find prod in cache for product in cached_goods: if product.id == product_id: - results.append((product, product_quantity, product_discount)) + results.append( + { + "product": product, + "quantity": product_quantity, + "discount": product_discount, + "price": product.price, + } + ) break - # if product.id == product_id: - # results.append(product) - # results.append(product_quantity) - # results.append(product_discount) - # break - - # for product in cached_goods: - # if product.id == product_id: - # results.append({ - # 'product': product, - # 'quantity': product_quantity, - # 'discount': product_discount - # }) - # break return results @staticmethod @@ -86,15 +78,6 @@ def get_city(validated_data): raise Exception("City not found") return city - @staticmethod - def get_rw(validated_data): - try: - rw_id = validated_data.get("destination") - rw = RailwayStation.objects.get(id=rw_id) - return rw - except RailwayStation.DoesNotExist: - raise Exception("Railway station not found") - @staticmethod def get_user(request): user = request.user diff --git a/makedoc/models.py b/makedoc/models.py deleted file mode 100644 index 6b20219..0000000 --- a/makedoc/models.py +++ /dev/null @@ -1 +0,0 @@ -# Create your models here. diff --git a/makedoc/serializers.py b/makedoc/serializers.py index 4b8bcae..51214fc 100644 --- a/makedoc/serializers.py +++ b/makedoc/serializers.py @@ -9,7 +9,7 @@ class DocumentsSimpleSerializer(serializers.Serializer[Any]): class OrderItemSerializer(serializers.Serializer[Any]): product_id = serializers.IntegerField() - quantity = serializers.IntegerField() + quantity = serializers.FloatField(min_value=0.001) discount = serializers.IntegerField(required=False, default=0, max_value=100) diff --git a/makedoc/services.py b/makedoc/services.py index 5f1b1a5..17a0d14 100644 --- a/makedoc/services.py +++ b/makedoc/services.py @@ -1,48 +1,12 @@ import os -from datetime import date, timedelta +from datetime import date -import babel.dates as bd import openpyxl -import pymorphy3 from openpyxl.styles import Alignment, Border, Font, Side -from clients.models import Client -from goods.models import Product -from logistics.models import City, RailwayStation, Factory -from users.models import CustomUser -from .data_service import DataService - -morph = pymorphy3.MorphAnalyzer() - - -def get_current_date(): - return date.today() - - -def format_date_case(date_object, case): - # case - падеж - return morph.parse(str(date_object))[0].inflect({case}).word - +from makedoc.utils import get_formatted_date_agreement, get_formatted_date_shipment -def format_month_ru_locale(date_object): - return bd.format_date(date_object, "MMMM", locale="ru_RU") - - -def get_formatted_date_agreement(): - return bd.format_date(get_current_date(), "«d» MMMM y г.", locale="ru_RU") - - -def get_formatted_date_shipment(case): - current_date = get_current_date() - next_month_date = (current_date.replace(day=1) + timedelta(days=31)).replace(day=1) - raw_current_month = format_month_ru_locale(current_date) - raw_next_month = format_month_ru_locale(next_month_date) - current_month = format_date_case(raw_current_month, case) - next_month = format_date_case(raw_next_month, case) - if current_date.year == next_month_date.year: - return f"{current_month}-{next_month} {current_date.year} г." - else: - return f"{current_month} {current_date.year} г.-{next_month} {next_month_date.year} г." +from .data_service import DataService class Documents: @@ -54,12 +18,7 @@ def __init__(self, validated_data): self.transport_sheet = 0 def update_documents(self): - # Надо порешать же с service_note или transport_sheet что из них ждало скидку, - # потому что скидка идет с другого места и там уже все сделать красиво, - # взяв ее с моих данных delivery_type = DataService.get_delivery_type(self.validated_data) - if delivery_type is None: - raise Exception("Type delivery not found") if "auto" in delivery_type: self.auto = 1 if "rw" in delivery_type: @@ -69,85 +28,14 @@ def update_documents(self): if "transport_sheet" in delivery_type: self.transport_sheet = 1 - def get_user(self, request): - try: - return CustomUser.objects.first() - except CustomUser.DoesNotExist: - raise Exception("User not found") - - def get_client(self, request): - try: - return Client.objects.all().first() - except Client.DoesNotExist: - raise Exception("Client not found") - - def get_product(self, request): - try: - return Product.objects.first() - except Product.DoesNotExist: - raise Exception("Product not found") - - def get_factory(self, request): - try: - return Factory.objects.first() - except Factory.DoesNotExist: - raise Exception("Factory not found") - - def get_rw(self, request): - try: - return RailwayStation.objects.all().first() - except RailwayStation.DoesNotExist: - raise Exception("Railway station not found") - - def get_discount(self, request): - return 15 - - def get_city(self, request): - try: - return City.objects.all().first() - except City.DoesNotExist: - raise Exception("City not found") - - def get_logistics(self, request): - return 2500 - def form_auto_document(self, request): self.docname = "auto" try: user = DataService.get_user(request) client = DataService.get_client(self.validated_data) - - # Список товаров - # Надо сделать DataService.get_products(self.validated_data) - # Выдаст список товаров с количеством каждого товара и скидкой для товара - product = self.get_product(request) - # Сюда прилетят продукты если что, надо заменить у тебя products = DataService.get_products(self.validated_data) - # print(products) - for produc in products: - print(produc) - # first_product = products[0]['product'] - # first_flour_name = first_product.flour_name - # first_brand = first_product.brand - # first_quantity = products[0]["quantity"] - # first_discount = products[0]["discount"] - # - # print(first_flour_name, first_brand, first_discount, first_quantity) - # - # # Доступ к полям второго товара - # second_product = products[1]['product'] - # second_flour_name = second_product.flour_name - # second_brand = second_product.brand - # second_quantity = products[1]["quantity"] - # second_discount = products[2]["discount"] - # - # print(second_flour_name, second_brand, second_discount, second_quantity) - factory = DataService.get_factory(self.validated_data) - - # logistics = delivery_cost(надо везде поменять) logistics = DataService.get_delivery_cost(self.validated_data) - except Exception as e: return f"Error fetching data: {e}" @@ -156,7 +44,7 @@ def form_auto_document(self, request): ws = wb.active self.fill_contract_info(ws, client) - self.fill_product_info(ws, product, logistics, 10) + self.fill_product_info(ws, products, logistics, 10) self.fill_factory_info(ws, factory) self.fill_auto_services(ws, logistics) self.fill_debt_info(ws) @@ -166,7 +54,7 @@ def form_auto_document(self, request): self.apply_styles(ws) - self.save_workbook(wb, user) + self.save_workbook(wb, user, client) def fill_contract_info(self, ws, client): formatted_contract_date = client.contract_date.strftime("%d.%m.%Y") @@ -180,8 +68,8 @@ def fill_contract_info(self, ws, client): ws.cell(row=4, column=1, value=client.client_name) ws.cell(row=6, column=6, value=get_formatted_date_agreement()) - def fill_product_info(self, ws, product, logistics, caret): - goods_quantity = 7 + def fill_product_info(self, ws, products, logistics, caret): + goods_quantity = len(products) thin_border = Border( left=Side(style="thin"), right=Side(style="thin"), @@ -189,16 +77,31 @@ def fill_product_info(self, ws, product, logistics, caret): bottom=Side(style="thin"), ) - for _ in range(goods_quantity): + for i in range(goods_quantity): ws.merge_cells(start_row=caret, start_column=1, end_row=caret, end_column=3) - ws.cell(row=caret, column=1, value=f"{str(product.flour_name)} {product.brand}") - ws.cell(row=caret, column=4, value=product.package.package) - ws.cell(row=caret, column=5, value=20) - ws.cell(row=caret, column=6, value=str(product.price)) - ws.cell(row=caret, column=7, value=logistics) - ws.cell(row=caret, column=8, value=product.price - logistics) - - for col_num in range(1, 9): + # Название продукта + product = f"{products[i]['product'].flour_name.flour_name}, \ +т/м {products[i]['product'].brand.brand}" + ws.cell(row=caret, column=1, value=product) + # Упаковка + package = products[i]["product"].package.package + ws.cell(row=caret, column=4, value=package) + # Количество товара по заказу + ws.cell(row=caret, column=5, value=products[i]["quantity"]) + # Цена за товар + price = products[i]["price"] * (100 - products[i]["discount"]) / 100 + ws.cell(row=caret, column=6, value=price) + if logistics: + # Стоимость доставки + ws.cell(row=caret, column=7, value=logistics) + # Цена на самовывозе + ws.cell(row=caret, column=8, value=price - logistics) + + table_width = range(1, 9) + if not logistics: + table_width = range(1, 7) + + for col_num in table_width: cell = ws.cell(row=caret, column=col_num) cell.border = thin_border if cell.column > 2: @@ -220,9 +123,7 @@ def fill_auto_services(self, ws, logistics): ws.cell( row=caret, column=3, - value="не входят в стоимость товара" - if logistics != 0 - else "входят в стоимость товара", + value="не входят в стоимость товара" if not logistics else "входят в стоимость товара", ) self.caret_services = caret + 1 @@ -277,18 +178,17 @@ def fill_manager_contact(self, ws, user): ) phone.alignment = Alignment(horizontal="center", vertical="center") - def save_workbook(self, wb, user): + def save_workbook(self, wb, user, client): directory = os.path.join( "makedoc", "tempdoc", - get_current_date().strftime("%d.%m.%Y"), - user.full_name.split()[0], + user.full_name, ) os.makedirs(directory, exist_ok=True) new_file_path = os.path.join( directory, - f"{self.docname}_{user.full_name.split()[0]}_\ -{get_current_date().strftime('%d.%m.%Y')}.xlsx", + f"{self.docname} {client.last_application_number} {client.client_name} \ +{date.today().strftime('%d.%m.%Y')}.xlsx", ) wb.save(new_file_path) @@ -308,16 +208,8 @@ def form_rw_document(self, request): try: user = DataService.get_user(request) client = DataService.get_client(self.validated_data) - - # Список товаров - # Надо сделать DataService.get_products(self.validated_data) - # Выдаст список товаров с количеством каждого товара и скидкой для товара - product = self.get_product(request) - - rw = DataService.get_rw(self.validated_data) + product = DataService.get_products(self.validated_data) factory = DataService.get_factory(self.validated_data) - - # logistics = delivery_cost(надо везде поменять) logistics = DataService.get_delivery_cost(self.validated_data) except Exception as e: @@ -330,7 +222,7 @@ def form_rw_document(self, request): self.fill_contract_info(ws, client) self.fill_product_info(ws, product, logistics, 10) self.fill_factory_info(ws, factory) - self.fill_rw_services(ws, rw, factory, client, logistics) + self.fill_rw_services(ws, factory, client, logistics) self.fill_debt_info(ws) self.fill_legal_info(ws, client) self.fill_signatures(ws, client) @@ -338,9 +230,9 @@ def form_rw_document(self, request): self.apply_styles(ws) - self.save_workbook(wb, user) + self.save_workbook(wb, user, client) - def fill_rw_services(self, ws, rw, factory, client, logistics): + def fill_rw_services(self, ws, factory, client, logistics): caret = self.caret_factory ws.merge_cells(start_row=caret, start_column=1, end_row=caret, end_column=2) ws.cell(row=caret, column=1, value="Поставка осуществляется:") @@ -348,20 +240,17 @@ def fill_rw_services(self, ws, rw, factory, client, logistics): caret += 1 ws.cell(row=caret, column=1, value="Станция отправления:") - ws.cell(row=caret, column=3, value=rw.station_name) + shipping_station = f"{factory.departure_station_name}, {factory.departure_station_branch}" + ws.cell(row=caret, column=3, value=shipping_station) caret += 1 - ws.cell(row=caret, column=1, value="Грузоотправитель:") - ws.cell(row=caret, column=3, value=factory.full_name) - caret += 1 - - ws.cell(row=caret, column=1, value="Условия поставки") + ws.cell(row=caret, column=1, value="Условия поставки:") ws.cell( row=caret, column=3, - value="не входят в стоимость товара" - if logistics != 0 - else "входят в стоимость товара", + value="франко-вагон станция отправления" + if not logistics + else "франко-вагон станция назначения", ) caret += 2 @@ -369,7 +258,10 @@ def fill_rw_services(self, ws, rw, factory, client, logistics): caret += 1 ws.cell(row=caret, column=1, value="Станция назначения:") - ws.cell(row=caret, column=3, value=client.railway_station.station_name) + destination_station = ( + f"{client.railway_station.station_name}, {client.railway_station.station_branch}" + ) + ws.cell(row=caret, column=3, value=destination_station) caret += 1 ws.cell(row=caret, column=1, value="Код станции:") @@ -395,17 +287,22 @@ def fill_rw_services(self, ws, rw, factory, client, logistics): ws.cell(row=caret, column=3, value=client.receiver_adress) caret += 1 + ws.cell(row=caret, column=1, value="Особые отметки:") + ws.cell(row=caret, column=3, value=client.special_marks) + caret += 1 + self.caret_services = caret + 1 def form_service_note(self, request): self.docname = "service_note" try: - client = self.get_client(request) - discount = self.get_discount(request) - city = self.get_city(request) - user = self.get_user(request) - product = self.get_product(request) - logistics = self.get_logistics(request) + client = DataService.get_client(self.validated_data) + city = DataService.get_city(self.validated_data) + user = DataService.get_user(request) + product = DataService.get_products(self.validated_data) + discount = max(product, key=lambda x: x["discount"])["discount"] + + logistics = DataService.get_delivery_cost(self.validated_data) except Exception as e: return f"Error fetching data: {e}" @@ -418,7 +315,7 @@ def form_service_note(self, request): self.fill_product_info(ws, product, logistics, 22) self.apply_styles(ws) - self.save_workbook(wb, user) + self.save_workbook(wb, user, client) def fill_text_note(self, ws, client, discount, city): ws.cell(row=15, column=1, value=f"{get_formatted_date_agreement()} № 12/2.2/23/3-") @@ -454,7 +351,7 @@ def form_transport_sheet(self, request): self.apply_styles(ws) - self.save_workbook(wb, user) + self.save_workbook(wb, user, client) def fill_contract_info_transport_sheet(self, ws, client): formatted_contract_date = client.contract_date.strftime("%d.%m.%Y") diff --git a/makedoc/utils.py b/makedoc/utils.py new file mode 100644 index 0000000..058c5e5 --- /dev/null +++ b/makedoc/utils.py @@ -0,0 +1,32 @@ +from datetime import date, timedelta + +import babel.dates as bd +import pymorphy3 + +morph = pymorphy3.MorphAnalyzer() + + +def format_date_case(date_object, case): + # case - падеж + return morph.parse(str(date_object))[0].inflect({case}).word + + +def format_month_ru_locale(date_object): + return bd.format_date(date_object, "MMMM", locale="ru_RU") + + +def get_formatted_date_agreement(): + return bd.format_date(date.today(), "«d» MMMM y г.", locale="ru_RU") + + +def get_formatted_date_shipment(case): + current_date = date.today() + next_month_date = (current_date.replace(day=1) + timedelta(days=31)).replace(day=1) + raw_current_month = format_month_ru_locale(current_date) + raw_next_month = format_month_ru_locale(next_month_date) + current_month = format_date_case(raw_current_month, case) + next_month = format_date_case(raw_next_month, case) + if current_date.year == next_month_date.year: + return f"{current_month}-{next_month} {current_date.year} г." + else: + return f"{current_month} {current_date.year} г.-{next_month} {next_month_date.year} г." diff --git a/nginx.conf b/nginx.conf index 3570b78..05f1ac6 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,10 +1,10 @@ server { - listen 443 ssl; + # listen 443 ssl; listen 80; - ssl_certificate /etc/nginx/ssl/nginx-selfsigned.crt; - ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key; + # ssl_certificate /etc/nginx/ssl/nginx-selfsigned.crt; + # ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key; location / { root /usr/share/nginx/html; diff --git a/scripts/faker_script.py b/scripts/faker_script.py index 780fff5..f573039 100644 --- a/scripts/faker_script.py +++ b/scripts/faker_script.py @@ -4,7 +4,7 @@ from clients.models import Client, DirectorPosition from goods.models import Brand, Flour, Package, Product -from logistics.models import City, RailwayStation, TripAuto, TripRailway, Factory +from logistics.models import City, Factory, RailwayStation, TripAuto, TripRailway from users.models import CustomUser, Department, Position fake = Faker("ru_RU") @@ -142,18 +142,14 @@ def create_client(n): # Создаем сорта муки из заданного списка def create_flour(): - flour_names = ["Пшеничная", "Ржаная", "Овсяная"] + flour_names = ["Пшеничная", "Ржаная", "Овсяная", "Сахарная", "Пятая"] for flour_name in flour_names: Flour.objects.create(flour_name=flour_name) # Создаем бренды муки из заданного списка def create_brand(): - brands = [ - "Бело-Нежная", - "Славна", - "Старооскольская", - ] + brands = ["Бело-Нежная", "Славна", "Старооскольская", "Четвертая", "Пятая", "Макфа"] for brand in brands: Brand.objects.create(brand=brand) From 413c1287f6126bc58ffcf941591d4c903c0e7930 Mon Sep 17 00:00:00 2001 From: leeroymk Date: Sat, 15 Jun 2024 16:49:55 +0300 Subject: [PATCH 16/17] remake transport sheet, service note --- makedoc/data_service.py | 8 ++++---- makedoc/serializers.py | 2 +- makedoc/services.py | 42 ++++++++++++++++++++++++----------------- makedoc/views.py | 1 + 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/makedoc/data_service.py b/makedoc/data_service.py index 54ff035..a1b0f15 100644 --- a/makedoc/data_service.py +++ b/makedoc/data_service.py @@ -72,11 +72,11 @@ def get_delivery_cost(validated_data): return delivery_cost @staticmethod - def get_city(validated_data): - city = validated_data.get("destination") - if city is None: + def get_destination(validated_data): + destination = validated_data.get("destination") + if destination is None: raise Exception("City not found") - return city + return destination @staticmethod def get_user(request): diff --git a/makedoc/serializers.py b/makedoc/serializers.py index 51214fc..1db4ffd 100644 --- a/makedoc/serializers.py +++ b/makedoc/serializers.py @@ -14,7 +14,7 @@ class OrderItemSerializer(serializers.Serializer[Any]): class DataDocSerializer(serializers.Serializer[Any]): - delivery_type = serializers.ListField() + delivery_type = serializers.CharField() client_id = serializers.IntegerField() items = serializers.ListField(child=OrderItemSerializer()) factory_id = serializers.IntegerField() diff --git a/makedoc/services.py b/makedoc/services.py index 17a0d14..38164d0 100644 --- a/makedoc/services.py +++ b/makedoc/services.py @@ -4,7 +4,10 @@ import openpyxl from openpyxl.styles import Alignment, Border, Font, Side -from makedoc.utils import get_formatted_date_agreement, get_formatted_date_shipment +from makedoc.utils import ( + get_formatted_date_agreement, + get_formatted_date_shipment, +) from .data_service import DataService @@ -19,15 +22,17 @@ def __init__(self, validated_data): def update_documents(self): delivery_type = DataService.get_delivery_type(self.validated_data) - if "auto" in delivery_type: + if delivery_type == "auto": self.auto = 1 - if "rw" in delivery_type: + else: self.rw = 1 - if "service_note" in delivery_type: - self.service_note = 1 - if "transport_sheet" in delivery_type: + + if self.validated_data["delivery_cost"] > 0: self.transport_sheet = 1 + if max(self.validated_data.get("items"), key=lambda x: x["discount"])["discount"] > 0: + self.service_note = 1 + def form_auto_document(self, request): self.docname = "auto" try: @@ -150,7 +155,7 @@ def fill_legal_info(self, ws, client): {formatted_contract_date}г." legal = ws.cell(row=caret, column=1, value=contract_option) legal.alignment = Alignment(wrap_text=True, horizontal="justify", vertical="center") - ws.row_dimensions[caret].height = 40 + ws.row_dimensions[caret].height = 50 self.caret_legal = caret + 4 def fill_signatures(self, ws, client): @@ -297,7 +302,7 @@ def form_service_note(self, request): self.docname = "service_note" try: client = DataService.get_client(self.validated_data) - city = DataService.get_city(self.validated_data) + destination = DataService.get_destination(self.validated_data) user = DataService.get_user(request) product = DataService.get_products(self.validated_data) discount = max(product, key=lambda x: x["discount"])["discount"] @@ -311,27 +316,30 @@ def form_service_note(self, request): wb = openpyxl.load_workbook(template_path, keep_vba=True) ws = wb.active - self.fill_text_note(ws, client, discount, city) + self.fill_text_note(ws, client, discount, destination) self.fill_product_info(ws, product, logistics, 22) self.apply_styles(ws) self.save_workbook(wb, user, client) - def fill_text_note(self, ws, client, discount, city): + def fill_text_note(self, ws, client, discount, destination): + region = destination.split(",")[1].strip() ws.cell(row=15, column=1, value=f"{get_formatted_date_agreement()} № 12/2.2/23/3-") - text = f" В целях увеличения объема продаж на территории {city.region} прошу Вашего \ -согласования применить скидку для контрагента {client.client_name} (г. {city.city}) до {discount}%\ + # Нужно правильлно разобрать в json регион чтобы склонять только название + text = f" В целях увеличения объема продаж на территории {region} прошу Вашего \ +согласования применить скидку для контрагента {client.client_name} ({destination}) до {discount}%\ в {get_formatted_date_shipment('loct')} на продукцию следующего ассортимента: " ws.cell(row=19, column=1, value=text) def form_transport_sheet(self, request): self.docname = "transport_sheet" try: - user = self.get_user(request) - product = self.get_product(request) - client = self.get_client(request) - logistics = self.get_logistics(request) - factory = self.get_factory(request) + user = DataService.get_user(request) + product = DataService.get_products(self.validated_data) + client = DataService.get_client(self.validated_data) + logistics = DataService.get_delivery_cost(self.validated_data) + factory = DataService.get_factory(self.validated_data) + except Exception as e: return f"Error fetching data: {e}" diff --git a/makedoc/views.py b/makedoc/views.py index bc75301..f1d83b0 100644 --- a/makedoc/views.py +++ b/makedoc/views.py @@ -9,6 +9,7 @@ from rest_framework.views import APIView from makedoc.services import Documents + from .serializers import DataDocSerializer, DocumentsSimpleSerializer From b2ca1c9dc460d9ebc12f1d6ddb2ae9f0ecd6add0 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 15 Jun 2024 18:27:57 +0200 Subject: [PATCH 17/17] Fix makedoc views tests, delete comment in nginx.conf --- makedoc/tests/test_views_makedoc.py | 4 ++-- nginx.conf | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/makedoc/tests/test_views_makedoc.py b/makedoc/tests/test_views_makedoc.py index ba7b131..91bc203 100644 --- a/makedoc/tests/test_views_makedoc.py +++ b/makedoc/tests/test_views_makedoc.py @@ -26,7 +26,7 @@ def test__data_doc_view__unauthorized_user_cannot_post_data() -> None: def test__data_doc_view__authorized_user_can_post_data(authorized_client) -> None: url = reverse("data") data = { - "delivery_type": ["auto", "rw"], + "delivery_type": "auto", "client_id": 1, "items": [ {"product_id": 1, "quantity": 2, "discount": 10}, @@ -44,7 +44,7 @@ def test__data_doc_view__authorized_user_can_post_data(authorized_client) -> Non def test__data_doc_view__authorized_user_post_data_response_is_correct(authorized_client) -> None: url = reverse("data") data = { - "delivery_type": ["auto", "rw"], + "delivery_type": "auto", "client_id": 1, "items": [ {"product_id": 1, "quantity": 2, "discount": 10}, diff --git a/nginx.conf b/nginx.conf index 05f1ac6..ee9f46b 100644 --- a/nginx.conf +++ b/nginx.conf @@ -3,8 +3,8 @@ server { # listen 443 ssl; listen 80; - # ssl_certificate /etc/nginx/ssl/nginx-selfsigned.crt; - # ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key; + ssl_certificate /etc/nginx/ssl/nginx-selfsigned.crt; + ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key; location / { root /usr/share/nginx/html;