From 999872a060c1d6da69a0b863e23dfb0700b9ebbf Mon Sep 17 00:00:00 2001 From: caoxiaozhu Date: Wed, 13 May 2026 06:54:27 +0000 Subject: [PATCH] refactor(backend): update financial record model, schema and expense claims - models/financial_record.py: update financial record model - schemas/reimbursement.py: update reimbursement schema - services/expense_claims.py: update expense claims service --- server/src/app/models/financial_record.py | 23 +++++++++++++++++++++++ server/src/app/schemas/reimbursement.py | 4 ++++ server/src/app/services/expense_claims.py | 12 ++++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/server/src/app/models/financial_record.py b/server/src/app/models/financial_record.py index 3d492a3..5607b26 100644 --- a/server/src/app/models/financial_record.py +++ b/server/src/app/models/financial_record.py @@ -44,6 +44,7 @@ class ExpenseClaim(Base): DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) + employee = relationship("Employee", foreign_keys=[employee_id]) items = relationship( "ExpenseClaimItem", back_populates="claim", @@ -51,6 +52,28 @@ class ExpenseClaim(Base): order_by="asc(ExpenseClaimItem.item_date)", ) + @property + def employee_position(self) -> str | None: + return str(self.employee.position).strip() if self.employee is not None and self.employee.position else None + + @property + def employee_grade(self) -> str | None: + return str(self.employee.grade).strip() if self.employee is not None and self.employee.grade else None + + @property + def manager_name(self) -> str | None: + if self.employee is None: + return None + if self.employee.manager is not None and self.employee.manager.name: + return str(self.employee.manager.name).strip() or None + return None + + @property + def role_labels(self) -> list[str]: + if self.employee is None or not self.employee.roles: + return [] + return [str(role.name).strip() for role in sorted(self.employee.roles, key=lambda item: item.name) if role.name] + class ExpenseClaimItem(Base): __tablename__ = "expense_claim_items" diff --git a/server/src/app/schemas/reimbursement.py b/server/src/app/schemas/reimbursement.py index 6174b0e..e6306e9 100644 --- a/server/src/app/schemas/reimbursement.py +++ b/server/src/app/schemas/reimbursement.py @@ -91,6 +91,10 @@ class ExpenseClaimRead(BaseModel): employee_name: str department_id: str | None department_name: str + employee_position: str | None = None + employee_grade: str | None = None + manager_name: str | None = None + role_labels: list[str] = Field(default_factory=list) project_code: str | None expense_type: str reason: str diff --git a/server/src/app/services/expense_claims.py b/server/src/app/services/expense_claims.py index cf83e44..dfed538 100644 --- a/server/src/app/services/expense_claims.py +++ b/server/src/app/services/expense_claims.py @@ -98,7 +98,11 @@ class ExpenseClaimService: def list_claims(self, current_user: CurrentUserContext) -> list[ExpenseClaim]: stmt = ( select(ExpenseClaim) - .options(selectinload(ExpenseClaim.items)) + .options( + selectinload(ExpenseClaim.items), + selectinload(ExpenseClaim.employee).selectinload(Employee.manager), + selectinload(ExpenseClaim.employee).selectinload(Employee.roles), + ) .order_by(ExpenseClaim.created_at.desc(), ExpenseClaim.occurred_at.desc()) ) stmt = self._apply_claim_scope(stmt, current_user) @@ -107,7 +111,11 @@ class ExpenseClaimService: def get_claim(self, claim_id: str, current_user: CurrentUserContext) -> ExpenseClaim | None: stmt = ( select(ExpenseClaim) - .options(selectinload(ExpenseClaim.items)) + .options( + selectinload(ExpenseClaim.items), + selectinload(ExpenseClaim.employee).selectinload(Employee.manager), + selectinload(ExpenseClaim.employee).selectinload(Employee.roles), + ) .where(ExpenseClaim.id == claim_id) ) stmt = self._apply_claim_scope(stmt, current_user)