2024-06-28 02:06:39 +08:00
|
|
|
|
from decimal import Decimal
|
2024-06-22 22:42:19 +08:00
|
|
|
|
|
2024-06-28 02:06:39 +08:00
|
|
|
|
from django.apps import apps
|
2024-06-22 22:42:19 +08:00
|
|
|
|
from django.core.validators import MinValueValidator, MaxValueValidator
|
2024-06-26 09:52:00 +08:00
|
|
|
|
from django.db import models, IntegrityError
|
2024-06-28 02:06:39 +08:00
|
|
|
|
from django.db.models.signals import post_save
|
|
|
|
|
from django.dispatch import receiver
|
2024-07-14 16:38:15 +08:00
|
|
|
|
from django.utils.functional import cached_property
|
2024-06-26 09:52:00 +08:00
|
|
|
|
|
|
|
|
|
from application.hrm_mgnt.models import EmployeeInformation
|
|
|
|
|
from application.org_mgnt.models import PrimaryDepartment
|
2024-05-27 23:39:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 项目台账
|
|
|
|
|
class ProjectLedger(models.Model):
|
2024-06-28 02:06:39 +08:00
|
|
|
|
# 业务人员填报部分
|
2024-05-27 23:39:32 +08:00
|
|
|
|
project_id = models.AutoField(primary_key=True, verbose_name='项目编号')
|
2024-06-26 09:52:00 +08:00
|
|
|
|
project_name = models.CharField(max_length=255, verbose_name='项目名称', null=False, blank=False)
|
|
|
|
|
start_date = models.DateField(verbose_name='登记日期', null=True, blank=True)
|
|
|
|
|
project_approval_date = models.DateField(verbose_name='立项日期', null=True, blank=True)
|
|
|
|
|
end_date = models.DateField(verbose_name='结束日期', null=True, blank=True)
|
|
|
|
|
primary_department = models.CharField(max_length=255, verbose_name='一级部门', null=True, blank=True)
|
|
|
|
|
customer_name = models.CharField(max_length=255, verbose_name='客户名称', null=True, blank=True)
|
|
|
|
|
province = models.CharField(max_length=255, verbose_name='省', null=True, blank=True)
|
|
|
|
|
city = models.CharField(max_length=255, verbose_name='市', null=True, blank=True)
|
|
|
|
|
district = models.CharField(max_length=255, verbose_name='区县', null=True, blank=True)
|
|
|
|
|
project_leader = models.CharField(max_length=255, verbose_name='负责人', null=False, blank=False)
|
|
|
|
|
project_members = models.TextField(verbose_name='项目组员', null=True, blank=True)
|
|
|
|
|
project_status = models.CharField(max_length=100, choices=[('进行中', '进行中'), ('暂停', '暂停'), ('待收款', '待收款'), ('完成', '完成')], verbose_name='项目状态', null=True, blank=True)
|
2024-06-28 02:06:39 +08:00
|
|
|
|
# 管理部人员填报部分:
|
2024-06-26 09:52:00 +08:00
|
|
|
|
resource_type = models.CharField(max_length=50, choices=[('公司', '公司'), ('个人', '个人')], verbose_name='资源类型', null=True, blank=True)
|
|
|
|
|
project_nature = models.CharField(max_length=100, choices=[('新增', '新增'), ('存量', '存量'), ('新增及存量', '新增及存量'), ('老客户新业务', '老客户新业务')], verbose_name='项目性质', null=True, blank=True)
|
|
|
|
|
project_progress = models.CharField(max_length=255, verbose_name='项目进度', null=True, blank=True)
|
|
|
|
|
contract_date = models.DateField(verbose_name='签约时间', null=True, blank=True)
|
|
|
|
|
contract_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='标的金额(元)', null=True, blank=True)
|
|
|
|
|
contract_rate = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='合同费率(%)', null=True, blank=True)
|
|
|
|
|
revenue = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='收入(元)', null=True, blank=True)
|
|
|
|
|
cost_rate = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='成本费率(%)', null=True, blank=True)
|
|
|
|
|
cost = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='成本(元)', null=True, blank=True)
|
|
|
|
|
net_income = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='净收入(元)', null=True, blank=True)
|
2024-06-28 02:06:39 +08:00
|
|
|
|
# 开票记录
|
2024-06-26 09:52:00 +08:00
|
|
|
|
total_amount_including_tax = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='价税合计金额(元)', null=True, blank=True)
|
2024-06-28 02:06:39 +08:00
|
|
|
|
# 回款记录
|
2024-06-26 09:52:00 +08:00
|
|
|
|
repayment_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='回款金额(元)', null=True, blank=True)
|
2024-06-28 02:06:39 +08:00
|
|
|
|
# 计算得出
|
2024-06-26 09:52:00 +08:00
|
|
|
|
receivable_net_income = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='应收净收入(元)', null=True, blank=True)
|
|
|
|
|
actual_net_income = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='实收净收入(元)', null=True, blank=True)
|
|
|
|
|
outstanding_net_income = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='待收净收入(元)', null=True, blank=True)
|
|
|
|
|
notes = models.TextField(verbose_name='备注', null=True, blank=True)
|
|
|
|
|
|
2024-06-28 02:06:39 +08:00
|
|
|
|
@property
|
|
|
|
|
def net_income_ratio(self):
|
|
|
|
|
if self.revenue and self.revenue > Decimal('0'):
|
|
|
|
|
return Decimal('1') - (self.cost / self.revenue)
|
|
|
|
|
return Decimal('0')
|
|
|
|
|
|
2024-07-14 16:38:15 +08:00
|
|
|
|
@cached_property
|
|
|
|
|
def calculate_net_income(self):
|
|
|
|
|
if self.revenue and self.cost:
|
|
|
|
|
return self.revenue - self.cost
|
|
|
|
|
return Decimal('0')
|
|
|
|
|
|
2024-06-28 02:06:39 +08:00
|
|
|
|
def calculate_receivable_net_income(self):
|
|
|
|
|
try:
|
|
|
|
|
self.receivable_net_income = self.net_income_ratio * self.total_amount_including_tax
|
|
|
|
|
except TypeError:
|
|
|
|
|
self.receivable_net_income = 0
|
|
|
|
|
|
|
|
|
|
def calculate_actual_net_income(self):
|
|
|
|
|
try:
|
|
|
|
|
self.actual_net_income = self.net_income_ratio * self.repayment_amount
|
|
|
|
|
except TypeError:
|
|
|
|
|
self.actual_net_income = 0
|
|
|
|
|
|
|
|
|
|
def calculate_outstanding_net_income(self):
|
|
|
|
|
self.outstanding_net_income = self.receivable_net_income - self.actual_net_income
|
|
|
|
|
|
2024-06-26 09:52:00 +08:00
|
|
|
|
def save(self, *args, **kwargs):
|
2024-07-14 16:38:15 +08:00
|
|
|
|
self.net_income = self.calculate_net_income
|
2024-06-26 09:52:00 +08:00
|
|
|
|
project_leader = EmployeeInformation.objects.filter(name=self.project_leader).first()
|
|
|
|
|
primary_department = PrimaryDepartment.objects.filter(department_name=self.primary_department).first()
|
|
|
|
|
|
|
|
|
|
if self.project_leader:
|
|
|
|
|
if not project_leader:
|
|
|
|
|
raise ValueError("费用当事人不存在")
|
|
|
|
|
|
|
|
|
|
if self.primary_department:
|
|
|
|
|
if not primary_department:
|
|
|
|
|
raise ValueError("一级部门不存在")
|
|
|
|
|
|
|
|
|
|
if self.pk is None:
|
|
|
|
|
# 新增操作,进行唯一性校验
|
|
|
|
|
if ProjectLedger.objects.filter(project_leader=self.project_leader, primary_department=self.primary_department, project_name=self.project_name).exists():
|
|
|
|
|
raise IntegrityError("该一级部门的负责人名下已存在该项目名称。")
|
|
|
|
|
|
|
|
|
|
super(ProjectLedger, self).save(*args, **kwargs)
|
2024-05-27 23:39:32 +08:00
|
|
|
|
|
2024-06-28 02:06:39 +08:00
|
|
|
|
def create_sub_table(self):
|
|
|
|
|
if self.primary_department == '天信' or self.primary_department == '混改':
|
|
|
|
|
ChildProjectLedgerA.objects.create(project_id=self)
|
|
|
|
|
elif self.primary_department == '艾力芬特':
|
|
|
|
|
ChildProjectLedgerB.objects.create(project_id=self)
|
|
|
|
|
elif self.primary_department == '星河':
|
|
|
|
|
ChildProjectLedgerC.objects.create(project_id=self)
|
|
|
|
|
elif self.primary_department == '星海':
|
|
|
|
|
ChildProjectLedgerD.objects.create(project_id=self)
|
|
|
|
|
|
2024-05-27 23:39:32 +08:00
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '项目台账'
|
|
|
|
|
verbose_name_plural = '项目台账'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.project_name
|
|
|
|
|
|
|
|
|
|
|
2024-06-28 02:06:39 +08:00
|
|
|
|
@receiver(post_save, sender=ProjectLedger)
|
|
|
|
|
def create_sub_table(sender, instance, created, **kwargs):
|
|
|
|
|
if created:
|
|
|
|
|
if instance.primary_department == '天信' or instance.primary_department == '混改':
|
|
|
|
|
ChildProjectLedgerA.objects.create(project_id=instance)
|
|
|
|
|
elif instance.primary_department == '艾力芬特':
|
|
|
|
|
ChildProjectLedgerB.objects.create(project_id=instance)
|
|
|
|
|
elif instance.primary_department == '星河':
|
|
|
|
|
ChildProjectLedgerC.objects.create(project_id=instance)
|
|
|
|
|
elif instance.primary_department == '星海':
|
|
|
|
|
ChildProjectLedgerD.objects.create(project_id=instance)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 项目问题记录表
|
|
|
|
|
class ProjectIssuesLog(models.Model):
|
|
|
|
|
issue_id = models.AutoField(primary_key=True, verbose_name='问题ID')
|
|
|
|
|
project_id = models.ForeignKey(ProjectLedger, on_delete=models.CASCADE, verbose_name='项目ID')
|
2024-07-14 16:38:15 +08:00
|
|
|
|
record_date = models.DateTimeField(verbose_name='记录时间', null=True, blank=True)
|
|
|
|
|
description = models.TextField(verbose_name='问题描述', null=True, blank=True)
|
|
|
|
|
handler = models.CharField(max_length=255, verbose_name='经办人', null=True, blank=True)
|
|
|
|
|
reference = models.TextField(verbose_name='参考依据', null=True, blank=True)
|
|
|
|
|
solution = models.TextField(verbose_name='解决方案', null=True, blank=True)
|
|
|
|
|
decision_maker = models.CharField(max_length=255, verbose_name='决策人', null=True, blank=True)
|
2024-06-28 02:06:39 +08:00
|
|
|
|
STATUS_CHOICES = [
|
|
|
|
|
('解决', '解决'),
|
|
|
|
|
('未解决', '未解决')
|
|
|
|
|
]
|
2024-07-14 16:38:15 +08:00
|
|
|
|
status = models.CharField(max_length=255, choices=STATUS_CHOICES, verbose_name='状态', null=True, blank=True, default='未解决')
|
2024-06-28 02:06:39 +08:00
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '项目问题记录表'
|
|
|
|
|
verbose_name_plural = '项目问题记录表'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"Issue #{self.issue_id} - Project: {self.project_id.project_name}"
|
|
|
|
|
|
|
|
|
|
|
2024-06-16 20:08:28 +08:00
|
|
|
|
# 项目进度表
|
|
|
|
|
class ProjectProgress(models.Model):
|
|
|
|
|
record_id = models.AutoField(primary_key=True, verbose_name='记录ID')
|
|
|
|
|
project_id = models.ForeignKey(ProjectLedger, on_delete=models.CASCADE, verbose_name='项目编号')
|
|
|
|
|
flow_nodes = models.JSONField(verbose_name='进度点')
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '项目进度表'
|
|
|
|
|
verbose_name_plural = '项目进度表'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"Record #{self.record_id} - Project: {self.project_id}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 项目进度设置表
|
|
|
|
|
class ProjectProgressSettings(models.Model):
|
|
|
|
|
config_id = models.AutoField(primary_key=True, verbose_name='配置ID')
|
|
|
|
|
project_type = models.CharField(max_length=255, verbose_name='项目类型', null=False, blank=False)
|
|
|
|
|
flow_nodes_setting = models.CharField(max_length=255, verbose_name='项目进度设置', null=False, blank=False,
|
|
|
|
|
help_text="项目进度设置示例:买菜;洗菜;切菜;烧菜;")
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '项目进度设置表'
|
|
|
|
|
verbose_name_plural = '项目进度设置表'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"Config #{self.config_id} - Project Type: {self.project_type}"
|
|
|
|
|
|
|
|
|
|
|
2024-06-28 02:06:39 +08:00
|
|
|
|
# 项目台账续表A
|
2024-05-27 23:39:32 +08:00
|
|
|
|
# 项目台账续表A
|
|
|
|
|
class ChildProjectLedgerA(models.Model):
|
2024-06-28 02:06:39 +08:00
|
|
|
|
project_id = models.OneToOneField(ProjectLedger, primary_key=True, on_delete=models.CASCADE, verbose_name='项目编号')
|
|
|
|
|
PROJECT_TYPE_CHOICES = [('cbc', 'cbc'), ('债拍', '债拍'), ('其他', '其他')]
|
|
|
|
|
project_type = models.CharField(max_length=255, choices=PROJECT_TYPE_CHOICES, verbose_name='项目类型', null=True, blank=True)
|
|
|
|
|
resource_party = models.CharField(max_length=255, verbose_name='资源方', null=True, blank=True)
|
|
|
|
|
cooperation_party = models.CharField(max_length=255, verbose_name='合作方', null=True, blank=True)
|
|
|
|
|
transaction_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='成交金额(元)', null=True, blank=True)
|
|
|
|
|
target_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='标的金额(元)', null=True, blank=True)
|
2024-05-27 23:39:32 +08:00
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def contract_completion_rate(self):
|
|
|
|
|
if self.target_amount != 0:
|
|
|
|
|
return round((self.transaction_amount / self.target_amount) * 100, 2)
|
2024-06-28 02:06:39 +08:00
|
|
|
|
return None
|
2024-05-27 23:39:32 +08:00
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '项目台账续表A'
|
|
|
|
|
verbose_name_plural = '项目台账续表A'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"Project #{self.project_id} - Type: {self.project_type}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 项目台账续表B
|
|
|
|
|
class ChildProjectLedgerB(models.Model):
|
2024-06-28 02:06:39 +08:00
|
|
|
|
project_id = models.OneToOneField(ProjectLedger, primary_key=True, on_delete=models.CASCADE, verbose_name='项目编号')
|
|
|
|
|
PROJECT_TYPE_CHOICES = [('承销', '承销'), ('贸易', '贸易'), ('其他', '其他')]
|
|
|
|
|
project_type = models.CharField(max_length=255, choices=PROJECT_TYPE_CHOICES, verbose_name='项目类型', null=True, blank=True)
|
|
|
|
|
partner = models.CharField(max_length=255, verbose_name='合作方', null=True, blank=True)
|
|
|
|
|
start_interest_date = models.DateField(verbose_name='起息日期', null=True, blank=True)
|
|
|
|
|
interest_payment_date = models.DateField(verbose_name='付息日期', null=True, blank=True)
|
|
|
|
|
number_of_people = models.IntegerField(verbose_name='人数', null=True, blank=True)
|
|
|
|
|
amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='金额', null=True, blank=True)
|
2024-05-27 23:39:32 +08:00
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '项目台账续表B'
|
|
|
|
|
verbose_name_plural = '项目台账续表B'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"Project #{self.project_id} - Type: {self.project_type}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 项目台账续表C
|
|
|
|
|
class ChildProjectLedgerC(models.Model):
|
2024-06-28 02:06:39 +08:00
|
|
|
|
project_id = models.OneToOneField(ProjectLedger, primary_key=True, on_delete=models.CASCADE, verbose_name='项目编号')
|
|
|
|
|
PROJECT_TYPE_CHOICES = [('咨询', '咨询'), ('科技', '科技'), ('新媒体', '新媒体'), ('其他', '其他')]
|
|
|
|
|
project_type = models.CharField(max_length=100, choices=PROJECT_TYPE_CHOICES, verbose_name='项目类型', null=True, blank=True)
|
|
|
|
|
resource_party = models.CharField(max_length=255, verbose_name='资源方', null=True, blank=True)
|
|
|
|
|
cooperation_party = models.CharField(max_length=255, verbose_name='合作方', null=True, blank=True)
|
|
|
|
|
service_period = models.CharField(max_length=100, verbose_name='服务周期', null=True, blank=True)
|
2024-05-27 23:39:32 +08:00
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '项目台账续表C'
|
|
|
|
|
verbose_name_plural = '项目台账续表C'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"Project #{self.project_id} - Type: {self.project_type}"
|
|
|
|
|
|
|
|
|
|
|
2024-06-06 15:08:38 +08:00
|
|
|
|
# 项目台账续表D
|
2024-05-27 23:39:32 +08:00
|
|
|
|
class ChildProjectLedgerD(models.Model):
|
2024-06-28 02:06:39 +08:00
|
|
|
|
project_id = models.OneToOneField(ProjectLedger, primary_key=True, on_delete=models.CASCADE, verbose_name='项目编号')
|
|
|
|
|
PROJECT_TYPE_CHOICES = [('非标', '非标'), ('贸易', '贸易'), ('其他', '其他')]
|
|
|
|
|
project_type = models.CharField(max_length=50, choices=PROJECT_TYPE_CHOICES, verbose_name='项目类型', null=True, blank=True)
|
|
|
|
|
capital_demand_party = models.CharField(max_length=255, verbose_name='资金需求方', null=True, blank=True)
|
|
|
|
|
capital_provider = models.CharField(max_length=255, verbose_name='资金提供方', null=True, blank=True)
|
|
|
|
|
financing_method = models.CharField(max_length=255, verbose_name='融资方式', null=True, blank=True)
|
|
|
|
|
target_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='标的金额(元)', null=True, blank=True)
|
|
|
|
|
term = models.CharField(max_length=100, verbose_name='期限', null=True, blank=True)
|
|
|
|
|
nominal_rate = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='票面利率', null=True, blank=True)
|
|
|
|
|
total_cost = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='综合成本(元)', null=True, blank=True)
|
|
|
|
|
TRADE_TYPE_CHOICES = [('带量', '带量'), ('取信', '取信'), ('补票', '补票')]
|
|
|
|
|
trade_type = models.CharField(max_length=50, choices=TRADE_TYPE_CHOICES, verbose_name='贸易类型', null=True, blank=True)
|
|
|
|
|
trade_entity = models.CharField(max_length=255, verbose_name='贸易主体', null=True, blank=True)
|
|
|
|
|
trade_service_provider = models.CharField(max_length=255, verbose_name='贸易服务商', null=True, blank=True)
|
|
|
|
|
trade_variety = models.CharField(max_length=255, verbose_name='贸易品种', null=True, blank=True)
|
|
|
|
|
demand_party = models.CharField(max_length=255, verbose_name='需求方', null=True, blank=True)
|
|
|
|
|
supply_party = models.CharField(max_length=255, verbose_name='供给方', null=True, blank=True)
|
2024-05-27 23:39:32 +08:00
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '项目台账续表D'
|
|
|
|
|
verbose_name_plural = '项目台账续表D'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"Project #{self.project_id} - Type: {self.project_type}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 项目组员收入结算表
|
|
|
|
|
class EmployeeProjectIncomeSettlement(models.Model):
|
|
|
|
|
record_id = models.AutoField(primary_key=True, verbose_name='记录ID')
|
2024-06-22 22:42:19 +08:00
|
|
|
|
project_name = models.ForeignKey('ProjectLedger', on_delete=models.CASCADE, verbose_name='项目名称')
|
|
|
|
|
year_month = models.DateField(max_length=7, verbose_name='年月', help_text='格式为 YYYY-MM,从开票记录中关联')
|
|
|
|
|
total_amount_including_tax = models.DecimalField(
|
|
|
|
|
max_digits=10,
|
|
|
|
|
decimal_places=2,
|
|
|
|
|
verbose_name='价税合计金额(元)',
|
|
|
|
|
help_text='从开票记录中获取',
|
|
|
|
|
null=True,
|
|
|
|
|
blank=True
|
|
|
|
|
)
|
|
|
|
|
name = models.CharField(max_length=255, verbose_name='姓名', help_text='员工姓名', null=True, blank=True)
|
2024-06-26 11:09:07 +08:00
|
|
|
|
primary_department = models.CharField(max_length=255, verbose_name='一级部门', null=True, blank=True)
|
2024-06-22 22:42:19 +08:00
|
|
|
|
contribution_rate = models.DecimalField(
|
|
|
|
|
max_digits=5,
|
|
|
|
|
decimal_places=2,
|
|
|
|
|
verbose_name='贡献率(%)',
|
|
|
|
|
validators=[MinValueValidator(0), MaxValueValidator(100)],
|
|
|
|
|
help_text='员工对项目的贡献率,单位为百分比',
|
|
|
|
|
null=True,
|
|
|
|
|
blank=True
|
|
|
|
|
)
|
|
|
|
|
sales_income = models.DecimalField(
|
|
|
|
|
max_digits=10,
|
|
|
|
|
decimal_places=2,
|
|
|
|
|
verbose_name='销售收入(元)',
|
|
|
|
|
help_text='计算得出,等于价税合计金额×贡献率',
|
|
|
|
|
null=True,
|
|
|
|
|
blank=True
|
|
|
|
|
)
|
2024-05-27 23:39:32 +08:00
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '项目组员收入结算表'
|
|
|
|
|
verbose_name_plural = '项目组员收入结算表'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
2024-06-22 22:42:19 +08:00
|
|
|
|
return f"Record #{self.record_id} - Project: {self.project_name}, Year-Month: {self.year_month}, Employee: {self.name or 'N/A'}"
|
2024-05-27 23:39:32 +08:00
|
|
|
|
|
2024-06-22 22:42:19 +08:00
|
|
|
|
def save(self, *args, **kwargs):
|
2024-06-26 11:09:07 +08:00
|
|
|
|
primary_department_name = PrimaryDepartment.objects.filter(department_name=self.primary_department).first()
|
|
|
|
|
name = EmployeeInformation.objects.filter(name=self.name).first()
|
|
|
|
|
|
|
|
|
|
if self.primary_department:
|
|
|
|
|
if not primary_department_name:
|
|
|
|
|
raise ValueError("一级部门不存在")
|
|
|
|
|
|
|
|
|
|
if self.name:
|
|
|
|
|
if not name:
|
|
|
|
|
raise ValueError("姓名不存在")
|
|
|
|
|
|
|
|
|
|
if self.pk is None:
|
|
|
|
|
# 新增操作,进行唯一性校验
|
|
|
|
|
if EmployeeProjectIncomeSettlement.objects.filter(project_name=self.project_name, year_month=self.year_month, name=self.name, primary_department=self.primary_department).exists():
|
|
|
|
|
raise IntegrityError("该部门下的员工在同一年月的同一项目下已存在一个项目结算。")
|
|
|
|
|
|
2024-06-22 22:42:19 +08:00
|
|
|
|
# 只在贡献率不为空时计算销售收入
|
|
|
|
|
if all([self.contribution_rate, self.total_amount_including_tax]):
|
|
|
|
|
self.sales_income = self.total_amount_including_tax * (self.contribution_rate / 100)
|
|
|
|
|
super().save(*args, **kwargs)
|