from collections import defaultdict from decimal import Decimal from django.db import models from django.db.models import Sum, F from django.utils import timezone from application.fac_mgnt.models import ReimbursementDetail, LaborCostDetail, RepaymentRecord, InvoiceRecord, \ GroupAnnualBudget, ProjectCommission, EmployeeCommissionDetail from application.hrm_mgnt.models import EmployeeInformation, EmployeeAttendanceRecord, OtherLeaveDetails from application.org_mgnt.models import PrimaryDepartment from application.perf_mgnt.models import GroupBusinessTarget, EmployeePerformanceTarget from application.pjt_mgnt.models import ProjectLedger, ChildProjectLedgerA, ChildProjectLedgerD, ChildProjectLedgerC, \ ChildProjectLedgerB, EmployeeProjectIncomeSettlement class UpdateLog(models.Model): table_name = models.CharField(max_length=255, unique=True, verbose_name="表名") last_update = models.DateField(verbose_name="最后更新时间", default=timezone.now) class Meta: verbose_name = "更新记录" verbose_name_plural = "更新记录" def __str__(self): return f"{self.table_name} - {self.last_update}" # 1.业务部门年度总体经营指标 class DepartmentAnnualPerformance(models.Model): """ 年度营业收入(万元)(=价税合计金额按一级部门和年份筛选完后的累计值)及 完成率(= 年度营业收入 / 收入总目标)【项目台账-价税合计金额, 集团经营目标-收入总目标】 年度新增收入(万元)(=价税合计金额按一级部门、年份、性质筛选完后的累计值)及 完成率(=年度新增收入/ 新增收入目标)【项目台账-价税合计金额, 集团经营目标-新增收入总目标】 年度存量收入(万元) (=价税合计金额按一级部门、年份、性质筛选完后的累计值)及 完成率(=年度存量收入 / 存量收入目标)【项目台账-价税合计金额, 集团经营目标-存量收入目标】 年度营业成本(万元) (=价税合计金额累计-应收净收入累计)及 占用率(年度营业成本 / 成本限额)【项目台账-价税合计金额,项目台账-应收净收入, 集团经营目标-存量收入目标, 集团经营目标表-成本限额 】 年度费用开销(万元) (=费用金额累计 + 全勤奖 + 餐津贴 + 其他货币性福利 + 实发工资 + 公司承担社保 + 公司承担公积金)及 占用率(=年度费用开销 / 费用限额)【报销明细-费用金额 ,人工费用明细-全勤奖、午餐津贴、其他货币型福利、实发工资、公司承担社保、公司承担公积金, 集团经营目标-费用限额 】 营业利润(万元) (=年度营业收入-年度营业成本-年度费用开销-开票税金(=税额按部门按年累计*1.12))【回款记录-不含税金额】 """ primary_department = models.CharField(max_length=255, verbose_name="一级部门") year = models.IntegerField(verbose_name="年份", help_text="表示数据统计的年份") annual_revenue = models.FloatField(verbose_name="年度营业收入(万元)", null=True, blank=True) annual_revenue_completion_rate = models.FloatField(verbose_name="年度营业收入完成率(%)", null=True, blank=True) annual_new_revenue = models.FloatField(verbose_name="年度新增收入(万元)", null=True, blank=True) annual_new_revenue_completion_rate = models.FloatField(verbose_name="年度新增收入完成率(%)", null=True, blank=True) annual_existing_revenue = models.FloatField(verbose_name="年度存量收入(万元)", null=True, blank=True) annual_existing_revenue_completion_rate = models.FloatField(verbose_name="年度存量收入完成率(%)", null=True, blank=True) annual_operating_costs = models.FloatField(verbose_name="年度营业成本(万元)", null=True, blank=True) annual_operating_costs_utilization_rate = models.FloatField(verbose_name="年度营业成本占用率(%)", null=True, blank=True) annual_expenses = models.FloatField(verbose_name="年度费用开销(万元)", null=True, blank=True) annual_expenses_utilization_rate = models.FloatField(verbose_name="年度费用开销占用率(%)", null=True, blank=True) operating_profit = models.FloatField(verbose_name="营业利润(万元)", null=True, blank=True) class Meta: verbose_name = "业务部门年度总体经营指标" verbose_name_plural = "业务部门年度总体经营指标" db_table_comment = '存储业务部门年度总体经营指标数据,包括一级部门、年份、营业收入及其完成率、新增收入及其完成率、存量收入及其完成率、营业成本及其占用率、费用开销及其占用率、营业利润等' def __str__(self): return f"{self.year} 年 {self.primary_department} 的经营指标" @staticmethod def calculate_and_update_for_year(year): primary_departments = PrimaryDepartment.objects.all() for department in primary_departments: primary_department = department.department_name # 年度营业收入 annual_revenue = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') annual_revenue = float(annual_revenue) # 收入总目标 total_revenue_target = GroupBusinessTarget.objects.filter( primary_department=primary_department, year=year ).aggregate(total=Sum('total_revenue_target'))['total'] or Decimal('1') # 避免除以零 total_revenue_target = float(total_revenue_target) # 年度营业收入完成率 annual_revenue_completion_rate = annual_revenue / total_revenue_target # 年度新增收入 annual_new_revenue = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year, project_nature="新增" ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') annual_new_revenue = float(annual_new_revenue) # 新增收入总目标 new_revenue_target = GroupBusinessTarget.objects.filter( primary_department=primary_department, year=year ).aggregate(total=Sum('new_revenue_target'))['total'] or Decimal('1') new_revenue_target = float(new_revenue_target) # 年度新增收入完成率 annual_new_revenue_completion_rate = Decimal(annual_new_revenue / new_revenue_target) # 年度存量收入 annual_existing_revenue = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year, project_nature="存量" ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') annual_existing_revenue = float(annual_existing_revenue) # 存量收入总目标 existing_revenue_target = GroupBusinessTarget.objects.filter( primary_department=primary_department, year=year ).aggregate(total=Sum('existing_revenue_target'))['total'] or Decimal('1') existing_revenue_target = float(existing_revenue_target) # 年度存量收入完成率 annual_existing_revenue_completion_rate = Decimal(annual_existing_revenue / existing_revenue_target) # 年度营业成本 total_amount_including_tax = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') total_amount_including_tax = float(total_amount_including_tax) net_receivable_amount = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year ).aggregate(total=Sum('receivable_net_income'))['total'] or Decimal('0') net_receivable_amount = float(net_receivable_amount) annual_operating_costs = Decimal(total_amount_including_tax - net_receivable_amount) # 成本限额 cost_limit = GroupBusinessTarget.objects.filter( primary_department=primary_department, year=year ).aggregate(total=Sum('cost_limit'))['total'] or Decimal('1') cost_limit = float(cost_limit) # 年度营业成本占用率 annual_operating_costs_utilization_rate = Decimal(float(annual_operating_costs) / cost_limit) # 年度费用开销 reimbursement_amount = ReimbursementDetail.objects.filter( primary_department=primary_department, year_month__year=year ).aggregate(total=Sum('amount'))['total'] or Decimal('0') reimbursement_amount = float(reimbursement_amount) labor_cost = LaborCostDetail.objects.filter( primary_department=primary_department, year_month__year=year ).aggregate( attendance_reward=Sum('attendance_reward'), lunch_allowance=Sum('lunch_allowance'), other_monetary_benefits=Sum('other_monetary_benefits'), net_salary=Sum('net_salary'), employer_social_security=Sum('employer_social_security'), employer_housing_fund=Sum('employer_housing_fund') ) labor_cost_total = sum(float(value or 0) for value in labor_cost.values()) annual_expenses = Decimal(reimbursement_amount + labor_cost_total) # 费用限额 expense_limit = GroupBusinessTarget.objects.filter( primary_department=primary_department, year=year ).aggregate(total=Sum('expense_limit'))['total'] or Decimal('1') expense_limit = float(expense_limit) # 年度费用开销占用率 annual_expenses_utilization_rate = Decimal(float(annual_expenses) / expense_limit) # 营业利润 amount_excluding_tax = InvoiceRecord.objects.filter( primary_department=primary_department, invoice_date__year=year ).aggregate(total=Sum('amount_excluding_tax'))['total'] or Decimal('0') amount_excluding_tax = float(amount_excluding_tax) operating_profit = Decimal( annual_revenue - float(annual_operating_costs) - float(annual_expenses) - (amount_excluding_tax * 1.12)) # 更新或创建模型实例 performance, created = DepartmentAnnualPerformance.objects.update_or_create( primary_department=primary_department, year=year, defaults={ 'annual_revenue': Decimal(annual_revenue), 'annual_revenue_completion_rate': round(annual_revenue_completion_rate, 2), 'annual_new_revenue': Decimal(annual_new_revenue), 'annual_new_revenue_completion_rate': round(annual_new_revenue_completion_rate, 2), 'annual_existing_revenue': Decimal(annual_existing_revenue), 'annual_existing_revenue_completion_rate': round(annual_existing_revenue_completion_rate, 2), 'annual_operating_costs': round(annual_operating_costs, 2), 'annual_operating_costs_utilization_rate': round(annual_operating_costs_utilization_rate, 2), 'annual_expenses': round(annual_expenses, 2), 'annual_expenses_utilization_rate': round(annual_expenses_utilization_rate, 2), 'operating_profit': round(operating_profit, 2) } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentAnnualPerformance', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_departments_for_year(cls, year): cls.calculate_and_update_for_year(year) # 2.收入情况 class DepartmentMonthlyIncome(models.Model): """ 当月收入 = 价税合计金额按一级部门和年月筛选完后的累计值 【项目台账-价税合计金额】 月收入目标 = 收入总目标/12 【集团经营目标-收入总目标】 月目标完成率 = 当月收入 / 月目标收入 当月新增收入 = 价税合计金额按年月、一级部门、性质筛选完后的累计值 【项目台账-价税合计金额】 月新增收入目标 = 新增收入目标 / 12 【集团经营目标-新增收入目标】 月新增收入完成率 = 当月新增收入 / 月新增收入目标 当月存量收入 = 当月存量收入按年月、一级部门、性质筛选完后的累计值 【项目台账-价税合计金额】 月存量收入目标 = 新增收入目标 / 12 【集团经营目标-新增收入目标】 月存量收入完成率 = 当月存量收入 / 月存量收入目标 年累计收入 = 价税合计金额按一级部门和当前筛选完后的累计值 【项目台账-价税合计金额】 累计目标完成率(年累计收入/ 收入总目标)【集团经营目标-收入总目标】 """ primary_department = models.CharField(max_length=255, verbose_name="一级部门", help_text="用于筛选、区分一级部门") year_month = models.CharField(max_length=7, verbose_name="年月", help_text="格式为'YYYY-MM',表示统计数据的年月") current_month_income = models.FloatField(verbose_name="当月收入(万元)", help_text="当月总收入,以万元为单位", null=True, blank=True) monthly_income_target = models.FloatField(verbose_name="月收入目标(万元)", help_text="当月收入目标,以万元为单位", null=True, blank=True) monthly_target_completion_rate = models.FloatField(verbose_name="月目标完成率(%)", help_text="当月收入与月收入目标的完成比率", null=True, blank=True) current_month_new_income = models.FloatField(verbose_name="当月新增收入(万元)", help_text="当月新增的收入,以万元为单位", null=True, blank=True) monthly_new_income_target = models.FloatField(verbose_name="月新增收入目标(万元)", help_text="当月新增收入的目标,以万元为单位", null=True, blank=True) monthly_new_income_completion_rate = models.FloatField(verbose_name="月新增收入完成率(%)", help_text="当月新增收入与月新增收入目标的完成比率", null=True, blank=True) current_month_existing_income = models.FloatField(verbose_name="当月存量收入(万元)", help_text="当月存量收入,以万元为单位", null=True, blank=True) monthly_existing_income_target = models.FloatField(verbose_name="月存量收入目标(万元)", help_text="当月存量收入的目标,以万元为单位", null=True, blank=True) monthly_existing_income_completion_rate = models.FloatField(verbose_name="月存量收入完成率(%)", help_text="当月存量收入与月存量收入目标的完成比率", null=True, blank=True) annual_accumulated_income = models.FloatField(verbose_name="年累计收入(万元)", help_text="年度累计收入,以万元为单位", null=True, blank=True) accumulated_target_completion_rate = models.FloatField(verbose_name="累计目标完成率(%)", help_text="年度累计收入与年度总收入目标的完成比率", null=True, blank=True) class Meta: verbose_name = "业务部门收入情况" verbose_name_plural = "业务部门收入情况" db_table_comment = '存储业务部门收入情况数据,包括一级部门、年月、当月收入及其目标和完成率、新增收入及其目标和完成率、存量收入及其目标和完成率、年累计收入及其目标完成率等' def __str__(self): return f"{self.year_month} 年 {self.primary_department} 的收入情况" @staticmethod def get_field_labels(): return { 'primary_department': '一级部门', 'year_month': '年月', 'current_month_income': '当月收入', 'monthly_income_target': '月收入目标', 'monthly_target_completion_rate': '月目标完成率', 'current_month_new_income': '当月新增收入', 'monthly_new_income_target': '月新增收入目标', 'monthly_new_income_completion_rate': '月新增收入完成率', 'current_month_existing_income': '当月存量收入', 'monthly_existing_income_target': '月存量收入目标', 'monthly_existing_income_completion_rate': '月存量收入完成率', 'annual_accumulated_income': '年累计收入', 'accumulated_target_completion_rate': '累计目标完成率', } def get_field_label(self, field_name): field_labels = self.get_field_labels() return field_labels.get(field_name, field_name) @staticmethod def calculate_and_update_for_month(year_month): primary_departments = PrimaryDepartment.objects.all() year, month = map(int, year_month.split('-')) for department in primary_departments: primary_department = department.department_name # 当月收入 current_month_income = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year, start_date__month=month ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') # 月收入目标 annual_revenue_target = GroupBusinessTarget.objects.filter( primary_department=primary_department, year=year ).aggregate(total=Sum('total_revenue_target'))['total'] or Decimal('1') monthly_income_target = annual_revenue_target / Decimal('12') # 月目标完成率 monthly_target_completion_rate = current_month_income / monthly_income_target # 当月新增收入 current_month_new_income = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year, start_date__month=month, project_nature="新增" ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') # 月新增收入目标 annual_new_revenue_target = GroupBusinessTarget.objects.filter( primary_department=primary_department, year=year ).aggregate(total=Sum('new_revenue_target'))['total'] or Decimal('1') monthly_new_income_target = annual_new_revenue_target / Decimal('12') # 月新增收入完成率 monthly_new_income_completion_rate = current_month_new_income / monthly_new_income_target # 当月存量收入 current_month_existing_income = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year, start_date__month=month, project_nature="存量" ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') # 月存量收入目标 monthly_existing_income_target = annual_new_revenue_target / Decimal('12') # 月存量收入完成率 monthly_existing_income_completion_rate = current_month_existing_income / monthly_existing_income_target # 年累计收入 annual_accumulated_income = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') # 累计目标完成率 accumulated_target_completion_rate = annual_accumulated_income / annual_revenue_target # 更新或创建模型实例 income, created = DepartmentMonthlyIncome.objects.update_or_create( primary_department=primary_department, year_month=year_month, defaults={ 'current_month_income': round(current_month_income, 2), 'monthly_income_target': round(monthly_income_target, 2), 'monthly_target_completion_rate': round(monthly_target_completion_rate, 2), 'current_month_new_income': round(current_month_new_income, 2), 'monthly_new_income_target': round(monthly_new_income_target, 2), 'monthly_new_income_completion_rate': round(monthly_new_income_completion_rate, 2), 'current_month_existing_income': round(current_month_existing_income, 2), 'monthly_existing_income_target': round(monthly_existing_income_target, 2), 'monthly_existing_income_completion_rate': round(monthly_existing_income_completion_rate, 2), 'annual_accumulated_income': round(annual_accumulated_income, 2), 'accumulated_target_completion_rate': round(accumulated_target_completion_rate, 2), } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentMonthlyIncome', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_departments_for_month(cls, year_month): cls.calculate_and_update_for_month(year_month) # 3.成本情况 class DepartmentMonthlyCost(models.Model): """ 当月成本 = 价税合计金额 - 应收净收入 【项目台账-价税合计金额, 项目台账- 应收净收入】 月成本限额 = 成本限额 / 12 【集团经营目标-成本限额】 月成本占用率 = 当月成本 / 月成本限额 年累计成本 = 当年成本累计值 累计成本占用率 = 年累计成本 / 成本限额 【集团经营目标-成本限额】 """ primary_department = models.CharField(max_length=255, verbose_name="一级部门", help_text="用于筛选、区分一级部门") year_month = models.CharField(max_length=7, verbose_name="年月", help_text="格式为'YYYY-MM',表示统计数据的年月") current_month_cost = models.FloatField(verbose_name="当月成本(万元)", help_text="当月成本总额,以万元为单位", null=True, blank=True) monthly_cost_limit = models.FloatField(verbose_name="月成本限额(万元)", help_text="每月的成本限额,以万元为单位", null=True, blank=True) monthly_cost_utilization_rate = models.FloatField(verbose_name="月成本占用率(%)", help_text="当月成本占用月成本限额的比率,以百分比表示", null=True, blank=True) annual_accumulated_cost = models.FloatField(verbose_name="年累计成本(万元)", help_text="年度累计成本总额,以万元为单位", null=True, blank=True) accumulated_cost_utilization_rate = models.FloatField(verbose_name="累计成本占用率(%)", help_text="年累计成本占用年度成本限额的比率,以百分比表示", null=True, blank=True) class Meta: verbose_name = "业务部门成本情况" verbose_name_plural = "业务部门成本情况" db_table_comment = '存储业务部门成本情况数据,包括一级部门、年月、当月成本及其限额和占用率、年累计成本及其占用率等' def __str__(self): return f"{self.year_month} 年 {self.primary_department} 的成本情况" @staticmethod def get_field_labels(): return { 'primary_department': '一级部门', 'year_month': '年月', 'current_month_cost': '当月成本(万元)', 'monthly_cost_limit': '月成本限额(万元)', 'monthly_cost_utilization_rate': '月成本占用率', 'annual_accumulated_cost': '年累计成本(万元)', 'accumulated_cost_utilization_rate': '累计成本占用率', } def get_field_label(self, field_name): field_labels = self.get_field_labels() return field_labels.get(field_name, field_name) @staticmethod def calculate_and_update_for_month(year_month): primary_departments = PrimaryDepartment.objects.all() year, month = map(int, year_month.split('-')) for department in primary_departments: primary_department = department.department_name # 当月成本 total_amount_including_tax = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year, start_date__month=month ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') net_receivable_amount = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year, start_date__month=month ).aggregate(total=Sum('receivable_net_income'))['total'] or Decimal('0') current_month_cost = total_amount_including_tax - net_receivable_amount # 月成本限额 annual_cost_limit = GroupBusinessTarget.objects.filter( primary_department=primary_department, year=year ).aggregate(total=Sum('cost_limit'))['total'] or Decimal('1') monthly_cost_limit = annual_cost_limit / Decimal('12') # 月成本占用率 monthly_cost_utilization_rate = current_month_cost / monthly_cost_limit # 年累计成本 # 价税合计金额按年合计 total_amount_including_tax_year = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') receivable_net_income_year = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year ).aggregate(total=Sum('receivable_net_income'))['total'] or Decimal('0') annual_accumulated_cost = total_amount_including_tax_year - receivable_net_income_year # 累计成本占用率 accumulated_cost_utilization_rate = annual_accumulated_cost / annual_cost_limit # 更新或创建模型实例 cost, created = DepartmentMonthlyCost.objects.update_or_create( primary_department=primary_department, year_month=year_month, defaults={ 'current_month_cost': round(current_month_cost, 2), 'monthly_cost_limit': round(monthly_cost_limit, 2), 'monthly_cost_utilization_rate': round(monthly_cost_utilization_rate, 2), 'annual_accumulated_cost': round(annual_accumulated_cost, 2), 'accumulated_cost_utilization_rate': round(accumulated_cost_utilization_rate, 2) } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentMonthlyCost', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_departments_for_month(cls, year_month): cls.calculate_and_update_for_month(year_month) # 4.费用情况 class DepartmentExpense(models.Model): """ 费用情况 年月、费用类型、费用明细、费用限额(集团年度预算表-按一级部门年份费用类型费用明细筛选后取金额) 已报销额度(报销明细表-费用金额按时间、类型、明细筛选后汇总,算当年总额) 可用额度(=费用限额-已报销额度) """ primary_department = models.CharField(max_length=255, verbose_name="一级部门", help_text="用于筛选、区分一级部门") year_month = models.CharField(max_length=7, verbose_name="年月", help_text="格式为'YYYY-MM',表示统计数据的年月") expense_type = models.CharField(max_length=255, verbose_name="费用类型") expense_detail = models.CharField(max_length=255, verbose_name="费用明细") expense_limit = models.FloatField(verbose_name="费用限额(元)", null=True, blank=True) reimbursed_amount = models.FloatField(verbose_name="已报销额度(元)", null=True, blank=True) available_amount = models.FloatField(verbose_name="可用额度(元)", null=True, blank=True) class Meta: verbose_name = "费用情况" verbose_name_plural = "费用情况" db_table_comment = '存储业务部门费用情况数据,包括一级部门、年月、费用类型、费用明细、费用限额、已报销额度、可用额度等' def __str__(self): return f"{self.year_month} 年 {self.primary_department} 的费用情况" @staticmethod def calculate_and_update_for_month(year_month): primary_departments = PrimaryDepartment.objects.all() year, month= map(int, year_month.split('-')) for department in primary_departments: primary_department = department.department_name # 从集团年度预算表获取费用类型和费用明细 budget_entries = GroupAnnualBudget.objects.filter( primary_department=primary_department, year=year ) for entry in budget_entries: expense_type = entry.expense_type.expense_type expense_type_instance = entry.expense_type expense_detail = entry.expense_detail.expense_detail expense_detail_instance = entry.expense_detail # 费用限额 expense_limit = entry.amount # 已报销额度 reimbursed_amount = ReimbursementDetail.objects.filter( primary_department=primary_department, year_month__icontains=year_month, expense_type=expense_type_instance, expense_detail=expense_detail_instance ).aggregate(total=Sum('amount'))['total'] or Decimal('0') # 可用额度 available_amount = expense_limit - reimbursed_amount # 更新或创建模型实例 expense, created = DepartmentExpense.objects.update_or_create( primary_department=primary_department, year_month=year_month, expense_type=expense_type, expense_detail=expense_detail, defaults={ 'expense_limit': expense_limit, 'reimbursed_amount': reimbursed_amount, 'available_amount': available_amount, } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentExpense', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_departments_for_month(cls, year_month): cls.calculate_and_update_for_month(year_month) # 5.利润情况 class DepartmentMonthlyProfit(models.Model): """ 费用情况 年月、营业利润(万元)、年累计营业利润(万元) 营业利润(万元)=【项目台账-应收净收入】应收净收入按一级部门、年月筛选-【报销明细表-费用金额】费用金额按一级部门、年月筛选累计-【人工费用明细-全勤奖、午餐津贴、其他货币性福利、实发工资、公司承担社保、公司承担公积金】(全勤奖+午餐津贴+其他货币性福利+实发工资+公司承担社保+公司承担公积金)按一级部门、年月筛选累计-【开票记录-不含税金额】税额按一级部门、年月筛选累计*1.12 """ primary_department = models.CharField(max_length=255, verbose_name="一级部门", help_text="用于筛选、区分一级部门") year_month = models.CharField(max_length=7, verbose_name="年月", help_text="格式为'YYYY-MM',表示统计数据的年月") operating_profit = models.FloatField(verbose_name="营业利润", help_text="当月的营业利润,计算方式如描述,以万元为单位", null=True, blank=True) annual_operating_profit = models.FloatField(verbose_name="年累计营业利润", help_text="当年的累计营业利润,以万元为单位", null=True, blank=True) class Meta: verbose_name = "业务部门利润情况" verbose_name_plural = "业务部门利润情况" db_table_comment = '存储业务部门利润情况数据,包括一级部门、年月、当月营业利润和年累计营业利润等' def __str__(self): return f"{self.year_month} 年 {self.primary_department} 的利润情况" @staticmethod def get_field_labels(): return { 'primary_department': '一级部门', 'year_month': '年月', 'operating_profit': '营业利润', 'annual_operating_profit': '年累计营业利润', } def get_field_label(self, field_name): field_labels = self.get_field_labels() return field_labels.get(field_name, field_name) @staticmethod def calculate_and_update_for_month(year_month): primary_departments = PrimaryDepartment.objects.all() year, month = map(int, year_month.split('-')) for department in primary_departments: primary_department = department.department_name # 应收净收入 net_receivable_income = ProjectLedger.objects.filter( primary_department=primary_department, start_date__year=year, start_date__month=month ).aggregate(total=Sum('receivable_net_income'))['total'] or Decimal('0') # 费用金额 reimbursed_amount = ReimbursementDetail.objects.filter( primary_department=primary_department, year_month__year=year, year_month__month=month ).aggregate(total=Sum('amount'))['total'] or Decimal('0') # 人工费用 labor_cost = LaborCostDetail.objects.filter( primary_department=primary_department, year_month__year=year, year_month__month=month ).aggregate( attendance_reward=Sum('attendance_reward'), lunch_allowance=Sum('lunch_allowance'), other_monetary_benefits=Sum('other_monetary_benefits'), net_salary=Sum('net_salary'), employer_social_security=Sum('employer_social_security'), employer_housing_fund=Sum('employer_housing_fund') ) labor_cost_total = sum(value or Decimal('0') for value in labor_cost.values()) # 开票税金 tax_amount = InvoiceRecord.objects.filter( primary_department=primary_department, invoice_date__year=year, invoice_date__month=month ).aggregate(total=Sum('amount_excluding_tax'))['total'] or Decimal('0') # 营业利润 operating_profit = net_receivable_income - reimbursed_amount - labor_cost_total - (tax_amount * Decimal('1.12')) # 年累计营业利润 annual_operating_profit = DepartmentMonthlyProfit.objects.filter( primary_department=primary_department, year_month=year_month ).aggregate(total=Sum('operating_profit'))['total'] or Decimal('0') annual_operating_profit = float(annual_operating_profit) + float(operating_profit) # 更新或创建模型实例 profit, created = DepartmentMonthlyProfit.objects.update_or_create( primary_department=primary_department, year_month=year_month, defaults={ 'operating_profit': operating_profit, 'annual_operating_profit': annual_operating_profit, } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentMonthlyProfit', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_departments_for_month(cls, year_month): cls.calculate_and_update_for_month(year_month) # 6.项目进度 class DepartmentProjectProgress(models.Model): """ 所有均摘自表28项目台账中对应的信息 项目类型根据一级部门不同有所区别 """ primary_department = models.CharField(max_length=255, verbose_name="一级部门", help_text="用于筛选、区分一级部门", blank=True, null=True) project_name = models.CharField(max_length=255, verbose_name="项目名称", help_text="项目的名称", blank=True, null=True) project_type = models.CharField(max_length=255, verbose_name="项目类型", help_text="项目的类型,如开发、研究等", blank=True, null=True) project_manager = models.CharField(max_length=255, verbose_name="负责人", help_text="负责项目的人员", blank=True, null=True) project_status = models.CharField(max_length=255, verbose_name="项目状态", help_text="项目当前的状态,如进行中、已完成、暂停等", blank=True, null=True) project_progress = models.CharField(max_length=255, verbose_name="项目进度", help_text="项目的完成进度,通常以百分比表示", blank=True, null=True) project_nature = models.CharField(max_length=255, verbose_name="项目性质", help_text="项目的性质,如内部项目、外包项目等", blank=True, null=True) contract_date = models.DateField(verbose_name="签约时间", help_text="项目签约的日期", blank=True, null=True) target_amount = models.FloatField(verbose_name="标的金额(元)", help_text="项目的标的金额,以元为单位", blank=True, null=True) contract_rate = models.FloatField(verbose_name="合同费率", help_text="项目合同中约定的费率", blank=True, null=True) revenue = models.FloatField(verbose_name="收入(元)", help_text="项目实际产生的收入,以元为单位", blank=True, null=True) cost_rate = models.FloatField(verbose_name="成本费率", help_text="项目成本的费率", blank=True, null=True) cost = models.FloatField(verbose_name="成本(元)", help_text="项目的实际成本,以元为单位", blank=True, null=True) net_income = models.FloatField(verbose_name="净收入(元)", help_text="项目的净收入,计算为收入减去成本", blank=True, null=True) transaction_amount = models.FloatField(verbose_name="成交金额(元)", help_text="项目的成交金额,以元为单位", blank=True, null=True) total_tax_inclusive_amount = models.FloatField(verbose_name="价税合计金额(元)", help_text="项目的价税合计金额,以元为单位", blank=True, null=True) payment_received = models.FloatField(verbose_name="回款金额(元)", help_text="项目实际已回款的金额,以元为单位", blank=True, null=True) class Meta: verbose_name = "业务部门项目进度" verbose_name_plural = "业务部门项目进度" db_table_comment = '存储业务部门项目进度数据,包括一级部门、项目名称、项目类型、负责人、项目状态、项目进度、项目性质、签约时间、标的金额、合同费率、收入、成本费率、成本、净收入、成交金额、价税合计金额和回款金额等' def __str__(self): return f"{self.primary_department} 部门的项目 {self.project_name} 进度" @staticmethod def get_field_labels(): return { 'primary_department': '一级部门', 'project_name': '项目名称', 'project_type': '项目类型', 'project_manager': '负责人', 'project_status': '项目状态', 'project_progress': '项目进度', 'project_nature': '项目性质', 'contract_date': '签约时间', 'target_amount': '标的金额(元)', 'contract_rate': '合同费率', 'revenue': '收入(元)', 'cost_rate': '成本费率', 'cost': '成本(元)', 'net_income': '净收入(元)', 'transaction_amount': '成交金额(元)', 'total_tax_inclusive_amount': '价税合计金额(元)', 'payment_received': '回款金额(元)', } def get_field_label(self, field_name): field_labels = self.get_field_labels() return field_labels.get(field_name, field_name) @staticmethod def calculate_and_update_progress(): primary_departments = PrimaryDepartment.objects.all() for department in primary_departments: primary_department = department.department_name # 从项目台账中获取项目进度相关数据 projects = ProjectLedger.objects.filter(primary_department=primary_department) def get_project_type(): pd = project.primary_department pt = None if pd in ['天信', '混改']: sub_project = ChildProjectLedgerA.objects.filter(project_id=project.project_id).first() if sub_project: pt = sub_project.project_type elif pd == '艾力芬特': sub_project = ChildProjectLedgerB.objects.filter(project_id=project.project_id).first() if sub_project: pt = sub_project.project_type elif pd == '星河': sub_project = ChildProjectLedgerC.objects.filter(project_id=project.project_id).first() if pd: pt = sub_project.project_type elif pd == '星海': sub_project = ChildProjectLedgerD.objects.filter(project_id=project.project_id).first() if sub_project: pt = sub_project.project_type return pt for project in projects: project_name = project.project_name project_type = get_project_type() project_manager = project.project_leader project_status = project.project_status project_progress = project.project_progress project_nature = project.project_nature contract_date = project.contract_date contract_amount = project.contract_amount contract_rate = project.contract_rate revenue = project.revenue cost_rate = project.cost_rate cost = project.cost net_income = revenue - cost if revenue and cost else 0 transaction_amount = project.contract_amount total_tax_inclusive_amount = project.total_amount_including_tax payment_received = project.repayment_amount # 更新或创建模型实例 progress, created = DepartmentProjectProgress.objects.update_or_create( primary_department=primary_department, project_name=project_name, defaults={ 'project_type': project_type, 'project_manager': project_manager, 'project_status': project_status, 'project_progress': project_progress, 'project_nature': project_nature, 'contract_date': contract_date, 'target_amount': contract_amount, 'contract_rate': contract_rate, 'revenue': revenue, 'cost_rate': cost_rate, 'cost': cost, 'net_income': net_income, 'transaction_amount': transaction_amount, 'total_tax_inclusive_amount': total_tax_inclusive_amount, 'payment_received': payment_received, } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentProjectProgress', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_projects_progress(cls): cls.calculate_and_update_progress() # 7.项目结算情况 class DepartmentProjectSettlement(models.Model): """ 项目结算情况 项目名称、营业收入、营业成本、税金及附加、营业利润、公司留存、项目提成、项目公积金 """ primary_department = models.CharField(max_length=255, verbose_name="一级部门", help_text="用于筛选、区分一级部门") project_name = models.CharField(max_length=255, verbose_name="项目名称", help_text="项目的名称") revenue = models.FloatField(verbose_name="营业收入(元)", help_text="项目的总营业收入", null=True, blank=True) operating_costs = models.FloatField(verbose_name="营业成本(元)", help_text="项目的总营业成本", null=True, blank=True) taxes_and_surcharges = models.FloatField(verbose_name="税金及附加(元)", help_text="项目相关的税金及附加费用,根据公式计算", null=True, blank=True) operating_profit = models.FloatField(verbose_name="营业利润(元)", help_text="项目的营业利润,计算为营业收入减去营业成本和税金及附加", null=True, blank=True) company_retention = models.FloatField(verbose_name="公司留存(元)", help_text="项目为公司留存的部分收益", null=True, blank=True) project_commission = models.FloatField(verbose_name="项目提成(元)", help_text="项目团队的提成金额", null=True, blank=True) project_provision_fund = models.FloatField(verbose_name="项目公积金(元)", help_text="从营业利润中提取的项目公积金", null=True, blank=True) class Meta: verbose_name = "业务部门项目结算情况" verbose_name_plural = "业务部门项目结算情况" db_table_comment = '存储业务部门项目结算情况数据,包括一级部门、项目名称、营业收入、营业成本、税金及附加、营业利润、公司留存、项目提成和项目公积金等' def __str__(self): return f"{self.primary_department} 部门的项目 {self.project_name} 结算情况" @staticmethod def get_field_labels(): return { 'primary_department': '一级部门', 'project_name': '项目名称', 'revenue': '营业收入(元)', 'operating_costs': '营业成本(元)', 'taxes_and_surcharges': '税金及附加(元)', 'operating_profit': '营业利润(元)', 'company_retention': '公司留存(元)', 'project_commission': '项目提成(元)', 'project_provision_fund': '项目公积金(元)', } def get_field_label(self, field_name): field_labels = self.get_field_labels() return field_labels.get(field_name, field_name) @staticmethod def calculate_and_update_settlement(): primary_departments = PrimaryDepartment.objects.all() for department in primary_departments: primary_department = department.department_name # 从项目台账中获取项目结算相关数据 projects = ProjectLedger.objects.filter(primary_department=primary_department) for project in projects: project_name = project.project_name # 营业收入 revenue = ProjectLedger.objects.filter( primary_department=primary_department, project_name=project_name ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') # 营业成本 net_receivable_income = ProjectLedger.objects.filter( primary_department=primary_department, project_name=project_name ).aggregate(total=Sum('receivable_net_income'))['total'] or Decimal('0') operating_costs = revenue - net_receivable_income # 税金及附加 tax_amount = InvoiceRecord.objects.filter( primary_department=primary_department, project_name=project ).aggregate(total=Sum('tax_amount'))['total'] or Decimal('0') taxes_and_surcharges = tax_amount * Decimal('1.12') # 营业利润 operating_profit = revenue - operating_costs - taxes_and_surcharges # 公司留存和项目提成 project_commission_record = ProjectCommission.objects.filter( primary_department=primary_department, project_name=project ).first() company_retention = project_commission_record.company_retained if project_commission_record else Decimal('0') project_commission = project_commission_record.total_commission if project_commission_record else Decimal('0') # 项目公积金 project_provision_fund = operating_profit - company_retention - project_commission # 更新或创建模型实例 settlement, created = DepartmentProjectSettlement.objects.update_or_create( primary_department=primary_department, project_name=project_name, defaults={ 'revenue': revenue, 'operating_costs': operating_costs, 'taxes_and_surcharges': taxes_and_surcharges, 'operating_profit': operating_profit, 'company_retention': company_retention, 'project_commission': project_commission, 'project_provision_fund': project_provision_fund, } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentProjectSettlement', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_projects_settlement(cls): cls.calculate_and_update_settlement() # 8.项目回款情况 class DepartmentProjectPayment(models.Model): """ 项目回款情况 """ primary_department = models.CharField(max_length=255, verbose_name="一级部门", help_text="用于筛选、区分一级部门", null=True, blank=True) project_name = models.CharField(max_length=255, verbose_name="项目名称", help_text="项目的名称", null=True, blank=True) project_type = models.CharField(max_length=255, verbose_name="项目类型", help_text="项目的类型", null=True, blank=True) project_manager = models.CharField(max_length=255, verbose_name="负责人", help_text="负责项目的人员", null=True, blank=True) total_tax_inclusive_amount = models.FloatField(verbose_name="价税合计金额(元)", help_text="项目的价税合计金额,累计数", null=True, blank=True) payment_received = models.FloatField(verbose_name="回款金额(元)", help_text="项目的回款金额,累计数", null=True, blank=True) outstanding_payment_amount = models.FloatField(verbose_name="待回款金额(元)", help_text="计算得出的待回款金额,价税合计金额减去回款金额", null=True, blank=True) receivable_net_income = models.FloatField(verbose_name="应收净收入(元)", help_text="应收的净收入,累计数", null=True, blank=True) actual_net_income = models.FloatField(verbose_name="实收净收入(元)", help_text="实际收到的净收入,累计数", null=True, blank=True) outstanding_net_income = models.FloatField(verbose_name="待收净收入(元)", help_text="待收净收入,计算为应收净收入减去实收净收入", null=True, blank=True) class Meta: verbose_name = "业务部门项目回款情况" verbose_name_plural = "业务部门项目回款情况" db_table_comment = '存储业务部门项目回款情况,包括一级部门、项目名称、项目类型、负责人、价税合计金额、回款金额、待回款金额、应收净收入、实收净收入和待收净收入等' def __str__(self): return f"Department Project Payment for {self.project_name} in {self.primary_department}" @staticmethod def get_field_labels(): return { 'primary_department': '一级部门', 'project_name': '项目名称', 'project_type': '项目类型', 'project_manager': '负责人', 'total_tax_inclusive_amount': '价税合计金额(元)', 'payment_received': '回款金额(元)', 'outstanding_payment_amount': '待回款金额(元)', 'receivable_net_income': '应收净收入(元)', 'actual_net_income': '实收净收入(元)', 'outstanding_net_income': '待收净收入(元)', } def get_field_label(self, field_name): field_labels = self.get_field_labels() return field_labels.get(field_name, field_name) @staticmethod def calculate_and_update_payments(): primary_departments = PrimaryDepartment.objects.all() for department in primary_departments: primary_department = department.department_name # 从项目台账中获取项目回款相关数据 projects = ProjectLedger.objects.filter(primary_department=primary_department) def get_project_type(): pd = project.primary_department pt = None if pd in ['天信', '混改']: sub_project = ChildProjectLedgerA.objects.filter(project_id=project.project_id).first() if sub_project: pt = sub_project.project_type elif pd == '艾力芬特': sub_project = ChildProjectLedgerB.objects.filter(project_id=project.project_id).first() if sub_project: pt = sub_project.project_type elif pd == '星河': sub_project = ChildProjectLedgerC.objects.filter(project_id=project.project_id).first() if pd: pt = sub_project.project_type elif pd == '星海': sub_project = ChildProjectLedgerD.objects.filter(project_id=project.project_id).first() if sub_project: pt = sub_project.project_type return pt for project in projects: project_name = project.project_name project_type = get_project_type() project_manager = project.project_leader # 获取价税合计金额 total_tax_inclusive_amount = ProjectLedger.objects.filter( primary_department=primary_department, project_name=project_name ).aggregate(total=Sum('total_amount_including_tax'))['total'] or Decimal('0') # 获取回款金额 payment_received = RepaymentRecord.objects.filter( primary_department=primary_department, project_name=project ).aggregate(total=Sum('repayment_amount'))['total'] or Decimal('0') # 计算待回款金额 outstanding_payment_amount = total_tax_inclusive_amount - payment_received # 获取应收净收入 receivable_net_income = ProjectLedger.objects.filter( primary_department=primary_department, project_name=project_name ).aggregate(total=Sum('receivable_net_income'))['total'] or Decimal('0') # 获取实收净收入 actual_net_income = ProjectLedger.objects.filter( primary_department=primary_department, project_name=project_name ).aggregate(total=Sum('actual_net_income'))['total'] or Decimal('0') # 计算待收净收入 outstanding_net_income = receivable_net_income - actual_net_income # 更新或创建模型实例 payment, created = DepartmentProjectPayment.objects.update_or_create( primary_department=primary_department, project_name=project_name, defaults={ 'project_type': project_type, 'project_manager': project_manager, 'total_tax_inclusive_amount': total_tax_inclusive_amount, 'payment_received': payment_received, 'outstanding_payment_amount': outstanding_payment_amount, 'receivable_net_income': receivable_net_income, 'actual_net_income': actual_net_income, 'outstanding_net_income': outstanding_net_income, } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentProjectPayment', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_projects_payments(cls): cls.calculate_and_update_payments() # 9.收入结构 class DepartmentRevenueStructure(models.Model): """ 业务部门收入结构 """ primary_department = models.CharField(max_length=255, verbose_name="一级部门", help_text="用于筛选、区分一级部门") year_month = models.CharField(max_length=7, verbose_name="年月", help_text="格式为'YYYY-MM',表示统计数据的年月") project_type = models.CharField(max_length=255, verbose_name="项目类型", help_text="项目的分类类型") total_tax_inclusive_amount = models.FloatField(verbose_name="价税合计金额", help_text="当月按项目类型的价税合计金额", null=True, blank=True) percentage = models.FloatField(verbose_name="占比", help_text="该项目类型的价税合计金额占当月总收入的百分比", null=True, blank=True) cumulative_tax_inclusive_amount = models.FloatField(verbose_name="累计价税合计金额", help_text="从年初到当前月的累计价税合计金额", null=True, blank=True) cumulative_percentage = models.FloatField(verbose_name="累计占比", help_text="该项目类型的累计价税合计金额占当年1月至当月的", null=True, blank=True) class Meta: verbose_name = "业务部门收入结构" verbose_name_plural = "业务部门收入结构" db_table_comment = '存储业务部门收入结构数据,包括一级部门、年月、项目类型、价税合计金额、占比、累计价税合计金额和累计占比等' def __str__(self): return f"Department Revenue Structure for {self.primary_department} in {self.year_month}" @staticmethod def get_field_labels(): return { 'primary_department': '一级部门', 'year_month': '年月', 'project_type': '项目类型', 'total_tax_inclusive_amount': '价税合计金额', 'percentage': '占比', 'cumulative_tax_inclusive_amount': '累计价税合计金额', 'cumulative_percentage': '累计占比', } def get_field_label(self, field_name): field_labels = self.get_field_labels() return field_labels.get(field_name, field_name) @staticmethod def get_project_type(project): primary_department = project.primary_department project_type = None if primary_department == '天信': sub_project = ChildProjectLedgerA.objects.filter(project_id=project.project_id).first() if sub_project: project_type = sub_project.project_type elif primary_department == '星河': sub_project = ChildProjectLedgerC.objects.filter(project_id=project.project_id).first() if sub_project: project_type = sub_project.project_type elif primary_department == '星海': sub_project = ChildProjectLedgerD.objects.filter(project_id=project.project_id).first() if sub_project: project_type = sub_project.project_type return project_type @staticmethod def calculate_and_update_revenue_structure(year_month): year, month = map(int, year_month.split('-')) # 定义有子表的部门 valid_departments = ['天信', '星河', '星海'] # 用于存储各部门、项目类型的收入 revenue_data = defaultdict(lambda: defaultdict(Decimal)) cumulative_revenue_data = defaultdict(lambda: defaultdict(Decimal)) # 获取所有符合条件的项目 projects = ProjectLedger.objects.filter( primary_department__in=valid_departments, start_date__year=year, start_date__month=month ) for project in projects: primary_department = project.primary_department project_type = DepartmentRevenueStructure.get_project_type(project) if project_type: total_amount = project.total_amount_including_tax or Decimal('0') revenue_data[primary_department][project_type] += total_amount # 获取从年初到当前月的项目 cumulative_projects = ProjectLedger.objects.filter( primary_department__in=valid_departments, start_date__year=year, ) for project in cumulative_projects: primary_department = project.primary_department project_type = DepartmentRevenueStructure.get_project_type(project) if project_type: cumulative_amount = project.total_amount_including_tax or Decimal('0') cumulative_revenue_data[primary_department][project_type] += cumulative_amount for primary_department in valid_departments: # 获取当月总收入 total_revenue = revenue_data[primary_department].values() total_revenue = sum(total_revenue) if total_revenue else Decimal('0') # 获取累计总收入 cumulative_revenue = cumulative_revenue_data[primary_department].values() cumulative_revenue = sum(cumulative_revenue) if cumulative_revenue else Decimal('0') for project_type, total_tax_inclusive_amount in revenue_data[primary_department].items(): percentage = (total_tax_inclusive_amount / total_revenue * 100) if total_revenue > 0 else 0 cumulative_tax_inclusive_amount = cumulative_revenue_data[primary_department][project_type] cumulative_percentage = ( cumulative_tax_inclusive_amount / cumulative_revenue * 100) if cumulative_revenue > 0 else 0 # 更新或创建模型实例 DepartmentRevenueStructure.objects.update_or_create( primary_department=primary_department, year_month=year_month, project_type=project_type, defaults={ 'total_tax_inclusive_amount': round(total_tax_inclusive_amount, 2), 'percentage': round(percentage, 2), 'cumulative_tax_inclusive_amount': round(cumulative_tax_inclusive_amount, 2), 'cumulative_percentage': round(cumulative_percentage, 2), } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentRevenueStructure', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_departments_revenue_structure(cls, year_month): cls.calculate_and_update_revenue_structure(year_month) # 10.利润结果 class DepartmentProfitStructure(models.Model): """ 业务部门利润结构 """ primary_department = models.CharField(max_length=255, verbose_name="一级部门", help_text="用于筛选、区分一级部门") year_month = models.CharField(max_length=7, verbose_name="年月", help_text="格式为'YYYY-MM',表示统计数据的年月") project_type = models.CharField(max_length=255, verbose_name="项目类型", help_text="项目的分类类型") net_receivable_income = models.FloatField(verbose_name="应收净收入(元)", help_text="当月按项目类型的应收净收入", null=True, blank=True) percentage = models.FloatField(verbose_name="占比", help_text="该项目类型的应收净收入占当月总利润的百分比", null=True, blank=True) cumulative_net_receivable_income = models.FloatField(verbose_name="累计应收净收入(元)", help_text="从年初到当前月的累计应收净收入", null=True, blank=True) cumulative_percentage = models.FloatField(verbose_name="累计占比", help_text="该项目类型的累计应收净收入占当年1月至当月的", null=True, blank=True) class Meta: verbose_name = "业务部门利润结构" verbose_name_plural = "业务部门利润结构" db_table_comment = '存储业务部门利润结构数据,包括一级部门、年月、项目类型、应收净收入、占比、累计应收净收入和累计占比等' def __str__(self): return f"Department Profit Structure for {self.primary_department} in {self.year_month}" @staticmethod def get_field_labels(): return { 'primary_department': '一级部门', 'year_month': '年月', 'project_type': '项目类型', 'net_receivable_income': '应收净收入(元)', 'percentage': '占比', 'cumulative_net_receivable_income': '累计应收净收入(元)', 'cumulative_percentage': '累计占比', } def get_field_label(self, field_name): field_labels = self.get_field_labels() return field_labels.get(field_name, field_name) @staticmethod def get_project_type(project): primary_department = project.primary_department project_type = None if primary_department == '天信': sub_project = ChildProjectLedgerA.objects.filter(project_id=project.project_id).first() if sub_project: project_type = sub_project.project_type elif primary_department == '星河': sub_project = ChildProjectLedgerC.objects.filter(project_id=project.project_id).first() if sub_project: project_type = sub_project.project_type elif primary_department == '星海': sub_project = ChildProjectLedgerD.objects.filter(project_id=project.project_id).first() if sub_project: project_type = sub_project.project_type return project_type @staticmethod def calculate_and_update_profit_structure(year_month): year, month = map(int, year_month.split('-')) # 定义有子表的部门 valid_departments = ['天信', '星河', '星海'] # 用于存储各部门、项目类型的利润 profit_data = defaultdict(lambda: defaultdict(Decimal)) cumulative_profit_data = defaultdict(lambda: defaultdict(Decimal)) # 获取所有符合条件的项目 projects = ProjectLedger.objects.filter( primary_department__in=valid_departments, start_date__year=year, start_date__month=month ) for project in projects: primary_department = project.primary_department project_type = DepartmentProfitStructure.get_project_type(project) if project_type: total_amount = project.receivable_net_income or Decimal('0') profit_data[primary_department][project_type] += total_amount # 获取从年初到当前月的项目 cumulative_projects = ProjectLedger.objects.filter( primary_department__in=valid_departments, start_date__year=year, ) for project in cumulative_projects: primary_department = project.primary_department project_type = DepartmentProfitStructure.get_project_type(project) if project_type: cumulative_amount = project.receivable_net_income or Decimal('0') cumulative_profit_data[primary_department][project_type] += cumulative_amount for primary_department in valid_departments: # 获取当月总利润 total_profit = profit_data[primary_department].values() total_profit = sum(total_profit) if total_profit else Decimal('0') # 获取累计总利润 cumulative_profit = cumulative_profit_data[primary_department].values() cumulative_profit = sum(cumulative_profit) if cumulative_profit else Decimal('0') for project_type, net_receivable_income in profit_data[primary_department].items(): percentage = (net_receivable_income / total_profit * 100) if total_profit > 0 else 0 cumulative_net_receivable_income = cumulative_profit_data[primary_department][project_type] cumulative_percentage = ( cumulative_net_receivable_income / cumulative_profit * 100) if cumulative_profit > 0 else 0 # 更新或创建模型实例 DepartmentProfitStructure.objects.update_or_create( primary_department=primary_department, year_month=year_month, project_type=project_type, defaults={ 'net_receivable_income': round(net_receivable_income, 2), 'percentage': round(percentage, 2), 'cumulative_net_receivable_income': round(cumulative_net_receivable_income, 2), 'cumulative_percentage': round(cumulative_percentage, 2), } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentProfitStructure', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_departments_profit_structure(cls, year_month): cls.calculate_and_update_profit_structure(year_month) # 项目经理收入完成及提成情况 class DepartmentProjectManagerIncomeCommission(models.Model): """ 项目经理收入完成及提成情况 """ primary_department = models.CharField(max_length=255, verbose_name="一级部门", help_text="用于筛选、区分一级部门") name = models.CharField(max_length=255, verbose_name="姓名", help_text="项目经理的姓名") year_month = models.CharField(max_length=7, verbose_name="年月", help_text="格式为'YYYY-MM',表示统计数据的年月") current_month_income = models.FloatField(verbose_name="当月收入", help_text="当月销售收入,按月累计,单位:元", null=True, blank=True) monthly_income_target = models.FloatField(verbose_name="月收入目标", help_text="当月收入目标,单位:元", null=True, blank=True) monthly_target_completion_rate = models.FloatField(verbose_name="月目标完成率", help_text="当月收入与月收入目标的比率", null=True, blank=True) annual_accumulated_income = models.FloatField(verbose_name="年累计收入", help_text="年度累计销售收入,单位:元", null=True, blank=True) annual_target_completion_rate = models.FloatField(verbose_name="累计目标完成率", help_text="项目经理年累计收入与部门收入目标比率", null=True, blank=True) current_month_commission = models.FloatField(verbose_name="当月提成", help_text="当月已发放的提成金额,单位:元", null=True, blank=True) current_month_accrued_commission = models.FloatField(verbose_name="当月计提提成", help_text="当月计提的提成金额,单位:元", null=True, blank=True) annual_accumulated_commission = models.FloatField(verbose_name="年累计提成", help_text="年度累计已发放的提成金额,单位:元", null=True, blank=True) annual_accumulated_accrued_commission = models.FloatField(verbose_name="年累计计提提成", help_text="年度累计计提的提成金额,单位:元", null=True, blank=True) class Meta: verbose_name = "业务部门项目经理收入完成及提成情况" verbose_name_plural = "业务部门项目经理收入完成及提成情况" db_table_comment = '存储业务部门项目经理收入完成及提成情况数据,包括一级部门、姓名、年月、当月收入、月收入目标、月目标完成率、年累计收入、累计目标完成率、当月提成、当月计提提成、年累计提成和年累计计提提成等' def __str__(self): return f"Income Commission for {self.name} in {self.year_month}" @staticmethod def get_field_labels(): return { 'primary_department': '一级部门', 'name': '姓名', 'year_month': '年月', 'current_month_income': '当月收入', 'monthly_income_target': '月收入目标', 'monthly_target_completion_rate': '月目标完成率', 'annual_accumulated_income': '年累计收入', 'annual_target_completion_rate': '累计目标完成率', 'current_month_commission': '当月提成', 'current_month_accrued_commission': '当月计提提成', 'annual_accumulated_commission': '年累计提成', 'annual_accumulated_accrued_commission': '年累计计提提成', } def get_field_label(self, field_name): field_labels = self.get_field_labels() return field_labels.get(field_name, field_name) @staticmethod def calculate_and_update_commissions(year_month): primary_departments = PrimaryDepartment.objects.all() year, month = map(int, year_month.split('-')) for department in primary_departments: primary_department = department.department_name # 获取部门经理 managers = EmployeeInformation.objects.filter( primary_department=primary_department, position='项目经理', status='在职' ) for manager in managers: name = manager.name # 当月收入 current_month_income = EmployeeProjectIncomeSettlement.objects.filter( primary_department=primary_department, name=name, year_month__year=year ).aggregate(total=Sum(F('sales_income')))['total'] or Decimal('0') # 月收入目标 income_target = EmployeePerformanceTarget.objects.filter( name=name, year=year ).aggregate(total=Sum('total_revenue_target'))['total'] or Decimal('0') monthly_income_target = income_target / 12 # 月目标完成率 monthly_target_completion_rate = (current_month_income / monthly_income_target) if monthly_income_target > 0 else 0 # 年累计收入 annual_accumulated_income = EmployeeProjectIncomeSettlement.objects.filter( primary_department=primary_department, name=name, year_month__year=year ).aggregate(total=Sum('sales_income'))['total'] or Decimal('0') # 累计目标完成率 annual_target_completion_rate = (annual_accumulated_income * 10000 / income_target) * 100 if income_target > 0 else 0 # 当月提成 current_month_commission = EmployeeCommissionDetail.objects.filter( employee__name=name, year=year, project_commission__year_month__year=year, project_commission__year_month__month=month ).aggregate(total=Sum('amount_paid'))['total'] or Decimal('0') # 当月计提提成 current_month_accrued_commission = EmployeeCommissionDetail.objects.filter( employee__name=name, year=year, project_commission__year_month__year=year, project_commission__year_month__month=month ).aggregate(total=Sum('accrued_amount'))['total'] or Decimal('0') # 年累计提成 annual_accumulated_commission = EmployeeCommissionDetail.objects.filter( primary_department=primary_department, employee__name=name, project_commission__year_month__year=year, ).aggregate(total=Sum('total_commission'))['total'] or Decimal('0') # 年累计计提提成 annual_accumulated_accrued_commission = EmployeeCommissionDetail.objects.filter( primary_department=primary_department, employee__name=name, project_commission__year_month__year=year, ).aggregate(total=Sum('accrued_amount'))['total'] or Decimal('0') # 更新或创建模型实例 commission, created = DepartmentProjectManagerIncomeCommission.objects.update_or_create( primary_department=primary_department, name=name, year_month=year_month, defaults={ 'current_month_income': current_month_income, 'monthly_income_target': monthly_income_target, 'monthly_target_completion_rate': monthly_target_completion_rate, 'annual_accumulated_income': annual_accumulated_income, 'annual_target_completion_rate': annual_target_completion_rate, 'current_month_commission': current_month_commission, 'current_month_accrued_commission': current_month_accrued_commission, 'annual_accumulated_commission': annual_accumulated_commission, 'annual_accumulated_accrued_commission': annual_accumulated_accrued_commission, } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentProjectManagerIncomeCommission', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_departments_commissions(cls, year_month): cls.calculate_and_update_commissions(year_month) # 出勤情况 class DepartmentAttendance(models.Model): primary_department = models.CharField(max_length=255, verbose_name="一级部门", help_text="用于筛选、区分一级部门") year_month = models.CharField(max_length=7, verbose_name="年月", help_text="格式为'YYYY-MM',表示统计数据的年月") late = models.IntegerField(verbose_name="迟到", help_text="当月累计迟到次数", null=True, blank=True, default=0) early_departure = models.IntegerField(verbose_name="早退", help_text="当月累计早退次数", null=True, blank=True, default=0) absenteeism = models.IntegerField(verbose_name="旷工", help_text="当月累计旷工天数", null=True, blank=True, default=0) annual_leave = models.IntegerField(verbose_name="年假", help_text="当月使用的年假天数", null=True, blank=True, default=0) personal_leave = models.IntegerField(verbose_name="事假", help_text="当月使用的事假天数", null=True, blank=True, default=0) sick_leave = models.IntegerField(verbose_name="病假", help_text="当月使用的病假天数", null=True, blank=True, default=0) other_leave = models.IntegerField(verbose_name="其他", help_text="当月使用的其他类型假期的天数", null=True, blank=True, default=0) total_days = models.IntegerField(verbose_name="合计", help_text="当月总假期天数,包括年假、事假、病假和其他类型假期", null=True, blank=True, default=0) class Meta: verbose_name = "业务部门出勤情况" verbose_name_plural = "业务部门出勤情况" db_table_comment = '存储业务部门出勤情况数据,包括一级部门、年月、迟到、早退、旷工、年假、事假、病假、其他假期和合计等' def __str__(self): return f"Attendance for {self.primary_department} in {self.year_month}" @staticmethod def get_field_labels(): return { 'primary_department': '一级部门', 'year_month': '年月', 'late': '迟到', 'early_departure': '早退', 'absenteeism': '旷工', 'annual_leave': '年假', 'personal_leave': '事假', 'sick_leave': '病假', 'other_leave': '其他', 'total_days': '合计', } def get_field_label(self, field_name): field_labels = self.get_field_labels() return field_labels.get(field_name, field_name) @staticmethod def calculate_and_update_attendance(year_month): primary_departments = PrimaryDepartment.objects.all() year, month = map(int, year_month.split('-')) for department in primary_departments: primary_department = department.department_name # 聚合数据 attendance_data = EmployeeAttendanceRecord.objects.filter( primary_department=primary_department, year_month__year=year, year_month__month=month ).aggregate( total_late=Sum('late'), total_early_departure=Sum('early_leave'), total_absenteeism=Sum('absenteeism'), total_annual_leave=Sum('annual_leave'), total_personal_leave=Sum('personal_leave'), total_sick_leave=Sum('sick_leave') ) other_leave_data = OtherLeaveDetails.objects.filter( attendance_record__primary_department=primary_department, attendance_record__year_month__year=year, attendance_record__year_month__month=month ).aggregate(total_other_leave=Sum('days')) total_other_leave = other_leave_data['total_other_leave'] or 0 attendance_data = {k: v or 0 for k, v in attendance_data.items()} total_days = ( attendance_data['total_annual_leave'] + attendance_data['total_personal_leave'] + attendance_data['total_sick_leave'] + total_other_leave ) # 更新或创建模型实例 attendance, created = DepartmentAttendance.objects.update_or_create( primary_department=primary_department, year_month=year_month, defaults={ 'late': attendance_data['total_late'] or 0, 'early_departure': attendance_data['total_early_departure'] or 0, 'absenteeism': attendance_data['total_absenteeism'] or 0, 'annual_leave': attendance_data['total_annual_leave'] or 0, 'personal_leave': attendance_data['total_personal_leave'] or 0, 'sick_leave': attendance_data['total_sick_leave'] or 0, 'other_leave': total_other_leave, 'total_days': total_days, } ) # 更新或创建更新时间记录 UpdateLog.objects.update_or_create( table_name='DepartmentAttendance', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_departments_attendance(cls, year_month): cls.calculate_and_update_attendance(year_month)