Skip to main content

System Patterns

Specific Algorithms

Budget Metrics & Recalculation

MetricCalculationSource
total_contracts_valueSum of fy_allocation.amount_due for all contractsAuto
committed_amountSum of fy_allocation.amount_due for Approved/In Delivery/Closed contractsAuto
spent_amountSum of invoice_fy_allocation.amount_allocated for Paid invoicesAuto
residualapproved_amount - spent_amountAuto
remaining_estimateapproved_amount - committed_amountAuto
remaining_paymentscommitted_amount - spent_amountAuto
closing_forecastmax(approved_amount, committed_amount)Auto

Recalculation Mechanism (Timestamp-Based):

  • Trigger: Modified_Time of Contracts/Invoices > last_recalculated of Budget Version
  • Scheduled Workflow: Daily (optional), compares timestamps and recalculates outdated versions
  • Manual Action: "Recalculate Selected Versions" button for batch processing
  • Performance: Only recalculates when necessary (lazy evaluation)
  • Tech Context - Technology stack and constraints
  • Product Behaviors - Business logic and expected behaviors
  • ETL Integrity Skill - Data transformation and mapping logic
  • Reference Skills: Use zoho_architect for Deluge syntax and zoho_simulation for logic verification.

Note: Originally formula fields, converted to EUR fields populated via workflows (aggregate formulas not supported in .ds files).

FY Allocation

  1. Fetch all "Open" records from Fiscal_Years.
  2. Calculate the total duration of the contract in days.
  3. Calculate daily_rate = total_contract_value / total_days.
  4. Loop through each FY:
    • Determine intersection start: max(Start_Contract, Start_FY)
    • Determine intersection end: min(End_Contract, End_FY)
    • If Start <= End:
      • Calculate days in FY.
      • amount_due = days_in_fy * daily_rate.
      • Insert row into fy_allocation subform.
  5. After loop, calculate total_allocated = sum of amount_due in subform.
  6. If total_allocated differs from total_contract_value by more than a rounding tolerance (e.g., 0.01):
    • Signal an error: "Contract period extends beyond defined fiscal years; only overlapping portion allocated."
    • The contract can still be saved, but the user must acknowledge the warning.

Behavioral Patterns

Budget Version Lifecycle

Status Flow: DraftApprovedArchived

  1. Draft: Fully editable.
  2. Approved (User Locked):
    • Triggered by "Approve & Roll".
    • Frozen Fields: committed_amount (snapshot of contracts at that moment).
    • Live Fields: spent_amount, residual (system continues to update these).
    • User Edits: Blocked.
  3. Archived: Same as Approved, but for old quarters.
    • Trigger: Automatically when the successive version becomes "Approved".

Strict Date Enforcement (Snapping)

  • Rule: Budget Versions MUST start on 1st of Oct, Jan, Apr, Jul.
  • Why: To ensure pivot tables align columns perfectly across all Streams.
  • Behavior: If a user enters "Nov 15", system auto-snaps to "Jan 1" (Next Quarter).

Field-Level Locking (Partial Freeze)

Unlike standard records, Budget Versions have a Dual State:

  • User Perspective: Read-Only when Approved.
  • System Perspective: Partially Write-Enabled.
    • committed_amount NEVER changes after approval (it's the "promise").
    • spent_amount DOES change (it's the "reality").

3. Verification & Safety

Since the environment does not support native transactions, we use the following safety protocols:

  • Simulation First: Use the zoho_simulation skill to verify complex logic locally using the Python logic_engine.py.
  • Explicit Staging: Follow the cleanup-session protocol for all commits.
  • Syntactic Safety: Consult the zoho_architect skill for Deluge-specific guardrails (comments, subforms).

ETL Integrity Principles:

  1. Orphan Check: No Invoice may exist without a matching Contract imported_id.
  2. Referential Completeness: Every stream_name in Buckets must resolve to a valid Stream ID.
  3. Financial Consistency: Sum(Source_Amounts) must equal Sum(Generated_CSV_Rows).
  4. Schema Compliance: Output CSVs must match Zoho Link Names exactly (snake_case).