Compare commits
No commits in common. "master" and "main" have entirely different histories.
3
.idea/.gitignore
generated
vendored
3
.idea/.gitignore
generated
vendored
@ -1,3 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
14
.idea/backend-fontend.iml
generated
14
.idea/backend-fontend.iml
generated
@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="PyDocumentationSettings">
|
||||
<option name="format" value="PLAIN" />
|
||||
<option name="myDocStringFormat" value="Plain" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/encodings.xml
generated
6
.idea/encodings.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/barcode/settings.py" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
6
.idea/inspectionProfiles/profiles_settings.xml
generated
@ -1,6 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
7
.idea/misc.xml
generated
7
.idea/misc.xml
generated
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.12 (backend-fontend)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (backend-fontend)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/backend-fontend.iml" filepath="$PROJECT_DIR$/.idea/backend-fontend.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
BIN
barcode/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
barcode/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
barcode/__pycache__/celery_app.cpython-312.pyc
Normal file
BIN
barcode/__pycache__/celery_app.cpython-312.pyc
Normal file
Binary file not shown.
BIN
barcode/__pycache__/settings.cpython-312.pyc
Normal file
BIN
barcode/__pycache__/settings.cpython-312.pyc
Normal file
Binary file not shown.
BIN
barcode/__pycache__/urls.cpython-312.pyc
Normal file
BIN
barcode/__pycache__/urls.cpython-312.pyc
Normal file
Binary file not shown.
BIN
barcode/__pycache__/wsgi.cpython-312.pyc
Normal file
BIN
barcode/__pycache__/wsgi.cpython-312.pyc
Normal file
Binary file not shown.
@ -16,9 +16,6 @@ from pathlib import Path
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
|
||||
|
||||
@ -28,10 +25,6 @@ SECRET_KEY = 'django-insecure-i#8aotin&c00-&#v@x!moruf-uimxr#c!8pi9ehltop98-@bzr
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
if DEBUG: # Убедитесь, что это только для разработки
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': [],
|
||||
}
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
CELERY_BROKER_URL = 'redis://localhost:6379/0'
|
||||
@ -51,8 +44,6 @@ INSTALLED_APPS = [
|
||||
'scan',
|
||||
'forms',
|
||||
'users',
|
||||
'issues',
|
||||
'production',
|
||||
"channels",
|
||||
'rest_framework',
|
||||
'rest_framework_simplejwt',
|
||||
@ -108,10 +99,10 @@ WSGI_APPLICATION = 'barcode.wsgi.application'
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'NAME': 'postgres',
|
||||
'USER': 'postgres',
|
||||
'PASSWORD': '1240069630Bk!',
|
||||
'HOST': 'localhost',
|
||||
'NAME': 'mydatabase',
|
||||
'USER': 'myuser',
|
||||
'PASSWORD': 'mypassword',
|
||||
'HOST': '31.130.144.182',
|
||||
'PORT': '5432',
|
||||
'OPTIONS': {
|
||||
'client_encoding': 'UTF8',
|
||||
@ -176,12 +167,7 @@ REST_FRAMEWORK = {
|
||||
),
|
||||
}
|
||||
|
||||
CORS_ALLOW_HEADERS = [
|
||||
'authorization',
|
||||
'content-type',
|
||||
'x-csrftoken',
|
||||
'x-requested-with',
|
||||
]
|
||||
CORS_ALLOW_HEADERS = ['Content-Type'] # <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
CORS_ALLOW_ALL_ORIGINS = True # <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
# <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> localhost:3000
|
||||
|
||||
@ -30,6 +30,4 @@ urlpatterns = [
|
||||
path("inventory/", include("inventory.urls")),
|
||||
path("forms/", include("forms.urls")),
|
||||
path("api/users/", include("users.urls")),
|
||||
path("api/production/", include("production.urls")),
|
||||
path("reference/", include("issues.urls")),
|
||||
]
|
||||
BIN
batches/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
batches/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
batches/__pycache__/admin.cpython-312.pyc
Normal file
BIN
batches/__pycache__/admin.cpython-312.pyc
Normal file
Binary file not shown.
BIN
batches/__pycache__/apps.cpython-312.pyc
Normal file
BIN
batches/__pycache__/apps.cpython-312.pyc
Normal file
Binary file not shown.
BIN
batches/__pycache__/models.cpython-312.pyc
Normal file
BIN
batches/__pycache__/models.cpython-312.pyc
Normal file
Binary file not shown.
BIN
batches/__pycache__/urls.cpython-312.pyc
Normal file
BIN
batches/__pycache__/urls.cpython-312.pyc
Normal file
Binary file not shown.
BIN
batches/__pycache__/views.cpython-312.pyc
Normal file
BIN
batches/__pycache__/views.cpython-312.pyc
Normal file
Binary file not shown.
BIN
batches/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
batches/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
forms/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
forms/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
forms/__pycache__/admin.cpython-312.pyc
Normal file
BIN
forms/__pycache__/admin.cpython-312.pyc
Normal file
Binary file not shown.
BIN
forms/__pycache__/apps.cpython-312.pyc
Normal file
BIN
forms/__pycache__/apps.cpython-312.pyc
Normal file
Binary file not shown.
BIN
forms/__pycache__/models.cpython-312.pyc
Normal file
BIN
forms/__pycache__/models.cpython-312.pyc
Normal file
Binary file not shown.
BIN
forms/__pycache__/serializers.cpython-312.pyc
Normal file
BIN
forms/__pycache__/serializers.cpython-312.pyc
Normal file
Binary file not shown.
BIN
forms/__pycache__/urls.cpython-312.pyc
Normal file
BIN
forms/__pycache__/urls.cpython-312.pyc
Normal file
Binary file not shown.
BIN
forms/__pycache__/views.cpython-312.pyc
Normal file
BIN
forms/__pycache__/views.cpython-312.pyc
Normal file
Binary file not shown.
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.1.5 on 2025-03-21 23:48
|
||||
# Generated by Django 5.1.5 on 2025-03-06 04:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
BIN
forms/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
BIN
forms/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
Binary file not shown.
BIN
forms/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
forms/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
inventory/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
inventory/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
inventory/__pycache__/admin.cpython-312.pyc
Normal file
BIN
inventory/__pycache__/admin.cpython-312.pyc
Normal file
Binary file not shown.
BIN
inventory/__pycache__/apps.cpython-312.pyc
Normal file
BIN
inventory/__pycache__/apps.cpython-312.pyc
Normal file
Binary file not shown.
BIN
inventory/__pycache__/models.cpython-312.pyc
Normal file
BIN
inventory/__pycache__/models.cpython-312.pyc
Normal file
Binary file not shown.
BIN
inventory/__pycache__/serializers.cpython-312.pyc
Normal file
BIN
inventory/__pycache__/serializers.cpython-312.pyc
Normal file
Binary file not shown.
BIN
inventory/__pycache__/urls.cpython-312.pyc
Normal file
BIN
inventory/__pycache__/urls.cpython-312.pyc
Normal file
Binary file not shown.
BIN
inventory/__pycache__/views.cpython-312.pyc
Normal file
BIN
inventory/__pycache__/views.cpython-312.pyc
Normal file
Binary file not shown.
@ -1,7 +1,6 @@
|
||||
# Generated by Django 5.1.5 on 2025-03-21 23:48
|
||||
# Generated by Django 5.1.5 on 2025-03-06 04:31
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
@ -10,7 +9,6 @@ class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@ -46,24 +44,4 @@ class Migration(migrations.Migration):
|
||||
('sticker', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.sticker')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StickerTransferRequest',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('status', models.CharField(choices=[('pending', 'Ожидает'), ('accepted', 'Принята'), ('declined', 'Отклонена'), ('cancelled', 'Отменена')], default='pending', max_length=20)),
|
||||
('comment', models.TextField(blank=True, null=True)),
|
||||
('from_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_transfers', to=settings.AUTH_USER_MODEL)),
|
||||
('to_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='received_transfers', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StickerTransferItem',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.IntegerField()),
|
||||
('sticker', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.sticker')),
|
||||
('transfer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='inventory.stickertransferrequest')),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
BIN
inventory/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
BIN
inventory/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
Binary file not shown.
BIN
inventory/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
inventory/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
@ -1,7 +1,5 @@
|
||||
from django.db import models
|
||||
from datetime import timedelta, date
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
class Nomenclature(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
@ -59,23 +57,3 @@ class StickerMovement(models.Model):
|
||||
self.sticker.location = "склад"
|
||||
self.sticker.save()
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class StickerTransferRequest(models.Model):
|
||||
STATUS_CHOICES = [
|
||||
("pending", "Ожидает"),
|
||||
("accepted", "Принята"),
|
||||
("declined", "Отклонена"),
|
||||
("cancelled", "Отменена"),
|
||||
]
|
||||
|
||||
from_user = models.ForeignKey(User, related_name="sent_transfers", on_delete=models.CASCADE)
|
||||
to_user = models.ForeignKey(User, related_name="received_transfers", on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending")
|
||||
comment = models.TextField(blank=True, null=True)
|
||||
|
||||
class StickerTransferItem(models.Model):
|
||||
transfer = models.ForeignKey(StickerTransferRequest, related_name="items", on_delete=models.CASCADE)
|
||||
sticker = models.ForeignKey(Sticker, on_delete=models.CASCADE)
|
||||
quantity = models.IntegerField()
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
from rest_framework import serializers
|
||||
from .models import Nomenclature, Sticker, StickerMovement
|
||||
from datetime import date
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
class NomenclatureSerializer(serializers.ModelSerializer):
|
||||
@ -33,35 +32,3 @@ class StickerMovementSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = StickerMovement
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
""" Transfer sticks """
|
||||
|
||||
|
||||
from rest_framework import serializers
|
||||
from .models import StickerTransferRequest, StickerTransferItem, Sticker
|
||||
|
||||
class StickerTransferItemSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = StickerTransferItem
|
||||
fields = ['id', 'sticker', 'quantity']
|
||||
|
||||
|
||||
class StickerTransferRequestSerializer(serializers.ModelSerializer):
|
||||
items = StickerTransferItemSerializer(many=True)
|
||||
from_user = serializers.StringRelatedField(read_only=True)
|
||||
to_user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
|
||||
|
||||
class Meta:
|
||||
model = StickerTransferRequest
|
||||
fields = ['id', 'from_user', 'to_user', 'status', 'created_at', 'items']
|
||||
|
||||
def create(self, validated_data):
|
||||
items_data = validated_data.pop('items')
|
||||
transfer = StickerTransferRequest.objects.create(**validated_data)
|
||||
for item in items_data:
|
||||
StickerTransferItem.objects.create(transfer=transfer, **item)
|
||||
return transfer
|
||||
@ -1,21 +0,0 @@
|
||||
from inventory.models import StickerTransferItem
|
||||
|
||||
|
||||
class StickerTransferItemSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = StickerTransferItem
|
||||
fields = "__all__"
|
||||
|
||||
class StickerTransferRequestSerializer(serializers.ModelSerializer):
|
||||
items = StickerTransferItemSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = StickerTransferRequest
|
||||
fields = "__all__"
|
||||
|
||||
def create(self, validated_data):
|
||||
items_data = validated_data.pop("items")
|
||||
transfer = StickerTransferRequest.objects.create(**validated_data)
|
||||
for item in items_data:
|
||||
StickerTransferItem.objects.create(transfer=transfer, **item)
|
||||
return transfer
|
||||
@ -1,35 +1,13 @@
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from .views import (
|
||||
NomenclatureViewSet,
|
||||
StickerViewSet,
|
||||
StickerMovementViewSet,
|
||||
ExternalNomenclatureView,
|
||||
)
|
||||
from .views_transfer import StickerTransferRequestViewSet # Импортируем новый ViewSet
|
||||
from .views import NomenclatureViewSet, StickerViewSet, StickerMovementViewSet, ExternalNomenclatureView
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'nomenclature', NomenclatureViewSet)
|
||||
router.register(r'stickers', StickerViewSet)
|
||||
router.register(r'movement', StickerMovementViewSet)
|
||||
router.register(r'transfers', StickerTransferRequestViewSet, basename='stickertransfer') # Добавляем
|
||||
|
||||
urlpatterns = [
|
||||
path('api/', include(router.urls)),
|
||||
path('api/external-nomenclature/', ExternalNomenclatureView.as_view(), name="external-nomenclature"),
|
||||
]
|
||||
"""Трансфер передачи стикеров"""
|
||||
"""{
|
||||
"to_user": 3, // <-- ID пользователя, а не имя!
|
||||
"items": [
|
||||
{
|
||||
"sticker": 12, // ID стикера
|
||||
"quantity": 10
|
||||
},
|
||||
{
|
||||
"sticker": 15,
|
||||
"quantity": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
@ -117,11 +117,6 @@ class StickerViewSet(viewsets.ModelViewSet):
|
||||
self.perform_destroy(instance)
|
||||
return Response({"message": "Стикер успешно удалён"}, status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
|
||||
"""Передача стикеров"""
|
||||
|
||||
class StickerMovementViewSet(viewsets.ModelViewSet):
|
||||
queryset = StickerMovement.objects.all()
|
||||
serializer_class = StickerMovementSerializer
|
||||
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
from rest_framework import viewsets, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.decorators import action
|
||||
from django.contrib.auth.models import User
|
||||
from .models import StickerTransferRequest, StickerTransferItem, Sticker, StickerMovement
|
||||
from .serializers import StickerTransferRequestSerializer, StickerTransferItemSerializer
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils import timezone
|
||||
|
||||
class StickerTransferRequestViewSet(viewsets.ModelViewSet):
|
||||
queryset = StickerTransferRequest.objects.all().select_related('from_user', 'to_user').prefetch_related('items__sticker')
|
||||
serializer_class = StickerTransferRequestSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
return StickerTransferRequest.objects.filter(from_user=user) | StickerTransferRequest.objects.filter(to_user=user)
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(from_user=self.request.user)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def accept(self, request, pk=None):
|
||||
transfer = get_object_or_404(StickerTransferRequest, pk=pk)
|
||||
|
||||
if transfer.to_user != request.user:
|
||||
return Response({"error": "Нет прав для принятия этой передачи."}, status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
if transfer.status != 'pending':
|
||||
return Response({"error": "Передача уже обработана."}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# Перемещение стикеров
|
||||
for item in transfer.items.all():
|
||||
StickerMovement.objects.create(
|
||||
sticker=item.sticker,
|
||||
from_location='склад',
|
||||
to_location='цех',
|
||||
quantity=item.quantity
|
||||
)
|
||||
item.sticker.location = 'цех'
|
||||
item.sticker.save()
|
||||
|
||||
transfer.status = 'accepted'
|
||||
transfer.save()
|
||||
return Response({"status": "Принята"})
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def decline(self, request, pk=None):
|
||||
transfer = get_object_or_404(StickerTransferRequest, pk=pk)
|
||||
|
||||
if transfer.to_user != request.user:
|
||||
return Response({"error": "Нет прав для отклонения этой передачи."}, status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
if transfer.status != 'pending':
|
||||
return Response({"error": "Передача уже обработана."}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
transfer.status = 'declined'
|
||||
transfer.save()
|
||||
return Response({"status": "Отклонена"})
|
||||
@ -1,16 +0,0 @@
|
||||
from django.contrib import admin
|
||||
from .models import IssueCategory, Zone, Issue
|
||||
|
||||
@admin.register(IssueCategory)
|
||||
class IssueCategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ("name",)
|
||||
|
||||
@admin.register(Zone)
|
||||
class ZoneAdmin(admin.ModelAdmin):
|
||||
list_display = ("name",)
|
||||
|
||||
@admin.register(Issue)
|
||||
class IssueAdmin(admin.ModelAdmin):
|
||||
list_display = ("category", "zone", "description", "created_at")
|
||||
list_filter = ("category", "zone")
|
||||
search_fields = ("description",)
|
||||
@ -1,6 +0,0 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class IssuesConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'issues'
|
||||
@ -1,59 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-03-23 07:18
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='IssueCategory',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, unique=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Message',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('identifier', models.CharField(max_length=100, unique=True)),
|
||||
('text', models.TextField()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Nomenclature',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('short_name', models.CharField(max_length=100)),
|
||||
('gtin', models.CharField(max_length=14, unique=True)),
|
||||
('groupe_water', models.CharField(max_length=255)),
|
||||
('groupe_names', models.CharField(max_length=255)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Zone',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, unique=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Issue',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('description', models.TextField()),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='issues', to='issues.issuecategory')),
|
||||
('zone', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='issues', to='issues.zone')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@ -1,93 +0,0 @@
|
||||
from django.db import models
|
||||
|
||||
class IssueCategory(models.Model):
|
||||
"""Категории проблем"""
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Zone(models.Model):
|
||||
"""Зоны, где возникают проблемы"""
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Issue(models.Model):
|
||||
"""Конкретные проблемы"""
|
||||
category = models.ForeignKey(IssueCategory, on_delete=models.CASCADE, related_name="issues")
|
||||
zone = models.ForeignKey(Zone, on_delete=models.CASCADE, related_name="issues")
|
||||
description = models.TextField()
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.category.name} - {self.zone.name}: {self.description[:50]}"
|
||||
|
||||
|
||||
"""GET /api/categories/ – список категорий
|
||||
POST /api/categories/ – создать категорию
|
||||
GET /api/zones/ – список зон
|
||||
POST /api/zones/ – создать зону
|
||||
GET /api/issues/ – список проблем
|
||||
POST /api/issues/ – добавить проблему
|
||||
DELETE /api/issues/<id>/ – удалить проблему"""
|
||||
|
||||
|
||||
|
||||
"""Модели справочника номенклатура и сообщения"""
|
||||
class Nomenclature(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
short_name = models.CharField(max_length=100)
|
||||
gtin = models.CharField(max_length=14, unique=True)
|
||||
groupe_water = models.CharField(max_length=255)
|
||||
groupe_names = models.CharField(max_length=255)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Message(models.Model):
|
||||
identifier = models.CharField(max_length=100, unique=True)
|
||||
text = models.TextField()
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.identifier}: {self.text[:30]}"
|
||||
|
||||
class Plant(models.Model):
|
||||
"""Справочник заводов"""
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class ProductionLine(models.Model):
|
||||
"""Справочник производственных линий"""
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
plant = models.ForeignKey(Plant, on_delete=models.CASCADE, related_name="lines")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.plant.name} - {self.name}"
|
||||
|
||||
|
||||
class ProductionZone(models.Model):
|
||||
"""Справочник производственных зон"""
|
||||
name = models.CharField(max_length=255)
|
||||
line = models.ForeignKey(ProductionLine, on_delete=models.CASCADE, related_name="zones")
|
||||
|
||||
class Meta:
|
||||
unique_together = ('name', 'line') # Зона уникальна в пределах линии
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.line.name} - {self.name}"
|
||||
|
||||
|
||||
class DowntimeReason(models.Model):
|
||||
"""Справочник причин простоев"""
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
description = models.TextField(blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
@ -1,33 +0,0 @@
|
||||
from rest_framework import serializers
|
||||
from .models import IssueCategory, Zone, Issue, Nomenclature, Message
|
||||
|
||||
class IssueCategorySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = IssueCategory
|
||||
fields = '__all__'
|
||||
|
||||
class ZoneSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Zone
|
||||
fields = '__all__'
|
||||
|
||||
class IssueSerializer(serializers.ModelSerializer):
|
||||
category = IssueCategorySerializer(read_only=True)
|
||||
category_id = serializers.PrimaryKeyRelatedField(queryset=IssueCategory.objects.all(), source='category', write_only=True)
|
||||
zone = ZoneSerializer(read_only=True)
|
||||
zone_id = serializers.PrimaryKeyRelatedField(queryset=Zone.objects.all(), source='zone', write_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Issue
|
||||
fields = ['id', 'category', 'category_id', 'zone', 'zone_id', 'description', 'created_at', 'updated_at']
|
||||
|
||||
|
||||
class NomenclatureSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Nomenclature
|
||||
fields = '__all__'
|
||||
|
||||
class MessageSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Message
|
||||
fields = '__all__'
|
||||
@ -1,3 +0,0 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@ -1,16 +0,0 @@
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from inventory.views import NomenclatureViewSet
|
||||
from .serializers import NomenclatureSerializer
|
||||
from .views import IssueCategoryViewSet, ZoneViewSet, IssueViewSet, NomenclatureViewSet, MessageViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'categories', IssueCategoryViewSet)
|
||||
router.register(r'zones', ZoneViewSet)
|
||||
router.register(r'issues', IssueViewSet)
|
||||
router.register(r'nomenclature', NomenclatureViewSet)
|
||||
router.register(r'messages', MessageViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path('api/', include(router.urls)),
|
||||
]
|
||||
@ -1,29 +0,0 @@
|
||||
from rest_framework import viewsets
|
||||
from .models import IssueCategory, Zone, Issue
|
||||
from .serializers import IssueCategorySerializer, ZoneSerializer, IssueSerializer
|
||||
|
||||
class IssueCategoryViewSet(viewsets.ModelViewSet):
|
||||
queryset = IssueCategory.objects.all()
|
||||
serializer_class = IssueCategorySerializer
|
||||
|
||||
class ZoneViewSet(viewsets.ModelViewSet):
|
||||
queryset = Zone.objects.all()
|
||||
serializer_class = ZoneSerializer
|
||||
|
||||
class IssueViewSet(viewsets.ModelViewSet):
|
||||
queryset = Issue.objects.all().order_by('-created_at')
|
||||
serializer_class = IssueSerializer
|
||||
|
||||
|
||||
"""Справочник номенклатуры и сообщений"""
|
||||
from rest_framework import viewsets
|
||||
from .models import Nomenclature, Message
|
||||
from .serializers import NomenclatureSerializer, MessageSerializer
|
||||
|
||||
class NomenclatureViewSet(viewsets.ModelViewSet):
|
||||
queryset = Nomenclature.objects.all()
|
||||
serializer_class = NomenclatureSerializer
|
||||
|
||||
class MessageViewSet(viewsets.ModelViewSet):
|
||||
queryset = Message.objects.all()
|
||||
serializer_class = MessageSerializer
|
||||
@ -1,321 +0,0 @@
|
||||
import flet as ft
|
||||
from datetime import datetime
|
||||
|
||||
def main(page: ft.Page):
|
||||
# Состояние формы
|
||||
state = {
|
||||
"current_step": 0,
|
||||
"operators_name": "",
|
||||
"factory": "",
|
||||
"line": "",
|
||||
"error_zone": "",
|
||||
"problems": set(), # будем накапливать выбранные значения
|
||||
"downtime_reasons": set(),
|
||||
"custom_problem": "",
|
||||
"custom_reason": "",
|
||||
"fix_method": "",
|
||||
"start_at": "",
|
||||
"end_at": "",
|
||||
# Зависимые опции:
|
||||
"line_options": [],
|
||||
"zone_options": [],
|
||||
"problem_options": [],
|
||||
"reason_options": [],
|
||||
}
|
||||
|
||||
# Справочники (аналогичные примерам в React/Ionic)
|
||||
factory_line_map = {
|
||||
"Славда": ["ПЭТ", "19л", "5л"],
|
||||
"Скит": ["Sipa", "Devin", "JR", "19 Литров", "5 Литров"]
|
||||
}
|
||||
|
||||
line_zone_map = {
|
||||
"Sipa": ["Сериализация", "Упаковка", "Сборка палеты", "Закрытие палеты"],
|
||||
"Devin": ["Сериализация", "Упаковка", "Сборка палеты"],
|
||||
"JR": ["Сериализация", "Упаковка", "Сборка палеты", "Закрытие палеты"],
|
||||
"19 Литров": ["Валидация", "Тонкий клиент"],
|
||||
"5 Литров": ["Валидация", "Тонкий клиент"],
|
||||
"ПЭТ": ["Сериализация", "Упаковка", "Сборка палеты", "Закрытие палеты"],
|
||||
"5л": ["Сериализация", "Упаковка", "Сборка палеты", "Закрытие палеты"],
|
||||
"19л": ["Валидация", "Тонкий клиент"],
|
||||
}
|
||||
|
||||
common_problems = {
|
||||
"Славда": ["Не печатает код", "Камера не считывает код", "Сбой принтера"],
|
||||
"Скит": ["Не печатает код", "Камера не считывает код", "Сбой принтера"],
|
||||
}
|
||||
|
||||
common_downtime_reasons = {
|
||||
"Славда": ["Сбой камеры", "Ошибка валидации", "Проблема с печатью"],
|
||||
"Скит": ["Сбой камеры", "Ошибка валидации", "Проблема с печатью"],
|
||||
}
|
||||
|
||||
# Элементы UI, которые будут обновляться
|
||||
operators_name_field = ft.TextField(label="Имя оператора *", width=300)
|
||||
factory_dropdown = ft.Dropdown(
|
||||
label="Завод *",
|
||||
options=[
|
||||
ft.dropdown.Option("Славда"),
|
||||
ft.dropdown.Option("Скит")
|
||||
],
|
||||
width=300
|
||||
)
|
||||
line_dropdown = ft.Dropdown(label="Линия *", width=300)
|
||||
zone_dropdown = ft.Dropdown(label="Зона *", width=300)
|
||||
|
||||
fix_method_field = ft.TextField(label="Как решили проблему? *", width=300)
|
||||
start_at_field = ft.TextField(label="Начало простоя (YYYY-MM-DD HH:MM) *", width=300)
|
||||
end_at_field = ft.TextField(label="Окончание простоя (YYYY-MM-DD HH:MM) *", width=300)
|
||||
|
||||
custom_problem_field = ft.TextField(label="Своя проблема (необязательно)", width=300)
|
||||
custom_reason_field = ft.TextField(label="Своя причина (необязательно)", width=300)
|
||||
|
||||
# Для выбора нескольких вариантов – используем колонки с чекбоксами
|
||||
problems_checkboxes = ft.Column()
|
||||
reasons_checkboxes = ft.Column()
|
||||
|
||||
# Функция для показа уведомлений (SnackBar)
|
||||
def show_snackbar(message, bgcolor):
|
||||
page.snack_bar = ft.SnackBar(ft.Text(message), bgcolor=bgcolor)
|
||||
page.snack_bar.open = True
|
||||
page.update()
|
||||
|
||||
# Обновление зависимых списков при выборе завода
|
||||
def update_factory_dependent():
|
||||
factory = state["factory"]
|
||||
state["line_options"] = factory_line_map.get(factory, [])
|
||||
line_dropdown.options = [ft.dropdown.Option(opt) for opt in state["line_options"]]
|
||||
line_dropdown.value = None
|
||||
state["line"] = ""
|
||||
|
||||
state["problem_options"] = common_problems.get(factory, [])
|
||||
state["reason_options"] = common_downtime_reasons.get(factory, [])
|
||||
update_problems_checkboxes()
|
||||
update_reasons_checkboxes()
|
||||
page.update()
|
||||
|
||||
# Обновление списка зон при выборе линии
|
||||
def update_line_dependent():
|
||||
line = state["line"]
|
||||
state["zone_options"] = line_zone_map.get(line, [])
|
||||
zone_dropdown.options = [ft.dropdown.Option(opt) for opt in state["zone_options"]]
|
||||
zone_dropdown.value = None
|
||||
state["error_zone"] = ""
|
||||
page.update()
|
||||
|
||||
def update_problems_checkboxes():
|
||||
problems_checkboxes.controls.clear()
|
||||
for prob in state["problem_options"]:
|
||||
chk = ft.Checkbox(label=prob, value=False)
|
||||
def on_change(e, label=prob):
|
||||
if e.control.value:
|
||||
state["problems"].add(label)
|
||||
else:
|
||||
state["problems"].discard(label)
|
||||
chk.on_change = on_change
|
||||
problems_checkboxes.controls.append(chk)
|
||||
page.update()
|
||||
|
||||
def update_reasons_checkboxes():
|
||||
reasons_checkboxes.controls.clear()
|
||||
for reason in state["reason_options"]:
|
||||
chk = ft.Checkbox(label=reason, value=False)
|
||||
def on_change(e, label=reason):
|
||||
if e.control.value:
|
||||
state["downtime_reasons"].add(label)
|
||||
else:
|
||||
state["downtime_reasons"].discard(label)
|
||||
chk.on_change = on_change
|
||||
reasons_checkboxes.controls.append(chk)
|
||||
page.update()
|
||||
|
||||
# Функция валидации этапов
|
||||
def validate_step():
|
||||
step = state["current_step"]
|
||||
if step == 0:
|
||||
if not operators_name_field.value.strip() or not factory_dropdown.value:
|
||||
show_snackbar("Введите имя и выберите завод", ft.colors.RED)
|
||||
return False
|
||||
elif step == 1:
|
||||
if not line_dropdown.value or not zone_dropdown.value:
|
||||
show_snackbar("Выберите линию и зону", ft.colors.RED)
|
||||
return False
|
||||
elif step == 2:
|
||||
total_problems = set(state["problems"])
|
||||
if custom_problem_field.value and custom_problem_field.value.strip():
|
||||
total_problems.add(custom_problem_field.value.strip())
|
||||
total_reasons = set(state["downtime_reasons"])
|
||||
if custom_reason_field.value and custom_reason_field.value.strip():
|
||||
total_reasons.add(custom_reason_field.value.strip())
|
||||
if not total_problems:
|
||||
show_snackbar("Укажите хотя бы одну проблему", ft.colors.RED)
|
||||
return False
|
||||
if not total_reasons:
|
||||
show_snackbar("Укажите хотя бы одну причину простоя", ft.colors.RED)
|
||||
return False
|
||||
elif step == 3:
|
||||
if not fix_method_field.value.strip():
|
||||
show_snackbar("Опишите, как решили проблему", ft.colors.RED)
|
||||
return False
|
||||
if not start_at_field.value.strip() or not end_at_field.value.strip():
|
||||
show_snackbar("Укажите время начала и окончания", ft.colors.RED)
|
||||
return False
|
||||
try:
|
||||
datetime.strptime(start_at_field.value.strip(), "%Y-%m-%d %H:%M")
|
||||
datetime.strptime(end_at_field.value.strip(), "%Y-%m-%d %H:%M")
|
||||
except ValueError:
|
||||
show_snackbar("Неверный формат даты/времени", ft.colors.RED)
|
||||
return False
|
||||
return True
|
||||
|
||||
# Контейнер для отображения содержимого этапа
|
||||
content_column = ft.Column()
|
||||
# Прогресс-бар (значение от 0 до 1)
|
||||
progress_bar = ft.ProgressBar(value=(state["current_step"]+1)/4)
|
||||
|
||||
# Кнопки навигации
|
||||
next_button = ft.ElevatedButton(text="Далее")
|
||||
back_button = ft.ElevatedButton(text="Назад")
|
||||
submit_button = ft.ElevatedButton(text="Отправить")
|
||||
|
||||
# Обновление UI в зависимости от этапа
|
||||
def update_ui():
|
||||
content_column.controls.clear()
|
||||
progress_bar.value = (state["current_step"]+1)/4
|
||||
|
||||
if state["current_step"] == 0:
|
||||
content_column.controls.extend([
|
||||
operators_name_field,
|
||||
factory_dropdown,
|
||||
])
|
||||
elif state["current_step"] == 1:
|
||||
content_column.controls.extend([
|
||||
line_dropdown,
|
||||
zone_dropdown,
|
||||
])
|
||||
elif state["current_step"] == 2:
|
||||
content_column.controls.extend([
|
||||
ft.Text("Проблемы (можно выбрать несколько):"),
|
||||
problems_checkboxes,
|
||||
custom_problem_field,
|
||||
ft.Text("Причины простоя (можно выбрать несколько):"),
|
||||
reasons_checkboxes,
|
||||
custom_reason_field,
|
||||
])
|
||||
elif state["current_step"] == 3:
|
||||
content_column.controls.extend([
|
||||
fix_method_field,
|
||||
start_at_field,
|
||||
end_at_field,
|
||||
])
|
||||
|
||||
# Кнопки навигации
|
||||
nav_buttons = []
|
||||
if state["current_step"] > 0:
|
||||
nav_buttons.append(back_button)
|
||||
if state["current_step"] < 3:
|
||||
nav_buttons.append(next_button)
|
||||
if state["current_step"] == 3:
|
||||
nav_buttons.append(submit_button)
|
||||
content_column.controls.append(ft.Row(controls=nav_buttons, spacing=20))
|
||||
page.update()
|
||||
|
||||
# Обработчики кнопок
|
||||
def on_next(e):
|
||||
if validate_step():
|
||||
if state["current_step"] == 0:
|
||||
state["operators_name"] = operators_name_field.value
|
||||
state["factory"] = factory_dropdown.value
|
||||
update_factory_dependent()
|
||||
elif state["current_step"] == 1:
|
||||
state["line"] = line_dropdown.value
|
||||
state["error_zone"] = zone_dropdown.value
|
||||
state["current_step"] += 1
|
||||
update_ui()
|
||||
|
||||
def on_back(e):
|
||||
state["current_step"] -= 1
|
||||
update_ui()
|
||||
|
||||
def on_submit(e):
|
||||
if not validate_step():
|
||||
return
|
||||
state["fix_method"] = fix_method_field.value
|
||||
state["start_at"] = start_at_field.value
|
||||
state["end_at"] = end_at_field.value
|
||||
|
||||
total_problems = list(state["problems"])
|
||||
if custom_problem_field.value and custom_problem_field.value.strip():
|
||||
total_problems.append(custom_problem_field.value.strip())
|
||||
total_reasons = list(state["downtime_reasons"])
|
||||
if custom_reason_field.value and custom_reason_field.value.strip():
|
||||
total_reasons.append(custom_reason_field.value.strip())
|
||||
|
||||
payload = {
|
||||
"factory": state["factory"],
|
||||
"line": state["line"],
|
||||
"operators_name": state["operators_name"],
|
||||
"error_zone": state["error_zone"],
|
||||
"problem": ", ".join(total_problems),
|
||||
"downtime_reason": ", ".join(total_reasons),
|
||||
"fix_method": state["fix_method"],
|
||||
"start_at": state["start_at"],
|
||||
"end_at": state["end_at"],
|
||||
}
|
||||
print("[DEBUG] Отправляем JSON:", payload)
|
||||
show_snackbar("Данные успешно отправлены!", ft.colors.GREEN)
|
||||
# Сброс формы
|
||||
state.update({
|
||||
"current_step": 0,
|
||||
"operators_name": "",
|
||||
"factory": "",
|
||||
"line": "",
|
||||
"error_zone": "",
|
||||
"problems": set(),
|
||||
"downtime_reasons": set(),
|
||||
"custom_problem": "",
|
||||
"custom_reason": "",
|
||||
"fix_method": "",
|
||||
"start_at": "",
|
||||
"end_at": "",
|
||||
"line_options": [],
|
||||
"zone_options": [],
|
||||
"problem_options": [],
|
||||
"reason_options": [],
|
||||
})
|
||||
operators_name_field.value = ""
|
||||
factory_dropdown.value = None
|
||||
line_dropdown.value = None
|
||||
zone_dropdown.value = None
|
||||
fix_method_field.value = ""
|
||||
start_at_field.value = ""
|
||||
end_at_field.value = ""
|
||||
custom_problem_field.value = ""
|
||||
custom_reason_field.value = ""
|
||||
problems_checkboxes.controls.clear()
|
||||
reasons_checkboxes.controls.clear()
|
||||
update_ui()
|
||||
|
||||
next_button.on_click = on_next
|
||||
back_button.on_click = on_back
|
||||
submit_button.on_click = on_submit
|
||||
|
||||
def on_factory_change(e):
|
||||
state["factory"] = factory_dropdown.value
|
||||
update_factory_dependent()
|
||||
factory_dropdown.on_change = on_factory_change
|
||||
|
||||
def on_line_change(e):
|
||||
state["line"] = line_dropdown.value
|
||||
update_line_dependent()
|
||||
line_dropdown.on_change = on_line_change
|
||||
|
||||
def on_zone_change(e):
|
||||
state["error_zone"] = zone_dropdown.value
|
||||
zone_dropdown.on_change = on_zone_change
|
||||
|
||||
page.title = "Журнал простоев (мобильная версия) - Flet"
|
||||
page.add(progress_bar, content_column)
|
||||
update_ui()
|
||||
|
||||
ft.app(target=main)
|
||||
@ -1,3 +0,0 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
@ -1,6 +0,0 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ProductionConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'production'
|
||||
@ -1,27 +0,0 @@
|
||||
# Generated by Django 5.1.5 on 2025-03-21 23:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ProductionPlan',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('date', models.DateField(verbose_name='Дата производства')),
|
||||
('line', models.CharField(max_length=100, verbose_name='Линия')),
|
||||
('product', models.CharField(max_length=100, verbose_name='Продукция')),
|
||||
('production', models.PositiveIntegerField(verbose_name='Плановый выпуск продукции')),
|
||||
('shift', models.CharField(max_length=50, verbose_name='Смена')),
|
||||
('employee', models.CharField(max_length=100, verbose_name='Сотрудник')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Создано')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@ -1,13 +0,0 @@
|
||||
from django.db import models
|
||||
|
||||
class ProductionPlan(models.Model):
|
||||
date = models.DateField(verbose_name="Дата производства")
|
||||
line = models.CharField(max_length=100, verbose_name="Линия")
|
||||
product = models.CharField(max_length=100, verbose_name="Продукция")
|
||||
production = models.PositiveIntegerField(verbose_name="Плановый выпуск продукции")
|
||||
shift = models.CharField(max_length=50, verbose_name="Смена")
|
||||
employee = models.CharField(max_length=100, verbose_name="Сотрудник")
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Создано")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.date} - {self.line} - {self.product}"
|
||||
@ -1,7 +0,0 @@
|
||||
from rest_framework import serializers
|
||||
from .models import ProductionPlan
|
||||
|
||||
class ProductionPlanSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ProductionPlan
|
||||
fields = '__all__'
|
||||
@ -1,3 +0,0 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@ -1,10 +0,0 @@
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from .views import ProductionPlanViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'production', ProductionPlanViewSet, basename='production')
|
||||
|
||||
urlpatterns = [
|
||||
path('calendar/', include(router.urls)),
|
||||
]
|
||||
@ -1,7 +0,0 @@
|
||||
from rest_framework import viewsets
|
||||
from .models import ProductionPlan
|
||||
from .serializers import ProductionPlanSerializer
|
||||
|
||||
class ProductionPlanViewSet(viewsets.ModelViewSet):
|
||||
queryset = ProductionPlan.objects.all().order_by('-created_at')
|
||||
serializer_class = ProductionPlanSerializer
|
||||
BIN
scan/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
scan/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
scan/__pycache__/admin.cpython-312.pyc
Normal file
BIN
scan/__pycache__/admin.cpython-312.pyc
Normal file
Binary file not shown.
BIN
scan/__pycache__/apps.cpython-312.pyc
Normal file
BIN
scan/__pycache__/apps.cpython-312.pyc
Normal file
Binary file not shown.
BIN
scan/__pycache__/models.cpython-312.pyc
Normal file
BIN
scan/__pycache__/models.cpython-312.pyc
Normal file
Binary file not shown.
BIN
scan/__pycache__/serializers.cpython-312.pyc
Normal file
BIN
scan/__pycache__/serializers.cpython-312.pyc
Normal file
Binary file not shown.
BIN
scan/__pycache__/urls.cpython-312.pyc
Normal file
BIN
scan/__pycache__/urls.cpython-312.pyc
Normal file
Binary file not shown.
BIN
scan/__pycache__/views.cpython-312.pyc
Normal file
BIN
scan/__pycache__/views.cpython-312.pyc
Normal file
Binary file not shown.
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.1.5 on 2025-03-21 23:48
|
||||
# Generated by Django 5.1.5 on 2025-03-06 04:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
BIN
scan/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
BIN
scan/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
Binary file not shown.
BIN
scan/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
scan/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
users/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
users/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
users/__pycache__/admin.cpython-312.pyc
Normal file
BIN
users/__pycache__/admin.cpython-312.pyc
Normal file
Binary file not shown.
BIN
users/__pycache__/apps.cpython-312.pyc
Normal file
BIN
users/__pycache__/apps.cpython-312.pyc
Normal file
Binary file not shown.
BIN
users/__pycache__/models.cpython-312.pyc
Normal file
BIN
users/__pycache__/models.cpython-312.pyc
Normal file
Binary file not shown.
BIN
users/__pycache__/serializers.cpython-312.pyc
Normal file
BIN
users/__pycache__/serializers.cpython-312.pyc
Normal file
Binary file not shown.
BIN
users/__pycache__/urls.cpython-312.pyc
Normal file
BIN
users/__pycache__/urls.cpython-312.pyc
Normal file
Binary file not shown.
BIN
users/__pycache__/views.cpython-312.pyc
Normal file
BIN
users/__pycache__/views.cpython-312.pyc
Normal file
Binary file not shown.
BIN
users/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
users/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
@ -5,12 +5,8 @@ from rest_framework_simplejwt.tokens import RefreshToken
|
||||
|
||||
class UserLoginSerializer(serializers.Serializer):
|
||||
username = serializers.CharField()
|
||||
profile_name = serializers.SerializerMethodField() # Добавляем поле для профиля
|
||||
password = serializers.CharField(write_only=True)
|
||||
|
||||
def get_profile_name(self, user):
|
||||
return f"{user.first_name} {user.last_name}".strip() or user.username # Если имя пустое, используем username
|
||||
|
||||
def validate(self, data):
|
||||
from django.contrib.auth import authenticate
|
||||
|
||||
@ -22,7 +18,6 @@ class UserLoginSerializer(serializers.Serializer):
|
||||
|
||||
return {
|
||||
"username": user.username,
|
||||
"profile": self.get_profile_name(user), # Возвращаем профильное имя
|
||||
"access": str(refresh.access_token),
|
||||
"refresh": str(refresh)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user