PSA/shared/billingClients/recurrenceStorageModel.ts
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

74 lines
2.8 KiB
TypeScript

import type { CadenceOwner } from '@alga-psa/types';
import { DEFAULT_RECURRING_AUTHORING_BILLING_TIMING } from './recurringAuthoringPolicy';
import { resolveCadenceOwner } from './recurringTiming';
export type RecurringBillingTiming = 'arrears' | 'advance';
type NormalizableRecurringStorage = {
billing_timing?: RecurringBillingTiming | null;
cadence_owner?: CadenceOwner | null;
};
// One storage contract for recurring authoring/read paths:
// - live lines store cadence/timing directly on contract_lines
// - template lines store cadence/timing directly on contract_template_lines
// - presets store cadence/timing directly on contract_line_presets
// - fixed-only partial-period compatibility settings stay on the fixed-config tables for
// template and preset surfaces until those legacy config tables are retired
export const AUTHORITATIVE_RECURRENCE_STORAGE_MODEL = {
liveContractLines: {
table: 'contract_lines',
fields: ['billing_frequency', 'billing_timing', 'cadence_owner', 'enable_proration', 'billing_cycle_alignment'],
},
templateLines: {
table: 'contract_template_lines',
fields: ['billing_frequency', 'billing_timing', 'cadence_owner'],
fixedConfigTable: 'contract_template_line_fixed_config',
fixedConfigFields: ['enable_proration', 'billing_cycle_alignment'],
},
presetDefaults: {
table: 'contract_line_presets',
fields: ['billing_frequency', 'billing_timing', 'cadence_owner'],
fixedConfigTable: 'contract_line_preset_fixed_config',
fixedConfigFields: ['enable_proration', 'billing_cycle_alignment'],
},
sharedInterfaces: {
authoritativeShapes: ['IContractLine', 'IContractTemplateLine', 'IContractLinePreset'],
compatibilityShapes: [
'IClientContractLine',
'IContractLineMapping',
'IContractLineFixedConfig',
'IContractLinePresetFixedConfig',
],
},
} as const;
export function normalizeLiveRecurringStorage<T extends NormalizableRecurringStorage>(
row: T,
): T & { billing_timing: RecurringBillingTiming; cadence_owner: CadenceOwner } {
return {
...row,
billing_timing: row.billing_timing ?? DEFAULT_RECURRING_AUTHORING_BILLING_TIMING,
cadence_owner: resolveCadenceOwner(row.cadence_owner),
};
}
export function normalizeTemplateRecurringStorage<T extends NormalizableRecurringStorage>(
row: T,
): T & { billing_timing: RecurringBillingTiming; cadence_owner: CadenceOwner } {
return {
...row,
billing_timing:
row.billing_timing
?? DEFAULT_RECURRING_AUTHORING_BILLING_TIMING,
cadence_owner: resolveCadenceOwner(row.cadence_owner),
};
}
export function normalizePresetRecurringStorage<T extends NormalizableRecurringStorage>(
row: T,
): T & { billing_timing: RecurringBillingTiming; cadence_owner: CadenceOwner } {
return normalizeLiveRecurringStorage(row);
}