factory/apps/pum/models.py

283 lines
13 KiB
Python

from decimal import Decimal
from django.db import models
from django.db.models import Sum
from apps.utils.models import CommonBModel, BaseModel, CommonBDModel, CommonADModel
from apps.mtm.models import Material
from apps.wf.models import Ticket
# Create your models here.
class Supplier(CommonBModel):
"""
TN:供应商
"""
name = models.CharField('供应商名称', max_length=50)
number= models.CharField('供应商编号', max_length=20, null=True, blank=True)
contact = models.CharField('联系人', max_length=20, default='', blank=True)
contact_phone = models.CharField('联系电话', max_length=11, default='', blank=True)
address = models.CharField('地址', max_length=200, default='', blank=True)
can_outsource = models.BooleanField('是否可外协', default=False)
class SupplierAudit(CommonADModel):
name = models.CharField('供应商名称', max_length=100)
material_name = models.CharField('物料名称', max_length=100)
material_cate = models.CharField('物料类别', max_length=100)
survery_form = models.ForeignKey('system.file', verbose_name='调查表', on_delete=models.SET_NULL, null=True, blank=True, related_name='supplier_audit_survey_form')
business_license = models.ForeignKey('system.file', verbose_name='营业执照', on_delete=models.SET_NULL, null=True, blank=True, related_name='supplier_audit_business_license')
quality_certificate = models.ForeignKey('system.file', verbose_name='质量证书', on_delete=models.SET_NULL, null=True, blank=True, related_name='supplier_audit_quality_certificate')
ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.SET_NULL, null=True, blank=True)
class PuPlan(CommonBModel):
"""
TN:采购计划
"""
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)
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):
"""
TN:采购订单
"""
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)
contract = models.ForeignKey(
'pum.PuContract', verbose_name='采购合同', on_delete=models.SET_NULL,
null=True, blank=True, related_name='orders')
delivery_date = models.DateField('截止到货日期', null=True, blank=True)
submit_time = models.DateTimeField('提交时间', null=True, blank=True)
submit_user = models.ForeignKey(
'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):
"""TN:物料信息表"""
material = models.ForeignKey(
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')
class PuPlanItem(CommonBDModel):
"""
TN:采购计划明细(因为各部门填写所以需要belong_dept字段)
"""
material = models.ForeignKey(
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')
pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单',
on_delete=models.SET_NULL, null=True, blank=True, related_name='puplan_item_puorder')
class QuotationApply(CommonADModel):
"""
TN:报价申请表
"""
customer_name = models.CharField(max_length=50,verbose_name="客户名称")
product_name = models.CharField(max_length=50,verbose_name="产品名称")
contact_person = models.CharField(max_length=50,verbose_name="联系人")
contact_phone = models.CharField(max_length=20,verbose_name="联系电话", null=True, blank=True)
receive_address = models.CharField(max_length=100,verbose_name="收件地址", null=True, blank=True)
product_spec_quantity = models.TextField(verbose_name="产品规格/数量", null=True, blank=True)
quotation_basis = models.TextField(verbose_name="报价依据", null=True, blank=True)
suggested_price_calc = models.TextField(verbose_name="建议价格及计算方式", null=True, blank=True)
quotation_range = models.CharField(max_length=100,verbose_name="报价区间", null=True, blank=True)
quoter = models.CharField(max_length=50,verbose_name="报价人", null=True, blank=True)
apply_date = models.DateField(verbose_name="申请日期",auto_now_add=True)
ticket = models.OneToOneField('wf.ticket', verbose_name='关联工单',
on_delete=models.CASCADE, related_name='quo_ticket', null=True, blank=True)
class PuContract(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_UNPAID = 10
SETTLEMENT_PARTIAL = 20
SETTLEMENT_FULL = 30
SETTLEMENT_CHOICES = (
(SETTLEMENT_UNPAID, '未付款'),
(SETTLEMENT_PARTIAL, '部分付款'),
(SETTLEMENT_FULL, '全部付款'),
)
name = models.CharField('合同名称', max_length=100)
number = models.CharField('合同编号', max_length=100, unique=True)
supplier = models.ForeignKey(Supplier, verbose_name='供应商', on_delete=models.CASCADE, related_name='contracts')
contract_amount = models.DecimalField('合同金额', max_digits=14, decimal_places=2, default=0)
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_UNPAID, help_text=str(SETTLEMENT_CHOICES))
paid_amount = models.DecimalField('累计已付款', max_digits=14, decimal_places=2, default=0)
unpaid_amount = models.DecimalField('累计未付款', max_digits=14, decimal_places=2, default=0)
pay_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):
paid_amount = PuContractRecord.objects.filter(contract=self).aggregate(
total=Sum('amount')
)['total'] or Decimal('0.00')
contract_amount = Decimal(str(self.contract_amount or 0)).quantize(Decimal('0.01'))
unpaid_amount = contract_amount - paid_amount
if unpaid_amount < Decimal('0.00'):
unpaid_amount = Decimal('0.00')
if contract_amount <= Decimal('0.00'):
pay_progress = Decimal('0.00')
else:
pay_progress = (paid_amount * Decimal('100.00') / contract_amount).quantize(Decimal('0.01'))
if pay_progress > Decimal('100.00'):
pay_progress = Decimal('100.00')
if paid_amount <= Decimal('0.00'):
settlement_status = self.SETTLEMENT_UNPAID
elif paid_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 paid_amount <= Decimal('0.00'):
status = self.STATUS_DRAFT
elif paid_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(
paid_amount=paid_amount,
unpaid_amount=unpaid_amount,
pay_progress=pay_progress,
settlement_status=settlement_status,
status=status,
)
self.paid_amount = paid_amount
self.unpaid_amount = unpaid_amount
self.pay_progress = pay_progress
self.settlement_status = settlement_status
self.status = status
class PuContractRecord(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(
PuContract, 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