Skip to content

BillSaveService

Owns the create/update/approve/adjust/delete lifecycle for legal bills, validating each request via IValidationService and IBillServiceHelper date rules, resolving the correct approver through ILegalService.DetermineAssignedAttorney and ILegalQueryProvider.GetAttorneyProfile, and persisting changes inside IUnitOfWork transactions with optimistic-concurrency checks on UpdateNumber.

Purpose

  • Creates and updates legal bills (SaveBill), reconciling submitted bill-service lines against the database and recording status-history entries on status changes.
  • Submits a bill for approval (SubmitBill), resolving the assigned attorney/approver or falling back to in-progress status when none can be determined.
  • Approves a bill (ApproveBill) and auto-approves when the resolved approver's payment authority covers the billed amount, or escalates to the approver's manager otherwise (UpdateBillStatusCode).
  • Approves a bill with changes (ApproveWithChanges) and returns/disapproves a bill for rework (DisapproveBill).
  • Creates an adjusted copy of a paid bill for correction (AdjustBill), carrying forward only changed service lines and building an audit-trail comment describing each change.
  • Deletes a bill (DeleteBill), un-amending any parent-bill service lines that referenced it.
  • Validates a bill and its service lines against date-range and adjustment-reason business rules (ValidateBill/ValidateBillServices) before allowing a save.

Context

  • Namespace: SAIF.Services.Legal.Bills
  • Assembly/package: SAIF.Services (packaged inside the SAIF.SAIFCode.Core NuGet package).

Public members

Member Signature Purpose
BillSaveService (constructor) public BillSaveService(IUnitOfWork unitOfWork, IUserProfileService userProfileService, IValidationService validationService, ILegalQueryProvider legalQueryProvider, IBillServiceHelper billServiceHelper, ILegalService legalService) Wires the unit of work, user-profile, validation, legal-query, bill-service-helper, and legal-service collaborators, and captures the current user ID (as a static field shared across instances).
AdjustBill public long AdjustBill(LegalBill bill, IMessageContainer messageContainer, string newStatus) Builds an adjusted copy of the bill (new bill ID, ParentBillId set to the original, only changed service lines retained) and saves it as a new bill; adds a "no changes" error and returns 0 if no service lines changed.
ApproveBill public long ApproveBill(LegalBill bill, IMessageContainer messageContainer) Sets approver/approved-date (unless already ApprovedWithChange), determines the resulting status via authority-limit comparison, and saves the bill.
ApproveWithChanges public long ApproveWithChanges(LegalBill bill, IMessageContainer messageContainer) Sets approver/approved-date, forces status to ApprovedWithChange, appends an "[APPROVED WITH CHANGES]" comment marker, and saves the bill.
DeleteBill public bool DeleteBill(long billId, IMessageContainer messageContainer) Deletes the bill transactionally and, if it was an adjustment of a parent bill, clears the IsAmended flag on the parent's corresponding service lines; returns false if the bill does not exist.
DisapproveBill public long DisapproveBill(LegalBill bill, IMessageContainer messageContainer) Clears approver/approved-date, sets status to InProgress, appends a "[Returned by approver]" comment marker, and saves the bill.
SaveBill public long SaveBill(LegalBill bill, IMessageContainer messageContainer) Defaults a null bill status to InProgress and saves the bill (insert or update based on bill.Id).
SubmitBill public long SubmitBill(LegalBill bill, IMessageContainer messageContainer) Resolves an approver via SetApproverId; if none can be resolved, falls back to a plain SaveBill, otherwise sets status to PendingApproval and saves.

Behavioral notes

  • SaveLegalBill (the shared private persistence path for all public mutation methods) skips business-rule validation for bills already in PaymentReturned/Paid status, but always enforces optimistic concurrency by comparing bill.UpdateNumber against the current database value and rolling back with an error if they differ.
  • New bills get a fresh BillStatusHistories/BillServices collection, a create-annotation comment, today's issue date, and a status-history entry; updates append comments via append-annotation formatting and add a new status-history entry only when the status code actually changes.
  • PrepareAdjustedBillForSave computes a human-readable comment describing each service-line change (partial return, additional payment, service code change, from/thru date changes) and reverts the new bill to Approved status when the amount was only partially returned or the service code changed without an amount change.
  • UpdateBillStatusCode auto-approves when either the approver's initiate or approve authority limit covers the billed amount; otherwise it escalates the request to the attorney's manager and appends a note explaining the escalation.
  • ValidateBill/ValidateBillServices combine FluentValidation results with IBillServiceHelper date-range checks and adjustment-reason business rules (e.g., a zero-paid, zero-total bill's adjustment reason must be one of duplicate/unknown/free-form).
  • SetApproverId resolves the assigned attorney via ILegalService.DetermineAssignedAttorney, falling back to the bill's requesting employee, then looks up that attorney's profile; if the attorney profile has an expiration date, the bill is routed to the attorney's manager instead of the attorney.

Constraints and usage notes

  • Only unitOfWork, userProfileService, validationService, legalQueryProvider, billServiceHelper, and legalService are null-checked in the constructor via Enforce.ArgumentNotNull; the constructor also assigns a static string _currentUser field, so the "current user" reflects the most recently constructed instance rather than being strictly per-instance.*
  • All public mutation methods require non-null bill and messageContainer arguments, enforced via Enforce.ArgumentNotNull.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with ** could not be confirmed; treat as unknown until verified.

Sources

  • Services/SAIF.Services/Legal/Bills/BillSaveService.cs