from django.db import models, IntegrityError from django.db.models import Q, Sum from application.hrm_mgnt.models import EmployeeInformation from application.org_mgnt.models import PrimaryDepartment, SecondaryDepartment, CompanyEntity from application.pjt_mgnt.models import ProjectLedger # 费用类型表 class ExpenseType(models.Model): type_id = models.AutoField(primary_key=True, verbose_name='费用类型ID') expense_type = models.CharField(max_length=255, unique=True, verbose_name='费用类型') class Meta: verbose_name = '费用类型表' verbose_name_plural = '费用类型表' def __str__(self): return self.expense_type # 费用明细表 class ExpenseDetail(models.Model): detail_id = models.AutoField(primary_key=True, verbose_name='明细ID') type_id = models.ForeignKey(ExpenseType, on_delete=models.CASCADE, verbose_name='费用类型名称') expense_detail = models.CharField(max_length=255, unique=True, verbose_name='费用明细') class Meta: verbose_name = '费用明细表' verbose_name_plural = '费用明细表' def __str__(self): return self.expense_detail # 集团年度预算表 class GroupAnnualBudget(models.Model): budget_id = models.AutoField(primary_key=True, verbose_name='记录ID') primary_department = models.CharField(max_length=255, verbose_name='一级部门') year = models.IntegerField(verbose_name='年份', null=False, blank=False) expense_type = models.ForeignKey(ExpenseType, on_delete=models.CASCADE, verbose_name='费用类型', null=False, blank=False) expense_detail = models.ForeignKey(ExpenseDetail, on_delete=models.CASCADE, verbose_name='费用明细', null=False, blank=False) amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='金额(元)') def save(self, *args, **kwargs): primary_department_name = PrimaryDepartment.objects.filter(department_name=self.primary_department).first() if not primary_department_name: raise ValueError("一级部门不存在") if self.pk is None: # 新增操作,进行唯一性校验 if GroupAnnualBudget.objects.filter(primary_department=self.primary_department, year=self.year, expense_detail=self.expense_detail).exists(): raise IntegrityError("该一级部门在同一年已经有一个相同费用明细的预算表。") super(GroupAnnualBudget, self).save(*args, **kwargs) class Meta: verbose_name = '集团年度预算表' verbose_name_plural = '集团年度预算表' def __str__(self): return f"{self.primary_department} - {self.year}" # 人工费明细表 class LaborCostDetail(models.Model): record_id = models.AutoField(primary_key=True, verbose_name='记录ID') year_month = models.DateField(verbose_name='年月', null=False, blank=False) name = models.CharField(max_length=255, verbose_name='姓名', null=False, blank=False) primary_department = models.CharField(max_length=255, verbose_name='一级部门', null=False, blank=False) secondary_department = models.CharField(max_length=255, verbose_name='二级部门', null=True, blank=True) attendance_days = models.IntegerField(verbose_name='出勤天数', null=True, blank=True) gross_salary = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='应发工资(元)', null=True, blank=True) attendance_reward = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='全勤奖(元)', null=True, blank=True) lunch_allowance = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='午餐津贴(元)', null=True, blank=True) other_monetary_benefits = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='其他货币性福利(元)', null=True, blank=True) social_security_deduction = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='代扣社保(元)', null=True, blank=True) housing_fund_deduction = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='代扣公积金(元)', null=True, blank=True) net_salary = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='实发工资(元)', null=True, blank=True) employer_social_security = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='公司承担社保(元)', null=True, blank=True) employer_housing_fund = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='公司承担公积金(元)', null=True, blank=True) def save(self, *args, **kwargs): primary_department_name = PrimaryDepartment.objects.filter(department_name=self.primary_department).first() secondary_department = SecondaryDepartment.objects.filter(secondary_department_name=self.secondary_department).first() name = EmployeeInformation.objects.filter(name=self.name).first() if self.primary_department: if not primary_department_name: raise ValueError("一级部门不存在") if self.secondary_department: if not secondary_department: raise ValueError("二级部门不存在") if self.name: if not name: raise ValueError("姓名不存在") if self.pk is None: # 新增操作,进行唯一性校验 if LaborCostDetail.objects.filter(primary_department=self.primary_department, year_month=self.year_month, name=self.name).exists(): raise IntegrityError("该姓名和一级部门在同一年月已存在一个费用明细。") super(LaborCostDetail, self).save(*args, **kwargs) class Meta: verbose_name = '人工费明细' verbose_name_plural = '人工费明细表' def __str__(self): return f"{self.name} - {self.year_month}" # 报销明细表 class ReimbursementDetail(models.Model): record_id = models.AutoField(primary_key=True, verbose_name='记录ID') year_month = models.DateField(verbose_name='年月', null=False, blank=False) primary_department = models.CharField(max_length=255, verbose_name='一级部门', null=False, blank=False) name = models.CharField(max_length=255, verbose_name='姓名', null=False, blank=False) is_project_based = models.CharField(max_length=3, choices=(('是', '是'), ('否', '否')), verbose_name='是否立项', null=True, blank=True) project_name = models.ForeignKey(ProjectLedger, on_delete=models.CASCADE, verbose_name='项目名称', null=True, blank=True) expense_type = models.ForeignKey(ExpenseType, on_delete=models.CASCADE, verbose_name='费用类型', null=True, blank=True) expense_detail = models.ForeignKey(ExpenseDetail, on_delete=models.CASCADE, verbose_name='费用明细', null=True, blank=True) expense_description = models.TextField(verbose_name='费用说明', null=True, blank=True) expense_date = models.DateField(verbose_name='费用发生时间', null=True, blank=True) amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='费用金额(元)', null=True, blank=True) def save(self, *args, **kwargs): primary_department_name = PrimaryDepartment.objects.filter(department_name=self.primary_department).first() name = EmployeeInformation.objects.filter(name=self.name).first() if self.name: if not primary_department_name: raise ValueError("一级部门不存在") if self.name: if not name: raise ValueError("姓名不存在") if self.pk is None: # 新增操作,进行唯一性校验 if LaborCostDetail.objects.filter(primary_department=self.primary_department, year_month=self.year_month, name=self.name).exists(): raise IntegrityError("该姓名和一级部门在同一年月已存在一个报销明细。") super(ReimbursementDetail, self).save(*args, **kwargs) class Meta: verbose_name = '报销明细表' verbose_name_plural = '报销明细表' def __str__(self): return f"{self.name} - {self.year_month}" # 奖金类别表 class BonusCategory(models.Model): category_id = models.AutoField(primary_key=True) category_name = models.CharField(max_length=255, verbose_name='奖金类别') description = models.TextField(blank=True, verbose_name='描述') class Meta: verbose_name = '奖金类别表' verbose_name_plural = '奖金类别表' def __str__(self): return self.category_name # 奖金分配表 class BonusAllocation(models.Model): record_id = models.AutoField(primary_key=True, verbose_name='记录ID') year_month = models.DateField(verbose_name='年月', null=False, blank=False) name = models.CharField(max_length=255, verbose_name='姓名', null=False, blank=False) primary_department = models.CharField(max_length=255, verbose_name='一级部门', null=False, blank=False) secondary_department = models.CharField(max_length=255, verbose_name='二级部门', null=True, blank=True) bonus_category = models.CharField(max_length=255, verbose_name='奖金类别', null=True, blank=True) award_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='奖励金额(元)', null=True, blank=True) def save(self, *args, **kwargs): primary_department_name = PrimaryDepartment.objects.filter(department_name=self.primary_department).first() secondary_department = SecondaryDepartment.objects.filter(secondary_department_name=self.secondary_department).first() name = EmployeeInformation.objects.filter(name=self.name).first() bonus_category = BonusCategory.objects.filter(category_name=self.bonus_category).first() if self.primary_department: if not primary_department_name: raise ValueError("一级部门不存在") if self.secondary_department: if not secondary_department: raise ValueError("二级部门不存在") if self.name: if not name: raise ValueError("姓名不存在") if self.bonus_category: if not bonus_category: raise ValueError("奖金类别不存在") if self.pk is None: # 新增操作,进行唯一性校验 if BonusAllocation.objects.filter(primary_department=self.primary_department, year_month=self.year_month, name=self.name, bonus_category=self.bonus_category).exists(): raise IntegrityError("该姓名和一级部门在同一年月已存在一个奖金类别。") super(BonusAllocation, self).save(*args, **kwargs) class Meta: verbose_name = '奖金分配表' verbose_name_plural = '奖金分配表' def __str__(self): return f"{self.name} - {self.year_month}" # 纳税记录表 class TaxRecord(models.Model): TAX_TYPE_CHOICES = [ ('增值税', '增值税'), ('消费税', '消费税'), ('企业所得税', '企业所得税'), ('个人所得税', '个人所得税'), ('资源税', '资源税'), ('城市维护建设税', '城市维护建设税'), ('房产税', '房产税'), ('印花税', '印花税'), ('城镇土地使用税', '城镇土地使用税'), ('土地增值税', '土地增值税'), ('车船税', '车船税'), ('船舶吨税', '船舶吨税'), ('车辆购置税', '车辆购置税'), ('烟叶税', '烟叶税'), ('耕地占用税', '耕地占用税'), ('契税', '契税'), ('环境保护税', '环境保护税'), ('关税', '关税'), ] TAX_PERIOD_CHOICES = [ ('月度', '月度'), ('季度', '季度'), ('半年度', '半年度'), ('年度', '年度'), ] tax_entity = models.CharField(max_length=255, verbose_name='纳税主体', null=False, blank=False) year = models.IntegerField(verbose_name='年度', null=False, blank=False) tax_type = models.CharField(max_length=255, choices=TAX_TYPE_CHOICES, verbose_name='纳税税种', null=True, blank=True) tax_frequency = models.CharField(max_length=255, choices=TAX_PERIOD_CHOICES, verbose_name='纳税频率', null=True, blank=True) tax_period = models.CharField(max_length=255, verbose_name='纳税所属期', null=True, blank=True) tax_date = models.DateField(verbose_name='完税日期', null=True, blank=True) tax_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='纳税金额(元)', null=True, blank=True) annual_cumulative = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='当年累计(元)', null=True, blank=True) note = models.CharField(max_length=255, verbose_name='备注', null=True, blank=True) def save(self, *args, **kwargs): tax_entity = CompanyEntity.objects.filter(company_name=self.tax_entity).first() if self.tax_entity: if not tax_entity: raise ValueError("纳税主体不存在") if self.pk is None: # 新增操作,进行唯一性校验 if TaxRecord.objects.filter(tax_entity=self.tax_entity, year=self.year, tax_type=self.tax_type).exists(): raise IntegrityError("该纳税主体在同一年月已存在一个纳税税种。") super(TaxRecord, self).save(*args, **kwargs) # # 计算并更新当年累计 self.update_annual_cumulative() def update_annual_cumulative(self): # 计算当年累计金额 annual_sum = TaxRecord.objects.filter( tax_entity=self.tax_entity, year=self.year ).aggregate(Sum('tax_amount'))['tax_amount__sum'] or 0 # 更新所有同主体同年度记录的当年累计值 TaxRecord.objects.filter( tax_entity=self.tax_entity, year=self.year ).update(annual_cumulative=annual_sum) class Meta: verbose_name = '纳税记录表' verbose_name_plural = '纳税记录表' def __str__(self): return f"{self.tax_entity} - {self.year} - {self.tax_type}" # 电子发票台账 class ElectronicInvoiceLedger(models.Model): expense_party = models.CharField(max_length=255, verbose_name='费用当事人', null=False, blank=False) primary_department = models.CharField(max_length=255, verbose_name='一级部门', null=False, blank=False) invoice_number = models.CharField(max_length=255, verbose_name='发票号码', null=False, blank=False) invoice_code = models.CharField(max_length=255, verbose_name='发票代码', null=True, blank=True) submission_date = models.DateField(verbose_name='提交日期', null=True, blank=True) invoice_date = models.DateField(verbose_name='开票日期', null=True, blank=True) buyer_name = models.CharField(max_length=255, verbose_name='购买方名称', null=True, blank=True) buyer_tax_number = models.CharField(max_length=255, verbose_name='购买方税号', null=True, blank=True) seller_name = models.CharField(max_length=255, verbose_name='销售方名称', null=True, blank=True) seller_tax_number = models.CharField(max_length=255, verbose_name='销售方税号', null=True, blank=True) goods_or_services_name = models.CharField(max_length=255, verbose_name='货物或应税劳务服务名称', null=True, blank=True) tax_rate = models.DecimalField(max_digits=5, decimal_places=3, verbose_name='税率', null=True, blank=True) total_amount_including_tax = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='价税合计(元)', null=True, blank=True) def save(self, *args, **kwargs): expense_party = EmployeeInformation.objects.filter(name=self.expense_party).first() primary_department = PrimaryDepartment.objects.filter(department_name=self.primary_department).first() if self.expense_party: if not expense_party: raise ValueError("费用当事人不存在") if self.primary_department: if not primary_department: raise ValueError("一级部门不存在") if self.tax_rate: self.tax_rate = float(self.tax_rate) if self.tax_rate < 1: self.tax_rate = self.tax_rate * 100 if self.pk is None: # 新增操作,进行唯一性校验 if ElectronicInvoiceLedger.objects.filter(expense_party=self.expense_party, primary_department=self.primary_department, invoice_number=self.invoice_number).exists(): raise IntegrityError("该一级部门的当事人在已存在一个发票号码。") super(ElectronicInvoiceLedger, self).save(*args, **kwargs) class Meta: verbose_name = '电子发票台账' verbose_name_plural = '电子发票台账' unique_together = [['invoice_code', 'invoice_number']] # 设置发票代码和发票号码的联合唯一性约束 def __str__(self): return f"{self.invoice_code} - {self.invoice_number}" # 开票记录 class InvoiceRecord(models.Model): INVOICE_TYPE_CHOICES = [('专票', '专票'), ('普票', '普票')] record_id = models.AutoField(primary_key=True, verbose_name='记录编号') project_name = models.ForeignKey(ProjectLedger, on_delete=models.CASCADE, verbose_name='项目名称') primary_department = models.CharField(max_length=255, verbose_name='一级部门', null=False, blank=False) project_manager = models.CharField(max_length=255, verbose_name='项目负责人', null=False, blank=False) nature = models.CharField(max_length=255, verbose_name='性质', null=True, blank=True) billing_entity = models.CharField(max_length=255, verbose_name='开票主体', null=True, blank=True) invoice_number = models.CharField(max_length=255, verbose_name='发票号码', unique=True, null=True, blank=True) purchase_info = models.TextField(verbose_name='购票信息', null=True, blank=True) invoice_date = models.DateField(verbose_name='开票时间', null=True, blank=True) invoice_content = models.TextField(verbose_name='开票内容', null=True, blank=True) total_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='价税合计金额(元)', null=True, blank=True) tax_rate = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='税率', null=True, blank=True) amount_excluding_tax = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='不含税金额(元)', null=True, blank=True) tax_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='税额(元)', null=True, blank=True) invoice_type = models.CharField(max_length=255, choices=INVOICE_TYPE_CHOICES, verbose_name='发票类型', null=True, blank=True) class Meta: verbose_name = '开票记录' verbose_name_plural = '开票记录' unique_together = ('invoice_number', 'primary_department') def save(self, *args, **kwargs): if self.pk is None and self.invoice_number is not None: # 新增操作,进行唯一性校验 if InvoiceRecord.objects.filter(Q(invoice_number=self.invoice_number) & Q(primary_department=self.primary_department)).exists(): raise IntegrityError("该项目的一级部门已经存在一个发票记录。") super(InvoiceRecord, self).save(*args, **kwargs) # 确保回款记录的一致性 RepaymentRecord.objects.get_or_create( invoice=self, defaults={ 'project_name': self.project_name, 'primary_department': self.primary_department, 'project_manager': self.project_manager, 'repayment_amount': 0.00 } ) def __str__(self): return f"发票号码: {self.invoice_number}, 项目名称: {self.project_name.project_name}" # 回款记录 class RepaymentRecord(models.Model): record_id = models.AutoField(primary_key=True, verbose_name='记录编号') project_name = models.ForeignKey(ProjectLedger, on_delete=models.CASCADE, verbose_name='项目名称') primary_department = models.CharField(max_length=255, verbose_name='一级部门', null=False, blank=False) project_manager = models.CharField(max_length=255, verbose_name='项目负责人', null=False, blank=False) invoice = models.ForeignKey(InvoiceRecord, on_delete=models.CASCADE, verbose_name='开票记录') repayment_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='已回款金额', null=False, blank=False) class Meta: verbose_name = '回款记录表' verbose_name_plural = '回款记录表' unique_together = ('project_name', 'primary_department', 'invoice') def __str__(self): return f"Record #{self.record_id} - Invoice Number: {self.invoice.invoice_number}, Total Amount: {self.invoice.total_amount}" # 回款详情 class RepaymentDetail(models.Model): record_id = models.AutoField(primary_key=True, verbose_name='记录编号') repayment_record = models.ForeignKey(RepaymentRecord, on_delete=models.CASCADE, related_name='details', verbose_name='回款记录') repayment_date = models.DateField(verbose_name='回款时间', null=False, blank=False) repayment_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='回款金额(元)', null=False, blank=False) class Meta: verbose_name = '回款详情' verbose_name_plural = '回款详情' def __str__(self): return f"Detail #{self.record_id} - Repayment Amount: {self.repayment_amount}" # 员工提成情况表-未使用 class EmployeeCommission(models.Model): record_id = models.AutoField(primary_key=True, verbose_name='记录编号') project_id = models.ForeignKey(ProjectLedger, on_delete=models.CASCADE, verbose_name='项目编号') project_name = models.CharField(max_length=255, verbose_name='项目名称', null=False, blank=False) year_month = models.DateField(verbose_name='年月', null=False, blank=False) company_retained = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='公司留存(元)', null=False, blank=False) name = models.ForeignKey('hrm_mgnt.EmployeeInformation', on_delete=models.SET_NULL, null=True, verbose_name='姓名') primary_department = models.CharField(max_length=255, verbose_name='一级部门', null=False, blank=False) total_commission = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='提成总额(元)', null=False, blank=False) amount_paid = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='已发放金额(元)', null=False, blank=False) accrued_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='计提金额(元)', null=False, blank=False) chairman_fund = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='董事长资金池(元)', null=False, blank=False) class Meta: verbose_name = '员工提成情况表' verbose_name_plural = '员工提成情况表' def __str__(self): return f"Record #{self.record_id} - Project: {self.project_name}, Employee: {self.name}, Year-Month: {self.year_month}" # 员工提成记录修改表-未使用 class CommissionModification(models.Model): modification_id = models.AutoField(primary_key=True, verbose_name='修改记录ID') commission_record = models.ForeignKey(EmployeeCommission, on_delete=models.CASCADE, verbose_name='提成记录ID') modified_field = models.CharField(max_length=255, verbose_name='修改金额字段', null=False, blank=False) previous_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='修改前金额(元)', null=False, blank=False) modified_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='修改后金额(元)', null=False, blank=False) modified_by = models.CharField(max_length=255, verbose_name='修改人', null=False, blank=False) modification_date = models.DateTimeField(verbose_name='修改时间', auto_now_add=True) class Meta: verbose_name = '员工提成记录修改表' verbose_name_plural = '员工提成记录修改表' def __str__(self): return f"Modification #{self.modification_id} - Commission Record: {self.commission_record}, Modified By: {self.modified_by}, Modification Date: {self.modification_date}" # 项目提成情况表 class ProjectCommission(models.Model): record_id = models.AutoField(primary_key=True, verbose_name='记录编号') project_name = models.ForeignKey('pjt_mgnt.ProjectLedger', on_delete=models.CASCADE, verbose_name='项目名称') primary_department = models.CharField(max_length=255, verbose_name='一级部门', null=False, blank=False) year_month = models.DateField(verbose_name='年月', null=False, blank=False) company_retained = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='公司留存(元)', null=False, blank=False) total_commission = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='提成总额(元)', null=False, blank=False) chairman_fund = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='董事长资金池(元)', null=False, blank=False) class Meta: verbose_name = '项目提成情况表' verbose_name_plural = '项目提成情况表' def __str__(self): return f"Record #{self.record_id} - Project: {self.project_name}, Year-Month: {self.year_month}" # 员工提成情况 class EmployeeCommissionDetail(models.Model): PERFORMANCE_CHOICES = ( ('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D') ) record_id = models.AutoField(primary_key=True, verbose_name='记录编号') project_commission = models.ForeignKey(ProjectCommission, on_delete=models.CASCADE, related_name='employee_commissions', verbose_name='项目提成情况') employee = models.ForeignKey('hrm_mgnt.EmployeeInformation', on_delete=models.CASCADE, verbose_name='员工') primary_department = models.CharField(max_length=255, verbose_name='一级部门', null=False, blank=False) year = models.IntegerField(verbose_name='年度', null=False, blank=False) performance_score = models.CharField(max_length=255, choices=PERFORMANCE_CHOICES, verbose_name='年度绩效') total_commission = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='提成金额(元)', null=False, blank=False) amount_paid = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='已发放金额(元)', null=False, blank=False) accrued_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='计提金额(元)', null=False, blank=False) back_pay_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='补发金额(元)', null=False, blank=False) deduction_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='扣除金额(元)', null=False, blank=False) class Meta: verbose_name = '员工提成详情表' verbose_name_plural = '员工提成详情表' def __str__(self): return f"Record #{self.record_id} - Employee: {self.employee.name}, Year: {self.year}" def save(self, *args, **kwargs): super().save(*args, **kwargs) self.update_project_commission_total() def update_project_commission_total(self): total_commission = self.project_commission.employee_commissions.aggregate(total=models.Sum('total_commission'))['total'] self.project_commission.total_commission = total_commission self.project_commission.save()