feat: 添加pum模块
This commit is contained in:
parent
5317c2c715
commit
58aab32859
|
@ -0,0 +1,32 @@
|
|||
# Generated by Django 3.2.12 on 2023-09-13 06:03
|
||||
|
||||
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),
|
||||
('mtm', '0008_mgroup_is_runing'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Process',
|
||||
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='删除标记')),
|
||||
('name', models.CharField(max_length=100, verbose_name='工序名称')),
|
||||
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='process_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='process_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -88,3 +88,12 @@ class Goal(CommonADModel):
|
|||
|
||||
class Meta:
|
||||
unique_together = ("mgroup", "year", "goal_cate")
|
||||
|
||||
|
||||
|
||||
class Process(CommonAModel):
|
||||
"""
|
||||
工序
|
||||
"""
|
||||
name = models.CharField('工序名称', max_length=100)
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PumConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'apps.pum'
|
|
@ -0,0 +1,19 @@
|
|||
from django_filters import rest_framework as filters
|
||||
from apps.pum.models import PuPlanItem, PuPlan
|
||||
|
||||
class PuPlanFilter(filters.FilterSet):
|
||||
class Meta:
|
||||
model = PuPlan
|
||||
fields = {
|
||||
"state": ["exact", "__in"]
|
||||
}
|
||||
|
||||
class PuPlanItemFilter(filters.FilterSet):
|
||||
class Meta:
|
||||
model = PuPlanItem
|
||||
fields = {
|
||||
"material": ["exact"],
|
||||
"pu_plan": ["exact"],
|
||||
"pu_order": ["exact", '__isnull'],
|
||||
"pu_order__state": ["exact"]
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
# Generated by Django 3.2.12 on 2023-09-18 05:42
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('system', '0002_myschedule'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('mtm', '0009_process'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='PuOrder',
|
||||
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='删除标记')),
|
||||
('state', models.PositiveSmallIntegerField(choices=[(10, '创建中'), (20, '已提交'), (30, '到货中'), (40, '已完成')], default=10, help_text="((10, '创建中'), (20, '已提交'), (30, '到货中'), (40, '已完成'))", verbose_name='状态')),
|
||||
('number', models.CharField(blank=True, max_length=20, null=True, verbose_name='订单编号')),
|
||||
('delivery_date', models.DateField(blank=True, null=True, verbose_name='截止到货日期')),
|
||||
('submit_time', models.DateTimeField(blank=True, null=True, verbose_name='提交时间')),
|
||||
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='puorder_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='puorder_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PuPlan',
|
||||
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='删除标记')),
|
||||
('state', models.PositiveSmallIntegerField(choices=[(10, '创建中'), (20, '已提交'), (30, '下单中'), (40, '下单完成'), (50, '已完成')], default=10, help_text="((10, '创建中'), (20, '已提交'), (30, '下单中'), (40, '下单完成'), (50, '已完成'))", verbose_name='状态')),
|
||||
('number', models.CharField(max_length=20, verbose_name='编号')),
|
||||
('name', models.CharField(blank=True, max_length=50, null=True, verbose_name='名称')),
|
||||
('submit_time', models.DateTimeField(blank=True, null=True, verbose_name='提交时间')),
|
||||
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='puplan_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='puplan_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='puplan_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Supplier',
|
||||
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='删除标记')),
|
||||
('name', models.CharField(max_length=50, verbose_name='供应商名称')),
|
||||
('contact', models.CharField(max_length=20, verbose_name='联系人')),
|
||||
('contact_phone', models.CharField(max_length=11, verbose_name='联系电话')),
|
||||
('address', models.CharField(default='', max_length=200, verbose_name='地址')),
|
||||
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='supplier_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='supplier_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='supplier_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PuPlanItem',
|
||||
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='删除标记')),
|
||||
('need_count', models.PositiveIntegerField(verbose_name='所属数量')),
|
||||
('need_date', models.DateField(verbose_name='需求日期')),
|
||||
('note', models.TextField(default='', verbose_name='备注')),
|
||||
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='puplanitem_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='puplanitem_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='所需物料')),
|
||||
('pu_order', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='puplan_item_puorder', to='pum.puorder', verbose_name='关联采购订单')),
|
||||
('pu_plan', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='item_puplan', to='pum.puplan', verbose_name='采购计划')),
|
||||
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='puplanitem_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PuOrderItem',
|
||||
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='删除标记')),
|
||||
('count', models.PositiveIntegerField(default=0, verbose_name='所需数量')),
|
||||
('delivered_count', models.PositiveIntegerField(default=0, verbose_name='已到货数量')),
|
||||
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='物料')),
|
||||
('pu_order', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='item_puorder', to='pum.puorder', verbose_name='关联采购订单')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='puorder',
|
||||
name='supplier',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pum.supplier', verbose_name='供应商'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='puorder',
|
||||
name='update_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='puorder_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,81 @@
|
|||
from django.db import models
|
||||
from apps.utils.models import CommonBModel, BaseModel, CommonBDModel
|
||||
from apps.mtm.models import Material
|
||||
|
||||
|
||||
# Create your models here.
|
||||
class Supplier(CommonBModel):
|
||||
"""
|
||||
供应商
|
||||
"""
|
||||
name = models.CharField('供应商名称', max_length=50)
|
||||
contact = models.CharField('联系人', max_length=20)
|
||||
contact_phone = models.CharField('联系电话', max_length=11)
|
||||
address = models.CharField('地址', max_length=200, default='')
|
||||
|
||||
|
||||
class PuPlan(CommonBModel):
|
||||
"""
|
||||
采购计划
|
||||
"""
|
||||
PUPLAN_CREATE = 10
|
||||
PUPLAN_SUBMITED = 20
|
||||
PUPLAN_ORDERING = 30
|
||||
PUPLAN_ORDERED = 40
|
||||
PUPLAN_DONE = 50
|
||||
PUPLAN_STATES = (
|
||||
(PUPLAN_CREATE, '创建中'),
|
||||
(PUPLAN_SUBMITED, '已提交'),
|
||||
(PUPLAN_ORDERING, '下单中'),
|
||||
(PUPLAN_ORDERED, '下单完成'),
|
||||
(PUPLAN_DONE, '已完成'),
|
||||
)
|
||||
state = models.PositiveSmallIntegerField('状态', choices=PUPLAN_STATES, default=10, help_text=str(PUPLAN_STATES))
|
||||
number = models.CharField('编号', max_length=20)
|
||||
name = models.CharField('名称', max_length=50, null=True, blank=True)
|
||||
submit_time = models.DateTimeField('提交时间', null=True, blank=True)
|
||||
|
||||
|
||||
|
||||
class PuOrder(CommonBModel):
|
||||
"""
|
||||
采购订单
|
||||
"""
|
||||
PUORDER_CREATE = 10
|
||||
PUORDER_SUBMITED = 20
|
||||
PUORDER_SHIP = 30
|
||||
PUORDER_DONE = 40
|
||||
PUORDER_STATES = (
|
||||
(PUORDER_CREATE, '创建中'),
|
||||
(PUORDER_SUBMITED, '已提交'),
|
||||
(PUORDER_SHIP, '到货中'),
|
||||
(PUORDER_DONE, '已完成'),
|
||||
)
|
||||
state = models.PositiveSmallIntegerField('状态', choices=PUORDER_STATES, default=10, help_text=str(PUORDER_STATES))
|
||||
number = models.CharField('订单编号', max_length=20, null=True, blank=True)
|
||||
supplier = models.ForeignKey(Supplier, verbose_name='供应商', on_delete=models.CASCADE)
|
||||
delivery_date = models.DateField('截止到货日期', null=True, blank=True)
|
||||
submit_time = models.DateTimeField('提交时间', null=True, blank=True)
|
||||
|
||||
|
||||
class PuOrderItem(BaseModel):
|
||||
material = models.ForeignKey(Material, verbose_name='物料', on_delete=models.CASCADE)
|
||||
count = models.PositiveIntegerField('所需数量', default=0)
|
||||
delivered_count = models.PositiveIntegerField('已到货数量', default=0)
|
||||
pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单',
|
||||
on_delete=models.CASCADE, null=True, blank=True, related_name='item_puorder')
|
||||
|
||||
|
||||
|
||||
class PuPlanItem(CommonBDModel):
|
||||
"""
|
||||
采购计划明细(因为各部门填写所以需要belong_dept字段)
|
||||
"""
|
||||
material = models.ForeignKey(Material, verbose_name='所需物料', on_delete=models.CASCADE)
|
||||
need_count = models.PositiveIntegerField('所属数量')
|
||||
need_date = models.DateField('需求日期')
|
||||
note = models.TextField('备注', default='')
|
||||
pu_plan = models.ForeignKey(PuPlan, verbose_name='采购计划', on_delete=models.CASCADE,
|
||||
null=True, blank=True, related_name='item_puplan')
|
||||
pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单',
|
||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='puplan_item_puorder')
|
|
@ -0,0 +1,100 @@
|
|||
from rest_framework import serializers
|
||||
from apps.utils.serializers import CustomModelSerializer
|
||||
from apps.utils.constants import EXCLUDE_FIELDS_DEPT, EXCLUDE_FIELDS_BASE
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from apps.pum.models import Supplier, PuPlan, PuPlanItem, PuOrder, PuOrderItem
|
||||
from apps.mtm.serializers import MaterialSerializer
|
||||
|
||||
class SupplierSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Supplier
|
||||
fields = '__all__'
|
||||
read_only_fields = EXCLUDE_FIELDS_DEPT
|
||||
|
||||
|
||||
class PuPlanSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = PuPlan
|
||||
fields = '__all__'
|
||||
read_only_fields = EXCLUDE_FIELDS_DEPT + ['state']
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
if instance.state != PuPlan.PUPLAN_CREATE:
|
||||
raise ValidationError('该状态下不可编辑')
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
class PuPlanItemSerializer(CustomModelSerializer):
|
||||
material_ = MaterialSerializer(source='material', read_only=True)
|
||||
belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True)
|
||||
class Meata:
|
||||
model = PuPlanItem
|
||||
fields = '__all__'
|
||||
read_only_fields = EXCLUDE_FIELDS_DEPT + ['pu_order']
|
||||
|
||||
def create(self, validated_data):
|
||||
pu_plan = validated_data['pu_plan']
|
||||
if pu_plan.state != PuPlan.PUPLAN_CREATE:
|
||||
raise ValidationError('该状态下不可添加需求')
|
||||
material = validated_data['material']
|
||||
user = self.context['request'].user
|
||||
if PuPlanItem.objects.filter(material=material, belong_dept=user.belong_dept).exists():
|
||||
raise ValidationError('同部门已提交该物料需求,请确认!')
|
||||
return super().create(validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
validated_data.pop('pu_plan')
|
||||
pu_plan = instance.pu_plan
|
||||
if pu_plan.state != PuPlan.PUPLAN_CREATE:
|
||||
raise ValidationError('该状态下不可编辑需求')
|
||||
material = validated_data['material']
|
||||
user = self.context['request'].user
|
||||
if instance.create_by != user:
|
||||
raise ValidationError('非创建人不可编辑')
|
||||
if PuPlanItem.objects.exclude(id=instance.id).filter(material=material, belong_dept=user.belong_dept).exists():
|
||||
raise ValidationError('同部门已提交该物料需求,请确认!')
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
class PuOrderSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = PuOrder
|
||||
fields = '__all__'
|
||||
read_only_fields = EXCLUDE_FIELDS_DEPT + ['state']
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
validated_data.pop('supplier')
|
||||
if instance.steate != PuOrder.PUORDER_CREATE:
|
||||
raise ValidationError('该状态下不可编辑')
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
class PuOrderItemSerializer(CustomModelSerializer):
|
||||
material_ = MaterialSerializer(source='material', read_only=True)
|
||||
class Meta:
|
||||
model = PuOrderItem
|
||||
fields = '__all__'
|
||||
read_only_fields = EXCLUDE_FIELDS_BASE + ['delivered_count']
|
||||
|
||||
def create(self, validated_data):
|
||||
pu_order = validated_data['pu_order']
|
||||
material = validated_data['material']
|
||||
if pu_order.state != PuOrder.PUORDER_CREATE:
|
||||
raise ValidationError('采购订单该状态下不可添加明细')
|
||||
if PuOrder.objects.filter(pu_order=pu_order, material=material).exists():
|
||||
raise ValidationError('该物料已添加')
|
||||
return super().create(validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
validated_data.pop('material')
|
||||
validated_data.pop('pu_order')
|
||||
pu_order = instance.pu_order
|
||||
if pu_order.state != PuOrder.PUORDER_CREATE:
|
||||
raise ValidationError('采购订单该状态下不可编辑')
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
class AddSerializer(serializers.Serializer):
|
||||
pu_order = serializers.PrimaryKeyRelatedField(label='采购订单ID', queryset=PuOrder.objects.all())
|
||||
pu_planitems = serializers.PrimaryKeyRelatedField(label='计划明细ID', queryset=PuPlanItem.objects.all(), many=True)
|
|
@ -0,0 +1,19 @@
|
|||
from apps.pum.models import PuOrderItem, PuPlan, PuPlanItem, PuOrder
|
||||
|
||||
class PumService:
|
||||
|
||||
def change_puplan_state_when_puorder_sumbit(puorder: PuOrder):
|
||||
puplanIds = PuPlanItem.objects.filter(pu_order=puorder).values_list('pu_plan', flat=True)
|
||||
for id in puplanIds:
|
||||
puplan = PuPlan.objects.get(id=id)
|
||||
state = puplan.state
|
||||
if PuPlanItem.objects.filter(pu_plan=puplan).count() == PuPlan.objects.filter(pu_plan=puplan, pu_order__state__gte=PuOrder.PUORDER_SUBMITED).count():
|
||||
state = PuPlan.PUPLAN_ORDERED
|
||||
else:
|
||||
state = PuPlan.PUPLAN_ORDERING
|
||||
puplan.state = state
|
||||
puplan.save()
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -0,0 +1,16 @@
|
|||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from apps.pum.views import (SupplierViewSet, PuPlanViewSet, PuPlanItemViewSet, PuOrderViewSet, PuOrderItemViewSet)
|
||||
|
||||
API_BASE_URL = 'api/pum/'
|
||||
HTML_BASE_URL = 'pum/'
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register('supplier', SupplierViewSet, basename='supplier')
|
||||
router.register('pu_plan', PuPlanViewSet, basename='pu_plan')
|
||||
router.register('pu_planitem', PuPlanItemViewSet, basename='pu_planitem')
|
||||
router.register('pu_order', PuOrderViewSet, basename='pu_order')
|
||||
router.register('pu_orderitem', PuOrderItemViewSet, basename='pu_orderitem')
|
||||
urlpatterns = [
|
||||
path(API_BASE_URL, include(router.urls)),
|
||||
]
|
|
@ -0,0 +1,155 @@
|
|||
from django.shortcuts import render
|
||||
from apps.pum.models import Supplier, PuPlan, PuPlanItem, PuOrder, PuOrderItem
|
||||
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
|
||||
from apps.pum.serializers import (SupplierSerializer, PuPlanSerializer, PuPlanItemSerializer,
|
||||
PuOrderSerializer, PuOrderItemSerializer, AddSerializer)
|
||||
from rest_framework.exceptions import ParseError, PermissionDenied
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework import serializers
|
||||
from apps.pum.filters import PuPlanItemFilter
|
||||
from django.db import transaction
|
||||
from rest_framework.response import Response
|
||||
from django.utils import timezone
|
||||
from apps.pum.services import PumService
|
||||
# Create your views here.
|
||||
|
||||
|
||||
class SupplierViewSet(CustomModelViewSet):
|
||||
queryset = Supplier.objects.all()
|
||||
serializer_class = SupplierSerializer
|
||||
search_fields = ['name', 'contact']
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
if PuOrder.objects.filter(supplier=instance).exists():
|
||||
raise ParseError('该供应商存在采购订单不可删除')
|
||||
instance.delete()
|
||||
|
||||
|
||||
class PuPlanViewSet(CustomModelViewSet):
|
||||
queryset = PuPlan.objects.all()
|
||||
serializer_class = PuPlanSerializer
|
||||
search_fields = ['name', 'number']
|
||||
filterset_fields = ['state']
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
if PuPlan.objects.filter(pu_plan=instance).exists():
|
||||
raise ParseError('该计划存在明细不可删除')
|
||||
return super().perform_destroy(instance)
|
||||
|
||||
@action(methods=['post'], detail=True, perms_map={'post': 'pu_plan.update'}, serializer_class=serializers.Serializer)
|
||||
def submit(self, request, *args, **kwargs):
|
||||
"""提交采购计划
|
||||
|
||||
提交采购计划
|
||||
"""
|
||||
puplan = self.get_object()
|
||||
user = request.user
|
||||
if puplan.create_by != user:
|
||||
raise PermissionDenied('非创建人不可提交')
|
||||
if puplan.state != PuPlan.PUPLAN_CREATE:
|
||||
raise ParseError('采购计划状态异常')
|
||||
puplan.submit_time = timezone.now()
|
||||
puplan.state = PuPlan.PUPLAN_SUBMITED
|
||||
puplan.save()
|
||||
return Response()
|
||||
|
||||
class PuPlanItemViewSet(CustomModelViewSet):
|
||||
queryset = PuPlanItem.objects.all()
|
||||
serializer_class = PuPlanItemSerializer
|
||||
filterset_class = PuPlanItemFilter
|
||||
ordering_fields = ['create_time', 'material', 'need_date', 'need_count']
|
||||
ordering = ['create_time']
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
user = self.request.user
|
||||
pu_plan = instance.pu_plan
|
||||
if pu_plan.state == PuPlan.PUPLAN_CREATE and user != instance.create_by:
|
||||
raise ParseError('非创建人不可删除')
|
||||
elif instance.pu_order is not None:
|
||||
raise ParseError('存在采购订单不可删除')
|
||||
return super().perform_destroy(instance)
|
||||
|
||||
|
||||
class PuOrderViewSet(CustomModelViewSet):
|
||||
queryset = PuOrder.objects.all()
|
||||
serializer_class = PuOrderSerializer
|
||||
filterset_fields = ['state', 'supplier']
|
||||
search_fields = ['number', 'supplier__name']
|
||||
|
||||
@transaction.atomic
|
||||
def perform_destroy(self, instance):
|
||||
if instance.state != PuOrder.PUORDER_CREATE:
|
||||
raise ParseError('采购订单非创建中不可删除')
|
||||
instance.delete(soft=False)
|
||||
|
||||
@action(methods=['post'], detail=True, perms_map={'post': 'pu_order.update'}, serializer_class=serializers.Serializer)
|
||||
@transaction.atomic
|
||||
def submit(self, request, *args, **kwargs):
|
||||
"""提交采购订单
|
||||
|
||||
提交采购订单
|
||||
"""
|
||||
puorder = self.get_object()
|
||||
user = request.user
|
||||
if puorder.delivery_date is None or puorder.number is None:
|
||||
raise ParseError('订单信息不全')
|
||||
if puorder.create_by != user:
|
||||
raise PermissionDenied('非创建人不可提交')
|
||||
if puorder.state != PuOrder.PUPLAN_CREATE:
|
||||
raise ParseError('采购计划状态异常')
|
||||
puorder.submit_time = timezone.now()
|
||||
puorder.state = PuPlan.PUPLAN_SUBMITED
|
||||
puorder.save()
|
||||
PumService.change_puplan_state_when_puorder_sumbit(puorder)
|
||||
return Response()
|
||||
|
||||
|
||||
class PuOrderItemViewSet(CustomModelViewSet):
|
||||
queryset = PuOrderItem.objects.all()
|
||||
serializer_class = PuOrderItemSerializer
|
||||
filterset_fields = ['material', 'pu_order']
|
||||
ordering = ['create_time']
|
||||
|
||||
@transaction.atomic
|
||||
def perform_destroy(self, instance):
|
||||
pu_order = instance.pu_order
|
||||
if pu_order.state != PuOrder.PUORDER_CREATE:
|
||||
raise ParseError('采购订单非创建中不可删除')
|
||||
instance.delete()
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post': 'pu_orderitem.create'}, serializer_class=AddSerializer)
|
||||
@transaction.atomic
|
||||
def add_from_planitems(self, request, *args, **kwargs):
|
||||
"""从计划明细创建/变更采购订单明细
|
||||
|
||||
从计划明细创建/变更采购订单明细
|
||||
"""
|
||||
data = request.data
|
||||
sr = AddSerializer(data=data)
|
||||
sr.is_valid(raise_exception=True)
|
||||
vdata = sr.validated_data
|
||||
puorder = vdata['pu_order']
|
||||
if puorder.state != PuOrder.PUORDER_CREATE:
|
||||
raise ParseError('该采购订单不可用')
|
||||
puplanitems = PuPlanItem.objects.filter(id__in=vdata['pu_planitems'])
|
||||
for item in puplanitems:
|
||||
if item.pu_plan.state == PuPlan.PUPLAN_CREATE:
|
||||
raise ParseError('存在不可选择的计划明细')
|
||||
if item.pu_order and item.pu_order.state != PuOrder.PUORDER_CREATE:
|
||||
raise ParseError('存在计划明细已指定进行中的采购订单')
|
||||
puorderitem, is_created = PuOrderItem.objects.get_or_create(
|
||||
pu_order = puorder, material=item.material,
|
||||
defaults={'pu_order': puorder, 'material': item.material, 'count': item.need_count}
|
||||
)
|
||||
if not is_created:
|
||||
puorderitem.count = puorderitem.count + item.need_count
|
||||
puorderitem.save()
|
||||
if puorder.delivery_date is None:
|
||||
puorder.delivery_date = item.need_date
|
||||
elif item.need_date < puorder.delivery_data:
|
||||
puorder.delivery_date = item.need_date
|
||||
puorder.save()
|
||||
item.pu_order = puorder
|
||||
item.save()
|
||||
return Response()
|
||||
|
|
@ -105,7 +105,8 @@ INSTALLED_APPS = [
|
|||
'apps.qm',
|
||||
'apps.enm',
|
||||
'apps.fim',
|
||||
'apps.inm'
|
||||
'apps.inm',
|
||||
'apps.pum'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
|
|
@ -62,6 +62,7 @@ urlpatterns = [
|
|||
path('', include('apps.enm.urls')),
|
||||
path('', include('apps.fim.urls')),
|
||||
path('', include('apps.inm.urls')),
|
||||
path('', include('apps.pum.urls')),
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue