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_user = models.ForeignKey(
'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):
@ -66,6 +67,7 @@ class PuOrder(CommonBModel):
'system.user', verbose_name='提交人', related_name='submit_user_puorder', on_delete=models.CASCADE, null=True, blank=True)
materials = models.ManyToManyField(
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):
@ -73,6 +75,8 @@ class PuOrderItem(BaseModel):
Material, verbose_name='物料', on_delete=models.CASCADE, related_name='pu_orderitem_material')
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='关联采购订单',
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)
need_count = models.PositiveIntegerField('所属数量')
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='')
pu_plan = models.ForeignKey(PuPlan, verbose_name='采购计划', on_delete=models.CASCADE,
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.mtm.serializers import MaterialSerializer, MaterialSimpleSerializer
from django.db import transaction
from .services import PumService
class SupplierSerializer(CustomModelSerializer):
@ -18,7 +20,7 @@ class PuPlanSerializer(CustomModelSerializer):
class Meta:
model = PuPlan
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):
if instance.state != PuPlan.PUPLAN_CREATE:
@ -41,6 +43,7 @@ class PuPlanItemSerializer(CustomModelSerializer):
fields = '__all__'
read_only_fields = EXCLUDE_FIELDS + ['pu_order']
@transaction.atomic
def create(self, validated_data):
pu_plan = validated_data['pu_plan']
if pu_plan.state != PuPlan.PUPLAN_CREATE:
@ -49,7 +52,9 @@ class PuPlanItemSerializer(CustomModelSerializer):
self.complete_belong_dept(validated_data)
if PuPlanItem.objects.filter(material=material, belong_dept=validated_data['belong_dept']).exists():
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):
belong_dept = validated_data.get('belong_dept', None)
@ -59,7 +64,8 @@ class PuPlanItemSerializer(CustomModelSerializer):
raise ValidationError('所属部门不可为空')
else:
validated_data['belong_dept'] = belong_dept
@transaction.atomic
def update(self, instance, validated_data):
validated_data.pop('pu_plan')
pu_plan = instance.pu_plan
@ -73,7 +79,9 @@ class PuPlanItemSerializer(CustomModelSerializer):
self.complete_belong_dept(validated_data)
if PuPlanItem.objects.exclude(id=instance.id).filter(material=material, belong_dept=validated_data['belong_dept']).exists():
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):
@ -89,7 +97,7 @@ class PuOrderSerializer(CustomModelSerializer):
class Meta:
model = PuOrder
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):
validated_data.pop('supplier')
@ -106,6 +114,7 @@ class PuOrderItemSerializer(CustomModelSerializer):
fields = '__all__'
read_only_fields = EXCLUDE_FIELDS_BASE + ['delivered_count']
@transaction.atomic
def create(self, validated_data):
pu_order = validated_data['pu_order']
material = validated_data['material']
@ -113,15 +122,20 @@ class PuOrderItemSerializer(CustomModelSerializer):
raise ValidationError('采购订单该状态下不可添加明细')
if PuOrderItem.objects.filter(pu_order=pu_order, material=material).exists():
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):
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)
ins = super().update(instance, validated_data)
PumService.cal_pu_order_total_price(pu_order)
return ins
class AddSerializer(serializers.Serializer):

View File

@ -1,11 +1,21 @@
from rest_framework.exceptions import ValidationError
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
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):
puplanIds = PuPlanItem.objects.filter(
pu_order=puorder).values_list('pu_plan', flat=True)

View File

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