from decimal import Decimal from django.db import models from django.db.models import Sum from django.utils import timezone from application.busi_tbl.models import DepartmentExpense, UpdateLog from application.fac_mgnt.models import GroupAnnualBudget, ReimbursementDetail from application.org_mgnt.models import PrimaryDepartment class DepartmentExpenseData(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 = DepartmentExpenseData.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='DepartmentExpenseData', defaults={'last_update': timezone.now().date()} ) @classmethod def update_all_departments_for_month(cls, year_month): cls.calculate_and_update_for_month(year_month)