From 949620809aea29a56b36acc6849536f4d257932f Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Tue, 21 Apr 2026 16:05:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=85=89=E8=8A=AF=E7=A7=91=E6=8A=80=20?= =?UTF-8?q?=E4=B8=BB=E8=A6=81=E4=BF=AE=E6=94=B9=E9=87=87=E8=B4=AD=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mpr/migrations/0006_auto_20260421_1427.py | 46 +++++++++++++++++++ apps/mpr/models.py | 24 ++++++++-- apps/mpr/serializers.py | 10 ++++ apps/mpr/urls.py | 2 + apps/mpr/views.py | 16 +++++++ 5 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 apps/mpr/migrations/0006_auto_20260421_1427.py diff --git a/apps/mpr/migrations/0006_auto_20260421_1427.py b/apps/mpr/migrations/0006_auto_20260421_1427.py new file mode 100644 index 00000000..f6abeefd --- /dev/null +++ b/apps/mpr/migrations/0006_auto_20260421_1427.py @@ -0,0 +1,46 @@ +# Generated by Django 3.2.12 on 2026-04-21 06:27 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('system', '0007_alter_dept_create_by_alter_dept_third_info_and_more'), + ('mpr', '0005_warehousestock_status'), + ] + + operations = [ + migrations.CreateModel( + name='WareHouse', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('number', models.CharField(max_length=20, verbose_name='库房编号')), + ('name', models.CharField(max_length=20, verbose_name='库房名称')), + ('place', models.CharField(max_length=50, verbose_name='具体地点')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mpr_warehouse_belong_dept', to='system.dept', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mpr_warehouse_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mpr_warehouse_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AlterField( + model_name='warehouseentry', + name='warehouse', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='entries', to='mpr.warehouse', verbose_name='库房'), + ), + migrations.AlterField( + model_name='warehousestock', + name='warehouse', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='mpr_stocks', to='mpr.warehouse', verbose_name='库房'), + ), + ] diff --git a/apps/mpr/models.py b/apps/mpr/models.py index 785bf4cb..67411e08 100644 --- a/apps/mpr/models.py +++ b/apps/mpr/models.py @@ -1,9 +1,27 @@ from django.db import models -from apps.utils.models import BaseModel, CommonBDModel +from apps.utils.models import BaseModel, CommonBDModel, CommonBModel from datetime import datetime from django.db.models import Max, Sum +class WareHouse(CommonBModel): + """ + TN:库房信息 + """ + number = models.CharField('库房编号', max_length=20) + name = models.CharField('库房名称', max_length=20) + place = models.CharField('具体地点', max_length=50) + create_by = models.ForeignKey( + 'system.user', null=True, blank=True, on_delete=models.SET_NULL, + verbose_name='创建人', related_name='mpr_warehouse_create_by') + update_by = models.ForeignKey( + 'system.user', null=True, blank=True, on_delete=models.SET_NULL, + verbose_name='最后编辑人', related_name='mpr_warehouse_update_by') + belong_dept = models.ForeignKey( + 'system.dept', null=True, blank=True, on_delete=models.SET_NULL, + verbose_name='所属部门', related_name='mpr_warehouse_belong_dept') + + def _get_number(model_cls): today_str = datetime.now().strftime('%Y%m%d') prefix = model_cls.PREFIX @@ -77,7 +95,7 @@ class WarehouseEntry(CommonBDModel): number = models.CharField('编号', max_length=20, unique=True) warehouse = models.ForeignKey( - 'inm.WareHouse', verbose_name='仓库', + WareHouse, verbose_name='库房', on_delete=models.CASCADE, related_name='entries') entry_date = models.DateField('入库日期', null=True, blank=True) entry_type = models.CharField('入库类型', max_length=20, choices=ENTRY_TYPE_CHOICES, default='raw_normal') @@ -123,7 +141,7 @@ class WarehouseStock(BaseModel): ) warehouse = models.ForeignKey( - 'inm.WareHouse', verbose_name='仓库', + WareHouse, verbose_name='库房', on_delete=models.CASCADE, related_name='mpr_stocks') entry = models.ForeignKey( WarehouseEntry, verbose_name='来源入库单', diff --git a/apps/mpr/serializers.py b/apps/mpr/serializers.py index 8f49cc8a..41f70376 100644 --- a/apps/mpr/serializers.py +++ b/apps/mpr/serializers.py @@ -7,10 +7,20 @@ from apps.mpr.models import ( PurchaseRequisition, PurchaseRequisitionItem, WarehouseEntry, WarehouseEntryItem, WarehouseStock, MaterialRequisition, MaterialRequisitionItem, + WareHouse, ) from apps.wf.serializers import TicketSimpleSerializer +# ========== 库房 ========== + +class WareHouseSerializer(CustomModelSerializer): + class Meta: + model = WareHouse + fields = '__all__' + read_only_fields = ['create_time', 'update_time', 'is_deleted'] + + # ========== 物资申购单 ========== class PurchaseRequisitionItemSerializer(CustomModelSerializer): diff --git a/apps/mpr/urls.py b/apps/mpr/urls.py index f6191e71..9cbe8a2e 100644 --- a/apps/mpr/urls.py +++ b/apps/mpr/urls.py @@ -1,6 +1,7 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter from apps.mpr.views import ( + WareHouseViewSet, PurchaseRequisitionViewSet, PurchaseRequisitionItemViewSet, WarehouseEntryViewSet, WarehouseEntryItemViewSet, WarehouseStockViewSet, @@ -10,6 +11,7 @@ from apps.mpr.views import ( API_BASE_URL = 'api/mpr/' router = DefaultRouter() +router.register('warehouse', WareHouseViewSet, basename='mpr_warehouse') router.register('requisition', PurchaseRequisitionViewSet, basename='requisition') router.register('requisition_item', PurchaseRequisitionItemViewSet, basename='requisition_item') router.register('warehouse_entry', WarehouseEntryViewSet, basename='warehouse_entry') diff --git a/apps/mpr/views.py b/apps/mpr/views.py index c00848f1..1e580a35 100644 --- a/apps/mpr/views.py +++ b/apps/mpr/views.py @@ -8,8 +8,10 @@ from apps.mpr.models import ( PurchaseRequisition, PurchaseRequisitionItem, WarehouseEntry, WarehouseEntryItem, WarehouseStock, MaterialRequisition, MaterialRequisitionItem, + WareHouse, ) from apps.mpr.serializers import ( + WareHouseSerializer, PurchaseRequisitionListSerializer, PurchaseRequisitionDetailSerializer, PurchaseRequisitionCreateSerializer, @@ -30,6 +32,20 @@ from apps.mpr.filters import ( ) +class WareHouseViewSet(CustomModelViewSet): + """ + 库房管理 + """ + queryset = WareHouse.objects.all() + serializer_class = WareHouseSerializer + search_fields = ['number', 'name', 'place'] + ordering = '-create_time' + perms_map = { + 'get': '*', 'post': 'warehouse.create', + 'put': 'warehouse.update', 'delete': 'warehouse.delete', + } + + class PurchaseRequisitionViewSet(TicketMixin, CustomModelViewSet): """ 物资申购单