feat: 采购计划和订单增加单价和总价

This commit is contained in:
caoqianming 2024-07-31 19:18:51 +08:00
parent 9e26f416a5
commit 3f62e8709f
5 changed files with 93 additions and 11 deletions

View File

@ -0,0 +1,43 @@
# Generated by Django 3.2.12 on 2024-07-31 10:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pum', '0007_supplier_number'),
]
operations = [
migrations.AddField(
model_name='puorder',
name='total_price',
field=models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True, verbose_name='总价'),
),
migrations.AddField(
model_name='puorderitem',
name='total_price',
field=models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True, verbose_name='总价'),
),
migrations.AddField(
model_name='puorderitem',
name='unit_price',
field=models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True, verbose_name='单价'),
),
migrations.AddField(
model_name='puplan',
name='total_price',
field=models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True, verbose_name='总价'),
),
migrations.AddField(
model_name='puplanitem',
name='total_price',
field=models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True, verbose_name='总价'),
),
migrations.AddField(
model_name='puplanitem',
name='unit_price',
field=models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True, verbose_name='单价'),
),
]

View File

@ -39,6 +39,7 @@ class PuPlan(CommonBModel):
submit_time = models.DateTimeField('提交时间', null=True, blank=True) submit_time = models.DateTimeField('提交时间', null=True, blank=True)
submit_user = models.ForeignKey( submit_user = models.ForeignKey(
'system.user', verbose_name='提交人', related_name='submit_user_puplan', on_delete=models.CASCADE, null=True, blank=True) 'system.user', verbose_name='提交人', related_name='submit_user_puplan', on_delete=models.CASCADE, null=True, blank=True)
total_price = models.DecimalField('总价', max_digits=14, decimal_places=2, null=True, blank=True)
class PuOrder(CommonBModel): class PuOrder(CommonBModel):
@ -66,6 +67,7 @@ class PuOrder(CommonBModel):
'system.user', verbose_name='提交人', related_name='submit_user_puorder', on_delete=models.CASCADE, null=True, blank=True) 'system.user', verbose_name='提交人', related_name='submit_user_puorder', on_delete=models.CASCADE, null=True, blank=True)
materials = models.ManyToManyField( materials = models.ManyToManyField(
Material, verbose_name='多个物料', blank=True, through='pum.puorderitem', related_name='pu_order_materials') Material, verbose_name='多个物料', blank=True, through='pum.puorderitem', related_name='pu_order_materials')
total_price = models.DecimalField('总价', max_digits=14, decimal_places=2, null=True, blank=True)
class PuOrderItem(BaseModel): class PuOrderItem(BaseModel):
@ -73,6 +75,8 @@ class PuOrderItem(BaseModel):
Material, verbose_name='物料', on_delete=models.CASCADE, related_name='pu_orderitem_material') Material, verbose_name='物料', on_delete=models.CASCADE, related_name='pu_orderitem_material')
count = models.PositiveIntegerField('所需数量', default=0) count = models.PositiveIntegerField('所需数量', default=0)
delivered_count = models.PositiveIntegerField('已到货数量', default=0) delivered_count = models.PositiveIntegerField('已到货数量', default=0)
unit_price = models.DecimalField('单价', max_digits=14, decimal_places=2, null=True, blank=True)
total_price = models.DecimalField('总价', max_digits=14, decimal_places=2, null=True, blank=True)
pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单', pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单',
on_delete=models.CASCADE, null=True, blank=True, related_name='item_puorder') on_delete=models.CASCADE, null=True, blank=True, related_name='item_puorder')
@ -85,6 +89,8 @@ class PuPlanItem(CommonBDModel):
Material, verbose_name='所需物料', on_delete=models.CASCADE) Material, verbose_name='所需物料', on_delete=models.CASCADE)
need_count = models.PositiveIntegerField('所属数量') need_count = models.PositiveIntegerField('所属数量')
need_date = models.DateField('需求日期') need_date = models.DateField('需求日期')
unit_price = models.DecimalField('单价', max_digits=14, decimal_places=2, null=True, blank=True)
total_price = models.DecimalField('总价', max_digits=14, decimal_places=2, null=True, blank=True)
note = models.TextField('备注', default='') note = models.TextField('备注', default='')
pu_plan = models.ForeignKey(PuPlan, verbose_name='采购计划', on_delete=models.CASCADE, pu_plan = models.ForeignKey(PuPlan, verbose_name='采购计划', on_delete=models.CASCADE,
null=True, blank=True, related_name='item_puplan') null=True, blank=True, related_name='item_puplan')

View File

@ -5,6 +5,8 @@ from rest_framework.exceptions import ValidationError
from apps.pum.models import Supplier, PuPlan, PuPlanItem, PuOrder, PuOrderItem from apps.pum.models import Supplier, PuPlan, PuPlanItem, PuOrder, PuOrderItem
from apps.mtm.serializers import MaterialSerializer, MaterialSimpleSerializer from apps.mtm.serializers import MaterialSerializer, MaterialSimpleSerializer
from django.db import transaction
from .services import PumService
class SupplierSerializer(CustomModelSerializer): class SupplierSerializer(CustomModelSerializer):
@ -18,7 +20,7 @@ class PuPlanSerializer(CustomModelSerializer):
class Meta: class Meta:
model = PuPlan model = PuPlan
fields = '__all__' fields = '__all__'
read_only_fields = EXCLUDE_FIELDS_DEPT + ['state', 'submit_time'] read_only_fields = EXCLUDE_FIELDS_DEPT + ['state', 'submit_time', 'total_price']
def update(self, instance, validated_data): def update(self, instance, validated_data):
if instance.state != PuPlan.PUPLAN_CREATE: if instance.state != PuPlan.PUPLAN_CREATE:
@ -41,6 +43,7 @@ class PuPlanItemSerializer(CustomModelSerializer):
fields = '__all__' fields = '__all__'
read_only_fields = EXCLUDE_FIELDS + ['pu_order'] read_only_fields = EXCLUDE_FIELDS + ['pu_order']
@transaction.atomic
def create(self, validated_data): def create(self, validated_data):
pu_plan = validated_data['pu_plan'] pu_plan = validated_data['pu_plan']
if pu_plan.state != PuPlan.PUPLAN_CREATE: if pu_plan.state != PuPlan.PUPLAN_CREATE:
@ -49,7 +52,9 @@ class PuPlanItemSerializer(CustomModelSerializer):
self.complete_belong_dept(validated_data) self.complete_belong_dept(validated_data)
if PuPlanItem.objects.filter(material=material, belong_dept=validated_data['belong_dept']).exists(): if PuPlanItem.objects.filter(material=material, belong_dept=validated_data['belong_dept']).exists():
raise ValidationError('同部门已提交该物料需求,请确认!') raise ValidationError('同部门已提交该物料需求,请确认!')
return super().create(validated_data) ins = super().create(validated_data)
PumService.cal_pu_plan_total_price(pu_plan)
return ins
def complete_belong_dept(self, validated_data): def complete_belong_dept(self, validated_data):
belong_dept = validated_data.get('belong_dept', None) belong_dept = validated_data.get('belong_dept', None)
@ -59,7 +64,8 @@ class PuPlanItemSerializer(CustomModelSerializer):
raise ValidationError('所属部门不可为空') raise ValidationError('所属部门不可为空')
else: else:
validated_data['belong_dept'] = belong_dept validated_data['belong_dept'] = belong_dept
@transaction.atomic
def update(self, instance, validated_data): def update(self, instance, validated_data):
validated_data.pop('pu_plan') validated_data.pop('pu_plan')
pu_plan = instance.pu_plan pu_plan = instance.pu_plan
@ -73,7 +79,9 @@ class PuPlanItemSerializer(CustomModelSerializer):
self.complete_belong_dept(validated_data) self.complete_belong_dept(validated_data)
if PuPlanItem.objects.exclude(id=instance.id).filter(material=material, belong_dept=validated_data['belong_dept']).exists(): if PuPlanItem.objects.exclude(id=instance.id).filter(material=material, belong_dept=validated_data['belong_dept']).exists():
raise ValidationError('同部门已提交该物料需求,请确认!') raise ValidationError('同部门已提交该物料需求,请确认!')
return super().update(instance, validated_data) ins = super().update(instance, validated_data)
PumService.cal_pu_plan_total_price(pu_plan)
return ins
class PuOrderSerializer(CustomModelSerializer): class PuOrderSerializer(CustomModelSerializer):
@ -89,7 +97,7 @@ class PuOrderSerializer(CustomModelSerializer):
class Meta: class Meta:
model = PuOrder model = PuOrder
fields = '__all__' fields = '__all__'
read_only_fields = EXCLUDE_FIELDS_DEPT + ['state', 'submit_time'] read_only_fields = EXCLUDE_FIELDS_DEPT + ['state', 'submit_time', 'total_price']
def update(self, instance, validated_data): def update(self, instance, validated_data):
validated_data.pop('supplier') validated_data.pop('supplier')
@ -106,6 +114,7 @@ class PuOrderItemSerializer(CustomModelSerializer):
fields = '__all__' fields = '__all__'
read_only_fields = EXCLUDE_FIELDS_BASE + ['delivered_count'] read_only_fields = EXCLUDE_FIELDS_BASE + ['delivered_count']
@transaction.atomic
def create(self, validated_data): def create(self, validated_data):
pu_order = validated_data['pu_order'] pu_order = validated_data['pu_order']
material = validated_data['material'] material = validated_data['material']
@ -113,15 +122,20 @@ class PuOrderItemSerializer(CustomModelSerializer):
raise ValidationError('采购订单该状态下不可添加明细') raise ValidationError('采购订单该状态下不可添加明细')
if PuOrderItem.objects.filter(pu_order=pu_order, material=material).exists(): if PuOrderItem.objects.filter(pu_order=pu_order, material=material).exists():
raise ValidationError('该物料已添加') raise ValidationError('该物料已添加')
return super().create(validated_data) ins = super().create(validated_data)
PumService.cal_pu_order_total_price(pu_order)
return ins
@transaction.atomic
def update(self, instance, validated_data): def update(self, instance, validated_data):
validated_data.pop('material') validated_data.pop('material')
validated_data.pop('pu_order') validated_data.pop('pu_order')
pu_order = instance.pu_order pu_order = instance.pu_order
if pu_order.state != PuOrder.PUORDER_CREATE: if pu_order.state != PuOrder.PUORDER_CREATE:
raise ValidationError('采购订单该状态下不可编辑') raise ValidationError('采购订单该状态下不可编辑')
return super().update(instance, validated_data) ins = super().update(instance, validated_data)
PumService.cal_pu_order_total_price(pu_order)
return ins
class AddSerializer(serializers.Serializer): class AddSerializer(serializers.Serializer):

View File

@ -1,11 +1,21 @@
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from apps.pum.models import PuOrderItem, PuPlan, PuPlanItem, PuOrder from apps.pum.models import PuOrderItem, PuPlan, PuPlanItem, PuOrder
from django.db.models import F from django.db.models import F, Sum
from apps.inm.models import MIO, MIOItem from apps.inm.models import MIO, MIOItem
class PumService: class PumService:
def cal_pu_order_total_price(puorder: PuOrder):
total_price = PuOrderItem.objects.filter(pu_order=puorder).aggregate(total=Sum("total_price"))["total"] or 0
puorder.total_price = total_price
puorder.save()
def cal_pu_plan_total_price(puplan: PuPlan):
total_price = PuPlanItem.objects.filter(pu_plan=puplan).aggregate(total=Sum("total_price"))["total"] or 0
puplan.total_price = total_price
puplan.save()
def change_puplan_state_when_puorder_sumbit(puorder: PuOrder): def change_puplan_state_when_puorder_sumbit(puorder: PuOrder):
puplanIds = PuPlanItem.objects.filter( puplanIds = PuPlanItem.objects.filter(
pu_order=puorder).values_list('pu_plan', flat=True) pu_order=puorder).values_list('pu_plan', flat=True)

View File

@ -45,7 +45,7 @@ class PuPlanViewSet(CustomModelViewSet):
def perform_destroy(self, instance): def perform_destroy(self, instance):
if PuPlanItem.objects.filter(pu_plan=instance).exists(): if PuPlanItem.objects.filter(pu_plan=instance).exists():
raise ParseError('该计划存在明细不可删除') raise ParseError('该计划存在明细不可删除')
return super().perform_destroy(instance) instance.delete(soft=False)
@action(methods=['post'], detail=True, perms_map={'post': 'pu_plan.submit'}, serializer_class=serializers.Serializer) @action(methods=['post'], detail=True, perms_map={'post': 'pu_plan.submit'}, serializer_class=serializers.Serializer)
def submit(self, request, *args, **kwargs): def submit(self, request, *args, **kwargs):
@ -80,6 +80,7 @@ class PuPlanItemViewSet(CustomModelViewSet):
ordering_fields = ['create_time', 'material', 'need_date', 'need_count'] ordering_fields = ['create_time', 'material', 'need_date', 'need_count']
ordering = ['create_time'] ordering = ['create_time']
@transaction.atomic
def perform_destroy(self, instance): def perform_destroy(self, instance):
user = self.request.user user = self.request.user
pu_plan = instance.pu_plan pu_plan = instance.pu_plan
@ -87,7 +88,8 @@ class PuPlanItemViewSet(CustomModelViewSet):
raise ParseError('非创建人不可删除') raise ParseError('非创建人不可删除')
elif instance.pu_order is not None: elif instance.pu_order is not None:
raise ParseError('存在采购订单不可删除') raise ParseError('存在采购订单不可删除')
return super().perform_destroy(instance) instance.delete()
PumService.cal_pu_plan_total_price(pu_plan)
class PuOrderViewSet(CustomModelViewSet): class PuOrderViewSet(CustomModelViewSet):
@ -149,6 +151,7 @@ class PuOrderItemViewSet(CustomModelViewSet):
if pu_order.state != PuOrder.PUORDER_CREATE: if pu_order.state != PuOrder.PUORDER_CREATE:
raise ParseError('采购订单非创建中不可删除') raise ParseError('采购订单非创建中不可删除')
instance.delete() instance.delete()
PumService.cal_pu_order_total_price(pu_order)
@action(methods=['post'], detail=False, perms_map={'post': 'pu_order.update'}, serializer_class=AddSerializer) @action(methods=['post'], detail=False, perms_map={'post': 'pu_order.update'}, serializer_class=AddSerializer)
@transaction.atomic @transaction.atomic
@ -172,10 +175,16 @@ class PuOrderItemViewSet(CustomModelViewSet):
puorderitem, is_created = PuOrderItem.objects.get_or_create( puorderitem, is_created = PuOrderItem.objects.get_or_create(
pu_order=puorder, material=item.material, pu_order=puorder, material=item.material,
defaults={'pu_order': puorder, defaults={'pu_order': puorder,
'material': item.material, 'count': item.need_count} 'material': item.material,
'count': item.need_count,
'unit_price': item.unit_price,
'total_price': item.total_price
}
) )
if not is_created: if not is_created:
puorderitem.count = puorderitem.count + item.need_count puorderitem.count = puorderitem.count + item.need_count
if item.total_price:
puorderitem.total_price = puorderitem.total_price if puorderitem.total_price else 0 + item.total_price
puorderitem.save() puorderitem.save()
if puorder.delivery_date is None: if puorder.delivery_date is None:
puorder.delivery_date = item.need_date puorder.delivery_date = item.need_date