XH_Digital_Management/application/busi_tbl/models.py

1602 lines
84 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)