from decimal import Decimal from django.db import models from django.db.models import Sum from apps.utils.models import CommonBModel, BaseModel, CommonBDModel from apps.mtm.models import Material # Create your models here. class Customer(CommonBModel): """ TN:客户信息 """ name = models.CharField('客户名称', max_length=50, unique=True) address = models.CharField('详细地址', max_length=20, blank=True, null=True) contact = models.CharField('联系人', max_length=20) contact_phone = models.CharField( '联系电话', max_length=11, unique=True, null=True) description = models.CharField('描述', max_length=200, blank=True, null=True) class Meta: verbose_name = '客户信息' verbose_name_plural = verbose_name def __str__(self): return self.name class Contract(CommonBDModel): """ TN:合同信息 """ STATUS_DRAFT = 10 STATUS_ACTIVE = 20 STATUS_DONE = 30 STATUS_TERMINATED = 40 STATUS_CHOICES = ( (STATUS_DRAFT, '草稿'), (STATUS_ACTIVE, '执行中'), (STATUS_DONE, '已完成'), (STATUS_TERMINATED, '已终止'), ) SETTLEMENT_UNRECEIVED = 10 SETTLEMENT_PARTIAL = 20 SETTLEMENT_FULL = 30 SETTLEMENT_CHOICES = ( (SETTLEMENT_UNRECEIVED, '未到款'), (SETTLEMENT_PARTIAL, '部分到款'), (SETTLEMENT_FULL, '全部到款'), ) name = models.CharField('合同名称', max_length=100) number = models.CharField('合同编号', max_length=100, unique=True) amount = models.IntegerField('合同金额', default=0) customer = models.ForeignKey(Customer, verbose_name='关联客户', on_delete=models.CASCADE, related_name='contract_customer') sign_date = models.DateField('签订日期') effective_date = models.DateField('生效日期', null=True, blank=True) end_date = models.DateField('截止日期', null=True, blank=True) status = models.PositiveSmallIntegerField( '合同状态', choices=STATUS_CHOICES, default=STATUS_DRAFT, help_text=str(STATUS_CHOICES)) settlement_status = models.PositiveSmallIntegerField( '结算状态', choices=SETTLEMENT_CHOICES, default=SETTLEMENT_UNRECEIVED, help_text=str(SETTLEMENT_CHOICES)) received_amount = models.DecimalField('累计已到款', max_digits=14, decimal_places=2, default=0) unreceived_amount = models.DecimalField('累计未到款', max_digits=14, decimal_places=2, default=0) receive_progress = models.DecimalField('到款进度', max_digits=5, decimal_places=2, default=0) description = models.CharField('描述', max_length=200, blank=True, null=True) class Meta: verbose_name = '合同信息' verbose_name_plural = verbose_name def __str__(self): return self.name def save(self, *args, **kwargs): refresh_settlement = kwargs.pop('refresh_settlement', True) super().save(*args, **kwargs) if refresh_settlement: self.refresh_settlement() def refresh_settlement(self): received_amount = ContractRecord.objects.filter(contract=self).aggregate( total=Sum('amount') )['total'] or Decimal('0.00') contract_amount = Decimal(str(self.amount or 0)).quantize(Decimal('0.01')) unreceived_amount = contract_amount - received_amount if unreceived_amount < Decimal('0.00'): unreceived_amount = Decimal('0.00') if contract_amount <= Decimal('0.00'): receive_progress = Decimal('0.00') else: receive_progress = (received_amount * Decimal('100.00') / contract_amount).quantize(Decimal('0.01')) if receive_progress > Decimal('100.00'): receive_progress = Decimal('100.00') if received_amount <= Decimal('0.00'): settlement_status = self.SETTLEMENT_UNRECEIVED elif received_amount >= contract_amount and contract_amount > Decimal('0.00'): settlement_status = self.SETTLEMENT_FULL else: settlement_status = self.SETTLEMENT_PARTIAL status = self.status if status != self.STATUS_TERMINATED: if received_amount <= Decimal('0.00'): status = self.STATUS_DRAFT elif received_amount >= contract_amount and contract_amount > Decimal('0.00'): status = self.STATUS_DONE else: status = self.STATUS_ACTIVE type(self).objects.filter(pk=self.pk).update( received_amount=received_amount, unreceived_amount=unreceived_amount, receive_progress=receive_progress, settlement_status=settlement_status, status=status, ) self.received_amount = received_amount self.unreceived_amount = unreceived_amount self.receive_progress = receive_progress self.settlement_status = settlement_status self.status = status class Order(CommonBModel): """ TN:订单信息 """ ORDER_CREATE = 10 ORDER_SUBMITED = 20 ORDER_DOING = 30 ORDER_DELIVERED = 40 ORDER_STATES = ( (10, '创建中'), (20, '已提交'), (30, '进行中'), (40, '已交付') ) state = models.PositiveSmallIntegerField( '订单状态', default=ORDER_CREATE, choices=ORDER_STATES, help_text=str(ORDER_STATES)) number = models.CharField('订单编号', max_length=100, unique=True) customer = models.ForeignKey( Customer, verbose_name='客户', on_delete=models.CASCADE) contract = models.ForeignKey( Contract, verbose_name='所属合同', null=True, blank=True, on_delete=models.SET_NULL) delivery_date = models.DateField('截止交货日期') items = models.ManyToManyField( Material, verbose_name='订单明细', through='sam.orderitem', blank=True) submit_time = models.DateTimeField('提交时间', null=True, blank=True) class Meta: verbose_name = '订单信息' verbose_name_plural = verbose_name class OrderItem(BaseModel): """ TN:订单明细 """ order = models.ForeignKey( Order, verbose_name='关联订单', on_delete=models.CASCADE, related_name='item_order') material = models.ForeignKey( Material, verbose_name='所需产品', on_delete=models.CASCADE, related_name='orderitem_material') count = models.PositiveIntegerField('所需数量', default=1) delivered_count = models.PositiveIntegerField('已交货数量', default=0) utask = models.ForeignKey('pm.utask', verbose_name='关联生产大任务', on_delete=models.SET_NULL, null=True, blank=True) class ContractRecord(CommonBDModel): """ TN:销售合同到款流水 """ STAGE_FIRST = 10 STAGE_MIDDLE = 20 STAGE_FINAL = 30 STAGE_OTHER = 40 STAGE_CHOICES = ( (STAGE_FIRST, '首款'), (STAGE_MIDDLE, '中间款'), (STAGE_FINAL, '尾款'), (STAGE_OTHER, '其他'), ) PAY_BANK = 10 PAY_CASH = 20 PAY_ACCEPTANCE = 30 PAY_WECHAT = 40 PAY_ALIPAY = 50 PAY_OTHER = 60 PAY_METHOD_CHOICES = ( (PAY_BANK, '银行转账'), (PAY_CASH, '现金'), (PAY_ACCEPTANCE, '承兑'), (PAY_WECHAT, '微信'), (PAY_ALIPAY, '支付宝'), (PAY_OTHER, '其他'), ) contract = models.ForeignKey( Contract, verbose_name='销售合同', on_delete=models.CASCADE, related_name='records') record_date = models.DateField('到款日期') amount = models.DecimalField('到款金额', max_digits=14, decimal_places=2) stage_type = models.PositiveSmallIntegerField( '阶段类型', choices=STAGE_CHOICES, default=STAGE_OTHER, help_text=str(STAGE_CHOICES)) pay_method = models.PositiveSmallIntegerField( '收款方式', choices=PAY_METHOD_CHOICES, default=PAY_BANK, help_text=str(PAY_METHOD_CHOICES)) voucher_no = models.CharField('凭证号', max_length=100, null=True, blank=True) remark = models.CharField('备注', max_length=200, null=True, blank=True) class Meta: verbose_name = '销售合同到款流水' verbose_name_plural = verbose_name ordering = ['-record_date', '-create_time'] def save(self, *args, **kwargs): super().save(*args, **kwargs) self.contract.refresh_settlement() def delete(self, using=None, *args, **kwargs): contract = self.contract result = super().delete(using=using, *args, **kwargs) contract.refresh_settlement() return result