From bbed23e06870a91e3aa6618f7d53cfd4af7b44d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BB=D0=B5=D1=80?= <101361201+DarkSteelD@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:28:15 +0300 Subject: [PATCH 1/2] Postman Tests and upload --- hq/__init__.py | 0 hq/admin.py | 10 + hq/apps.py | 6 + hq/migrations/0001_initial.py | 67 +++++++ hq/migrations/__init__.py | 0 hq/models.py | 38 ++++ hq/serializers.py | 29 +++ hq/tests.py | 0 hq/urls.py | 9 + hq/views.py | 37 ++++ logs.log | 220 ++++++++++++++++++++++ settings/__pycache__/base.cpython-310.pyc | Bin 1870 -> 1874 bytes settings/base.py | 1 + urls.py | 1 + 14 files changed, 418 insertions(+) create mode 100644 hq/__init__.py create mode 100644 hq/admin.py create mode 100644 hq/apps.py create mode 100644 hq/migrations/0001_initial.py create mode 100644 hq/migrations/__init__.py create mode 100644 hq/models.py create mode 100644 hq/serializers.py create mode 100644 hq/tests.py create mode 100644 hq/urls.py create mode 100644 hq/views.py diff --git a/hq/__init__.py b/hq/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hq/admin.py b/hq/admin.py new file mode 100644 index 0000000..c8e7f2b --- /dev/null +++ b/hq/admin.py @@ -0,0 +1,10 @@ +from django.contrib import admin +from .models import Product, Employee, Contractor, ContractorContact + +@admin.register(Product) +class ProductAdmin(admin.ModelAdmin): + list_display = ('name', 'manufacturer', 'shelf_life', 'barcode') + +@admin.register(Employee) +class EmployeeAdmin(admin.ModelAdmin): + list_display = ('full_name', 'position', 'login', 'work_phone') diff --git a/hq/apps.py b/hq/apps.py new file mode 100644 index 0000000..74c86b7 --- /dev/null +++ b/hq/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class HQConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'hq' diff --git a/hq/migrations/0001_initial.py b/hq/migrations/0001_initial.py new file mode 100644 index 0000000..605f867 --- /dev/null +++ b/hq/migrations/0001_initial.py @@ -0,0 +1,67 @@ +# Generated by Django 5.1.4 on 2025-01-09 09:26 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Contractor', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('contract_number', models.CharField(max_length=100)), + ('address', models.TextField()), + ], + ), + migrations.CreateModel( + name='Employee', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('full_name', models.CharField(max_length=255)), + ('passport_series', models.CharField(max_length=10)), + ('passport_number', models.CharField(max_length=10)), + ('birth_date', models.DateField()), + ('position', models.CharField(max_length=255)), + ('department', models.CharField(max_length=255)), + ('login', models.CharField(max_length=100, unique=True)), + ('password', models.CharField(max_length=100)), + ('role', models.CharField(max_length=100)), + ('work_phone', models.CharField(max_length=20)), + ('personal_phone', models.CharField(blank=True, max_length=20, null=True)), + ('email', models.EmailField(max_length=254)), + ], + ), + migrations.CreateModel( + name='Product', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('manufacturer', models.CharField(max_length=255)), + ('manufacturer_country', models.CharField(max_length=255)), + ('manufacturer_code', models.CharField(max_length=50)), + ('dimensions', models.CharField(blank=True, max_length=255, null=True)), + ('unit', models.CharField(max_length=50)), + ('shelf_life', models.IntegerField()), + ('barcode', models.CharField(max_length=50)), + ('additional_info', models.TextField(blank=True, null=True)), + ], + ), + migrations.CreateModel( + name='ContractorContact', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('full_name', models.CharField(max_length=255)), + ('phone', models.CharField(max_length=20)), + ('email', models.EmailField(max_length=254)), + ('contractor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contacts', to='hq.contractor')), + ], + ), + ] diff --git a/hq/migrations/__init__.py b/hq/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hq/models.py b/hq/models.py new file mode 100644 index 0000000..0189d05 --- /dev/null +++ b/hq/models.py @@ -0,0 +1,38 @@ +from django.db import models + +class Product(models.Model): + name = models.CharField(max_length=255) + manufacturer = models.CharField(max_length=255) + manufacturer_country = models.CharField(max_length=255) + manufacturer_code = models.CharField(max_length=50) + dimensions = models.CharField(max_length=255, null=True, blank=True) + unit = models.CharField(max_length=50) + shelf_life = models.IntegerField() # Срок годности в днях + barcode = models.CharField(max_length=50) + additional_info = models.TextField(null=True, blank=True) + +class Employee(models.Model): + full_name = models.CharField(max_length=255) + passport_series = models.CharField(max_length=10) + passport_number = models.CharField(max_length=10) + birth_date = models.DateField() + position = models.CharField(max_length=255) + department = models.CharField(max_length=255) + login = models.CharField(max_length=100, unique=True) + password = models.CharField(max_length=100) + role = models.CharField(max_length=100) + work_phone = models.CharField(max_length=20) + personal_phone = models.CharField(max_length=20, null=True, blank=True) + email = models.EmailField() + +# Пример дополнительных моделей +class Contractor(models.Model): + name = models.CharField(max_length=255) + contract_number = models.CharField(max_length=100) + address = models.TextField() + +class ContractorContact(models.Model): + contractor = models.ForeignKey(Contractor, on_delete=models.CASCADE, related_name="contacts") + full_name = models.CharField(max_length=255) + phone = models.CharField(max_length=20) + email = models.EmailField() diff --git a/hq/serializers.py b/hq/serializers.py new file mode 100644 index 0000000..62cdd3e --- /dev/null +++ b/hq/serializers.py @@ -0,0 +1,29 @@ +from rest_framework import serializers +from .models import Product, Employee, Contractor, ContractorContact + +class ProductSerializer(serializers.ModelSerializer): + class Meta: + model = Product + fields = [ + 'id', 'name', 'manufacturer', 'manufacturer_country', 'manufacturer_code', + 'dimensions', 'unit', 'shelf_life', 'barcode', 'additional_info' + ] + +class EmployeeSerializer(serializers.ModelSerializer): + class Meta: + model = Employee + fields = [ + 'id', 'full_name', 'passport_series', 'passport_number', 'birth_date', + 'position', 'department', 'login', 'password', 'role', 'work_phone', + 'personal_phone', 'email' + ] + +class ContractorSerializer(serializers.ModelSerializer): + class Meta: + model = Contractor + fields = ['id', 'name', 'contract_number', 'address'] + +class ContractorContactSerializer(serializers.ModelSerializer): + class Meta: + model = ContractorContact + fields = ['id', 'contractor', 'full_name', 'phone', 'email'] diff --git a/hq/tests.py b/hq/tests.py new file mode 100644 index 0000000..e69de29 diff --git a/hq/urls.py b/hq/urls.py new file mode 100644 index 0000000..184290f --- /dev/null +++ b/hq/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from .views import ProductUploadView, EmployeeUploadView, ContractorUploadView, ContractorContactUploadView + +urlpatterns = [ + path('api/products/upload/', ProductUploadView.as_view(), name='product-upload'), + path('api/employees/upload/', EmployeeUploadView.as_view(), name='employee-upload'), + path('api/contractors/upload/', ContractorUploadView.as_view(), name='contractor-upload'), + path('api/contractor-contacts/upload/', ContractorContactUploadView.as_view(), name='contractor-contact-upload'), +] diff --git a/hq/views.py b/hq/views.py new file mode 100644 index 0000000..85d88af --- /dev/null +++ b/hq/views.py @@ -0,0 +1,37 @@ +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status +from .models import Product, Employee, Contractor, ContractorContact +from .serializers import ProductSerializer, EmployeeSerializer, ContractorSerializer, ContractorContactSerializer + +class ProductUploadView(APIView): + def post(self, request, *args, **kwargs): + serializer = ProductSerializer(data=request.data, many=True) + if serializer.is_valid(): + serializer.save() + return Response({"message": "Products uploaded successfully"}, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class EmployeeUploadView(APIView): + def post(self, request, *args, **kwargs): + serializer = EmployeeSerializer(data=request.data, many=True) + if serializer.is_valid(): + serializer.save() + return Response({"message": "Employees uploaded successfully"}, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class ContractorUploadView(APIView): + def post(self, request, *args, **kwargs): + serializer = ContractorSerializer(data=request.data, many=True) + if serializer.is_valid(): + serializer.save() + return Response({"message": "Contractors uploaded successfully"}, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class ContractorContactUploadView(APIView): + def post(self, request, *args, **kwargs): + serializer = ContractorContactSerializer(data=request.data, many=True) + if serializer.is_valid(): + serializer.save() + return Response({"message": "Contractor contacts uploaded successfully"}, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) diff --git a/logs.log b/logs.log index 11ff944..154246d 100644 --- a/logs.log +++ b/logs.log @@ -186,3 +186,223 @@ Not Found: /favicon.ico "GET /static/drf-yasg/immutable.min.js HTTP/1.1" 304 0 "GET /static/drf-yasg/swagger-ui-dist/swagger-ui.css HTTP/1.1" 200 145206 "GET /api/hr/swagger/?format=openapi HTTP/1.1" 200 54931 +Watching for file changes with StatReloader +Not Found: / +"GET / HTTP/1.1" 404 2932 +/home/dark/Documents/GitHub/store-management-system/urls.py changed, reloading. +Watching for file changes with StatReloader +Watching for file changes with StatReloader +/home/dark/Documents/GitHub/store-management-system/settings/base.py changed, reloading. +Watching for file changes with StatReloader +Watching for file changes with StatReloader +Not Found: / +"GET / HTTP/1.1" 404 3082 +Not Found: /api/hq/ +"GET /api/hq/ HTTP/1.1" 404 4133 +Method Not Allowed: /api/hq/api/products/upload/ +"GET /api/hq/api/products/upload/ HTTP/1.1" 405 10569 +"GET /static/rest_framework/css/bootstrap.min.css HTTP/1.1" 304 0 +"GET /static/rest_framework/css/bootstrap-tweaks.css HTTP/1.1" 304 0 +"GET /static/rest_framework/css/default.css HTTP/1.1" 304 0 +"GET /static/rest_framework/css/prettify.css HTTP/1.1" 304 0 +"GET /static/rest_framework/js/csrf.js HTTP/1.1" 304 0 +"GET /static/rest_framework/js/prettify-min.js HTTP/1.1" 304 0 +"GET /static/rest_framework/js/jquery-3.7.1.min.js HTTP/1.1" 304 0 +"GET /static/rest_framework/js/bootstrap.min.js HTTP/1.1" 304 0 +"GET /static/rest_framework/js/ajax-form.js HTTP/1.1" 304 0 +"GET /static/rest_framework/js/default.js HTTP/1.1" 304 0 +"GET /static/rest_framework/js/load-ajax-form.js HTTP/1.1" 304 0 +"GET /static/rest_framework/img/grid.png HTTP/1.1" 200 1458 +Not Found: /api/products/upload +"POST /api/products/upload HTTP/1.1" 404 3158 +Not Found: /api/products/upload +"POST /api/products/upload HTTP/1.1" 404 3158 +Not Found: /api/products/upload +"POST /api/products/upload HTTP/1.1" 404 3158 +Not Found: /api/products/upload +"POST /api/products/upload HTTP/1.1" 404 3158 +"GET /api/hr/swagger/?format=openapi HTTP/1.1" 200 55769 +Not Found: / +"GET / HTTP/1.1" 404 3082 +Not Found: /api/hq/ +"GET /api/hq/ HTTP/1.1" 404 4133 +Not Found: /api/hq/ api/products/upload/ +"GET /api/hq/%20api/products/upload/ HTTP/1.1" 404 4198 +Method Not Allowed: /api/hq/api/products/upload/ +"GET /api/hq/api/products/upload/ HTTP/1.1" 405 10569 +Internal Server Error: /api/hq/api/products/upload/ +Traceback (most recent call last): + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 105, in _execute + return self.cursor.execute(sql, params) +psycopg2.errors.UndefinedTable: relation "hq_product" does not exist +LINE 1: INSERT INTO "hq_product" ("name", "manufacturer", "manufactu... + ^ + + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 65, in _view_wrapper + return view_func(request, *args, **kwargs) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/views/generic/base.py", line 104, in view + return self.dispatch(request, *args, **kwargs) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/views.py", line 509, in dispatch + response = self.handle_exception(exc) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/views.py", line 469, in handle_exception + self.raise_uncaught_exception(exc) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception + raise exc + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch + response = handler(request, *args, **kwargs) + File "/home/dark/Documents/GitHub/store-management-system/hq/views.py", line 11, in post + serializer.save() + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/serializers.py", line 758, in save + self.instance = self.create(validated_data) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/serializers.py", line 730, in create + return [ + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/serializers.py", line 731, in + self.child.create(attrs) for attrs in validated_data + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/serializers.py", line 989, in create + instance = ModelClass._default_manager.create(**validated_data) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/manager.py", line 87, in manager_method + return getattr(self.get_queryset(), name)(*args, **kwargs) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/query.py", line 679, in create + obj.save(force_insert=True, using=self.db) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/base.py", line 892, in save + self.save_base( + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/base.py", line 998, in save_base + updated = self._save_table( + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/base.py", line 1161, in _save_table + results = self._do_insert( + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/base.py", line 1202, in _do_insert + return manager._insert( + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/manager.py", line 87, in manager_method + return getattr(self.get_queryset(), name)(*args, **kwargs) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/query.py", line 1847, in _insert + return query.get_compiler(using=using).execute_sql(returning_fields) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1836, in execute_sql + cursor.execute(sql, params) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 122, in execute + return super().execute(sql, params) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 79, in execute + return self._execute_with_wrappers( + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers + return executor(sql, params, many, context) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 100, in _execute + with self.db.wrap_database_errors: + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/utils.py", line 91, in __exit__ + raise dj_exc_value.with_traceback(traceback) from exc_value + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 105, in _execute + return self.cursor.execute(sql, params) +django.db.utils.ProgrammingError: relation "hq_product" does not exist +LINE 1: INSERT INTO "hq_product" ("name", "manufacturer", "manufactu... + ^ + +"POST /api/hq/api/products/upload/ HTTP/1.1" 500 215430 +Watching for file changes with StatReloader +Internal Server Error: /api/hq/api/products/upload/ +Traceback (most recent call last): + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 105, in _execute + return self.cursor.execute(sql, params) +psycopg2.errors.UndefinedTable: relation "hq_product" does not exist +LINE 1: INSERT INTO "hq_product" ("name", "manufacturer", "manufactu... + ^ + + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 65, in _view_wrapper + return view_func(request, *args, **kwargs) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/views/generic/base.py", line 104, in view + return self.dispatch(request, *args, **kwargs) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/views.py", line 509, in dispatch + response = self.handle_exception(exc) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/views.py", line 469, in handle_exception + self.raise_uncaught_exception(exc) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception + raise exc + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch + response = handler(request, *args, **kwargs) + File "/home/dark/Documents/GitHub/store-management-system/hq/views.py", line 11, in post + serializer.save() + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/serializers.py", line 758, in save + self.instance = self.create(validated_data) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/serializers.py", line 730, in create + return [ + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/serializers.py", line 731, in + self.child.create(attrs) for attrs in validated_data + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/rest_framework/serializers.py", line 989, in create + instance = ModelClass._default_manager.create(**validated_data) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/manager.py", line 87, in manager_method + return getattr(self.get_queryset(), name)(*args, **kwargs) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/query.py", line 679, in create + obj.save(force_insert=True, using=self.db) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/base.py", line 892, in save + self.save_base( + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/base.py", line 998, in save_base + updated = self._save_table( + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/base.py", line 1161, in _save_table + results = self._do_insert( + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/base.py", line 1202, in _do_insert + return manager._insert( + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/manager.py", line 87, in manager_method + return getattr(self.get_queryset(), name)(*args, **kwargs) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/query.py", line 1847, in _insert + return query.get_compiler(using=using).execute_sql(returning_fields) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1836, in execute_sql + cursor.execute(sql, params) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 122, in execute + return super().execute(sql, params) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 79, in execute + return self._execute_with_wrappers( + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers + return executor(sql, params, many, context) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 100, in _execute + with self.db.wrap_database_errors: + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/utils.py", line 91, in __exit__ + raise dj_exc_value.with_traceback(traceback) from exc_value + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/db/backends/utils.py", line 105, in _execute + return self.cursor.execute(sql, params) +django.db.utils.ProgrammingError: relation "hq_product" does not exist +LINE 1: INSERT INTO "hq_product" ("name", "manufacturer", "manufactu... + ^ + +"POST /api/hq/api/products/upload/ HTTP/1.1" 500 215430 +Watching for file changes with StatReloader +"POST /api/hq/api/products/upload/ HTTP/1.1" 201 44 +Internal Server Error: /api/hq/api/contractors/upload +Traceback (most recent call last): + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/utils/deprecation.py", line 131, in __call__ + response = self.process_response(request, response) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/middleware/common.py", line 108, in process_response + return self.response_redirect_class(self.get_full_path_with_slash(request)) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/middleware/common.py", line 87, in get_full_path_with_slash + raise RuntimeError( +RuntimeError: You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining POST data. Change your form to point to 127.0.0.1:8000/api/hq/api/contractors/upload/ (note the trailing slash), or set APPEND_SLASH=False in your Django settings. +"POST /api/hq/api/contractors/upload HTTP/1.1" 500 78748 +Internal Server Error: /api/hq/api/employees/upload +Traceback (most recent call last): + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/utils/deprecation.py", line 131, in __call__ + response = self.process_response(request, response) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/middleware/common.py", line 108, in process_response + return self.response_redirect_class(self.get_full_path_with_slash(request)) + File "/home/dark/miniconda3/envs/django/lib/python3.10/site-packages/django/middleware/common.py", line 87, in get_full_path_with_slash + raise RuntimeError( +RuntimeError: You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining POST data. Change your form to point to 127.0.0.1:8000/api/hq/api/employees/upload/ (note the trailing slash), or set APPEND_SLASH=False in your Django settings. +"POST /api/hq/api/employees/upload HTTP/1.1" 500 78716 +"POST /api/hq/api/employees/upload/ HTTP/1.1" 201 45 +"POST /api/hq/api/contractors/upload/ HTTP/1.1" 201 47 +"POST /api/hq/api/contractor-contacts/upload/ HTTP/1.1" 201 55 diff --git a/settings/__pycache__/base.cpython-310.pyc b/settings/__pycache__/base.cpython-310.pyc index e43ac90accc892b74a2165967fd13e78d01d7020..92793c017290178b83ab9e0d03d6bd46554ba675 100644 GIT binary patch delta 45 zcmX@dcZrWLpO=@50SFi;*QYaaZsapyVdR@^&vJkziYcRT^M4jCCPu-@TI?zS@Jb4h delta 40 ucmcb_caD!QpO=@50SJQD*QNj9*vMzV!pJ+>p5?%1W>zgGMuEwC>?#1)D+#{< diff --git a/settings/base.py b/settings/base.py index 04bdeb4..e3d3d2c 100644 --- a/settings/base.py +++ b/settings/base.py @@ -58,6 +58,7 @@ INSTALLED_APPS = [ 'inventory', 'warehouse', 'hr', + 'hq', 'product_directory', 'goods_reception', 'pricing', diff --git a/urls.py b/urls.py index 022f400..c58f39b 100644 --- a/urls.py +++ b/urls.py @@ -8,4 +8,5 @@ urlpatterns = [ path('api/goods-reception/', include('goods_reception.urls')), path('api/warehouse/', include('warehouse.urls')), path('api/hr/', include('hr.urls')), + path('api/hq/', include('hq.urls')), ] From e38e99374acc1d4ac45b8a73d22c5974ef59b107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BB=D0=B5=D1=80?= <101361201+DarkSteelD@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:48:36 +0300 Subject: [PATCH 2/2] kek --- hr/migrations/0001_initial.py | 69 +++++++++++++++++++++++++++++++++++ hr/migrations/__init__.py | 0 hr/urls.py | 5 ++- hr/views.py | 46 ++++++++++++++++++++++- logs.log | 2 + 5 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 hr/migrations/0001_initial.py create mode 100644 hr/migrations/__init__.py diff --git a/hr/migrations/0001_initial.py b/hr/migrations/0001_initial.py new file mode 100644 index 0000000..8f35336 --- /dev/null +++ b/hr/migrations/0001_initial.py @@ -0,0 +1,69 @@ +# Generated by Django 5.1.4 on 2025-01-09 09:45 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Employee', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=50)), + ('last_name', models.CharField(max_length=50)), + ('position', models.CharField(max_length=100)), + ('email', models.EmailField(max_length=254, unique=True)), + ('hired_date', models.DateField()), + ('work_schedule', models.JSONField(default=dict)), + ], + ), + migrations.CreateModel( + name='Leave', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('leave_type', models.CharField(choices=[('vacation', 'Vacation'), ('sick', 'Sick Leave')], max_length=10)), + ('start_date', models.DateField()), + ('end_date', models.DateField()), + ('reason', models.TextField(blank=True)), + ('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hr.employee')), + ], + ), + migrations.CreateModel( + name='OvertimeReport', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField()), + ('worked_hours', models.FloatField()), + ('required_hours', models.FloatField(default=8.0)), + ('overtime', models.FloatField()), + ('comment', models.TextField(blank=True)), + ('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hr.employee')), + ], + ), + migrations.CreateModel( + name='Report', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('report_date', models.DateField(auto_now_add=True)), + ('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hr.employee')), + ], + ), + migrations.CreateModel( + name='WorkTimeLog', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField()), + ('check_in', models.TimeField(blank=True, null=True)), + ('check_out', models.TimeField(blank=True, null=True)), + ('worked_hours', models.FloatField(blank=True, null=True)), + ('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hr.employee')), + ], + ), + ] diff --git a/hr/migrations/__init__.py b/hr/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hr/urls.py b/hr/urls.py index 6d88889..5eed527 100644 --- a/hr/urls.py +++ b/hr/urls.py @@ -7,14 +7,16 @@ from .views import ( EmployeeViewSet, WorkTimeLogViewSet, LeaveViewSet, OvertimeReportViewSet, ReportViewSet ) +from .views import generate_employee_report # Create the router for HR-related views router_hr = DefaultRouter() router_hr.register(r'employees', EmployeeViewSet) router_hr.register(r'work-time-logs', WorkTimeLogViewSet) -router_hr.register(r'leaves', LeaveViewSet) router_hr.register(r'overtime-reports', OvertimeReportViewSet) router_hr.register(r'reports', ReportViewSet) +router_hr.register(r'work-time-logs', WorkTimeLogViewSet, basename='work-time-log') +router_hr.register(r'leaves', LeaveViewSet, basename='leave') # Swagger schema view for HR schema_view_hr = get_schema_view( @@ -34,4 +36,5 @@ urlpatterns = [ path('', include(router_hr.urls)), path('swagger/', schema_view_hr.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui-hr'), path('redoc/', schema_view_hr.with_ui('redoc', cache_timeout=0), name='schema-redoc-hr'), + path('generate-report//', generate_employee_report, name='generate_employee_report'), ] diff --git a/hr/views.py b/hr/views.py index f958047..14c2a4d 100644 --- a/hr/views.py +++ b/hr/views.py @@ -5,7 +5,51 @@ from .serializers import ( OvertimeReportSerializer, ReportSerializer ) -# ViewSet для модели Employee +from django.http import FileResponse +from django.shortcuts import get_object_or_404 +from rest_framework import viewsets +from rest_framework.filters import OrderingFilter +from django_filters.rest_framework import DjangoFilterBackend + +class WorkTimeLogViewSet(viewsets.ModelViewSet): + queryset = WorkTimeLog.objects.all() + serializer_class = WorkTimeLogSerializer + filter_backends = [DjangoFilterBackend, OrderingFilter] + filterset_fields = { + 'employee__id': ['exact'], + 'date': ['gte', 'lte'], + } + ordering_fields = ['date'] + +class LeaveViewSet(viewsets.ModelViewSet): + queryset = Leave.objects.all() + serializer_class = LeaveSerializer + filter_backends = [DjangoFilterBackend, OrderingFilter] + filterset_fields = { + 'employee__id': ['exact'], + 'start_date': ['gte', 'lte'], + 'end_date': ['gte', 'lte'], + } + ordering_fields = ['start_date', 'end_date'] + +class OvertimeReportViewSet(viewsets.ModelViewSet): + queryset = OvertimeReport.objects.all() + serializer_class = OvertimeReportSerializer + filter_backends = [DjangoFilterBackend, OrderingFilter] + filterset_fields = { + 'employee__id': ['exact'], + 'date': ['gte', 'lte'], + } + ordering_fields = ['date'] + +def generate_employee_report(request, report_id): + """ + Генерация отчета с фильтрацией по диапазону дат. + """ + report = get_object_or_404(Report, id=report_id) + pdf_buffer = report.generate_pdf() + return FileResponse(pdf_buffer, as_attachment=True, filename=f"отчет_{report.employee.last_name}.pdf") + class EmployeeViewSet(viewsets.ModelViewSet): queryset = Employee.objects.all() serializer_class = EmployeeSerializer diff --git a/logs.log b/logs.log index 6051cdf..dbc9113 100644 --- a/logs.log +++ b/logs.log @@ -951,3 +951,5 @@ RuntimeError: You called this URL via POST, but the URL doesn't end in a slash a "POST /api/hq/api/employees/upload/ HTTP/1.1" 201 45 "POST /api/hq/api/contractors/upload/ HTTP/1.1" 201 47 "POST /api/hq/api/contractor-contacts/upload/ HTTP/1.1" 201 55 +Watching for file changes with StatReloader +"GET /api/hr/ HTTP/1.1" 200 10827