offinance-shared-core 0.1.0-alpha.2 → 0.1.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,8 @@
1
1
  import type { FinanceAccount } from './contracts/AccountContract.js';
2
2
  import type { FinanceJournalEntry, JournalDraftInput } from './contracts/JournalContract.js';
3
+ import type { FinanceOpenItemAgingQuery, FinanceOpenItemAgingSummary, FinanceOpenItemPosition, FinanceOpenItemScope } from './contracts/OpenItemContract.js';
4
+ import type { FinanceOpenItemReconciliationInput, FinanceOpenItemReconciliationSummary } from './contracts/ReconciliationContract.js';
5
+ import type { FinanceCashBankMovementEntry, FinanceCashBankMovementScope, FinanceCashBankMovementSummary } from './contracts/CashMovementContract.js';
3
6
  import type { FiscalPeriod, TrialBalanceRow, FinanceLedgerScope } from './contracts/FiscalContract.js';
4
7
  import type { RapbPlan, CreateRapbInput, RapbVariance } from './contracts/BudgetContract.js';
5
8
  interface LedgerAccumulator {
@@ -27,6 +30,11 @@ export declare class OffinanceCore {
27
30
  getTrialBalance(): TrialBalanceRow[];
28
31
  getTrialBalanceByScope(scope?: FinanceLedgerScope): TrialBalanceRow[];
29
32
  listJournals(scope?: FinanceLedgerScope): FinanceJournalEntry[];
33
+ listOpenItems(scope?: FinanceOpenItemScope): FinanceOpenItemPosition[];
34
+ getOpenItemAging(query: FinanceOpenItemAgingQuery): FinanceOpenItemAgingSummary;
35
+ reconcileOpenItems(input: FinanceOpenItemReconciliationInput): FinanceOpenItemReconciliationSummary;
36
+ listCashBankMovements(scope: FinanceCashBankMovementScope): FinanceCashBankMovementEntry[];
37
+ summarizeCashBankMovements(scope: FinanceCashBankMovementScope): FinanceCashBankMovementSummary;
30
38
  private assertJournalLinesKnownAccounts;
31
39
  private assertJournalPeriodOpen;
32
40
  private findPeriodByDate;
@@ -0,0 +1,33 @@
1
+ import type { ResponseEnvelope } from 'ofcore';
2
+ import type { FinanceLedgerScope } from './FiscalContract.js';
3
+ export type FinanceCashBankMovementDirection = 'in' | 'out' | 'transfer_in' | 'transfer_out';
4
+ export interface FinanceCashBankMovementScope extends FinanceLedgerScope {
5
+ trackedAccountIds: string[];
6
+ }
7
+ export interface FinanceCashBankMovementEntry {
8
+ journalId: string;
9
+ tenantId?: string;
10
+ branchId?: string;
11
+ financeDomainId?: string;
12
+ ledgerProfileId?: string;
13
+ occurredAt: string;
14
+ reference?: string;
15
+ evidenceRef?: string;
16
+ accountId: string;
17
+ direction: FinanceCashBankMovementDirection;
18
+ amount: number;
19
+ counterpartAccountIds: string[];
20
+ trackedAccountIdsInJournal: string[];
21
+ }
22
+ export interface FinanceCashBankMovementSummary {
23
+ totalInflow: number;
24
+ totalOutflow: number;
25
+ totalTransferIn: number;
26
+ totalTransferOut: number;
27
+ netExternalMovement: number;
28
+ entries: FinanceCashBankMovementEntry[];
29
+ }
30
+ export interface FinanceCashBankMovementServiceContractV2 {
31
+ listCashBankMovements(scope: FinanceCashBankMovementScope): Promise<ResponseEnvelope<FinanceCashBankMovementEntry[]>>;
32
+ summarizeCashBankMovements(scope: FinanceCashBankMovementScope): Promise<ResponseEnvelope<FinanceCashBankMovementSummary>>;
33
+ }
@@ -0,0 +1,44 @@
1
+ import type { ScopeRef } from 'ofcore';
2
+ export type FinanceComplianceExportDatasetFormat = 'json' | 'csv';
3
+ export type FinanceComplianceExportDatasetSemantic = 'trial_balance' | 'income_statement' | 'balance_sheet' | 'open_items' | 'aging_summary' | 'reconciliation' | 'cash_movements' | 'tax_lines' | 'custom';
4
+ export interface FinanceComplianceExportPeriod {
5
+ from: string | null;
6
+ to: string | null;
7
+ label: string | null;
8
+ }
9
+ export interface FinanceComplianceExportDatasetInput {
10
+ key: string;
11
+ fileName: string;
12
+ format: FinanceComplianceExportDatasetFormat;
13
+ semantic?: FinanceComplianceExportDatasetSemantic;
14
+ contentType?: string;
15
+ payload: unknown;
16
+ }
17
+ export interface FinanceComplianceExportDatasetDescriptor {
18
+ key: string;
19
+ fileName: string;
20
+ format: FinanceComplianceExportDatasetFormat;
21
+ semantic: FinanceComplianceExportDatasetSemantic;
22
+ contentType: string;
23
+ recordCount: number;
24
+ checksum: string;
25
+ }
26
+ export interface FinanceComplianceExportContract extends ScopeRef {
27
+ contractVersion: 'fcx-v1';
28
+ financeDomainId?: string;
29
+ ledgerProfileId?: string;
30
+ generatedAt: string;
31
+ period: FinanceComplianceExportPeriod;
32
+ currency: {
33
+ baseCurrencyCode: string;
34
+ };
35
+ datasets: FinanceComplianceExportDatasetDescriptor[];
36
+ summary: {
37
+ datasetCount: number;
38
+ totalRecordCount: number;
39
+ };
40
+ }
41
+ export interface FinanceComplianceExportBundle {
42
+ contract: FinanceComplianceExportContract;
43
+ files: Record<string, string>;
44
+ }
@@ -1,10 +1,16 @@
1
1
  import type { ResponseEnvelope, ScopeRef } from 'ofcore';
2
2
  import type { FinanceLedgerScope } from './FiscalContract.js';
3
+ import type { FinanceOpenItemType } from './OpenItemContract.js';
3
4
  export interface JournalLineInput {
4
5
  accountId: string;
5
6
  debit: number;
6
7
  credit: number;
7
8
  memo?: string;
9
+ openItemId?: string;
10
+ openItemType?: FinanceOpenItemType;
11
+ counterpartyRef?: string;
12
+ documentRef?: string;
13
+ dueAt?: string;
8
14
  }
9
15
  export interface JournalDraftInput extends ScopeRef {
10
16
  id: string;
@@ -0,0 +1,48 @@
1
+ import type { ResponseEnvelope, ScopeRef } from 'ofcore';
2
+ import type { FinanceLedgerScope } from './FiscalContract.js';
3
+ export type FinanceOpenItemType = 'receivable' | 'payable';
4
+ export interface FinanceOpenItemScope extends FinanceLedgerScope {
5
+ openItemType?: FinanceOpenItemType;
6
+ counterpartyRef?: string;
7
+ includeSettled?: boolean;
8
+ }
9
+ export interface FinanceOpenItemPosition extends ScopeRef {
10
+ financeDomainId?: string;
11
+ ledgerProfileId: string;
12
+ openItemId: string;
13
+ openItemType: FinanceOpenItemType;
14
+ accountId: string;
15
+ counterpartyRef?: string;
16
+ documentRef?: string;
17
+ dueAt?: string;
18
+ originatedAt: string;
19
+ lastActivityAt: string;
20
+ originalAmount: number;
21
+ settledAmount: number;
22
+ outstandingAmount: number;
23
+ status: 'open' | 'settled' | 'overpaid';
24
+ }
25
+ export interface FinanceOpenItemAgingBucket {
26
+ key: string;
27
+ label: string;
28
+ minDaysPastDue?: number;
29
+ maxDaysPastDue?: number;
30
+ }
31
+ export interface FinanceOpenItemAgingQuery extends FinanceOpenItemScope {
32
+ asOf: string;
33
+ buckets?: FinanceOpenItemAgingBucket[];
34
+ }
35
+ export interface FinanceOpenItemAgingBucketResult extends FinanceOpenItemAgingBucket {
36
+ amount: number;
37
+ itemCount: number;
38
+ }
39
+ export interface FinanceOpenItemAgingSummary {
40
+ asOf: string;
41
+ openItemType?: FinanceOpenItemType;
42
+ totalOutstanding: number;
43
+ buckets: FinanceOpenItemAgingBucketResult[];
44
+ }
45
+ export interface FinanceOpenItemServiceContractV2 {
46
+ listOpenItems(scope?: FinanceOpenItemScope): Promise<ResponseEnvelope<FinanceOpenItemPosition[]>>;
47
+ getOpenItemAging(query: FinanceOpenItemAgingQuery): Promise<ResponseEnvelope<FinanceOpenItemAgingSummary>>;
48
+ }
@@ -0,0 +1,42 @@
1
+ import type { ResponseEnvelope, ScopeRef } from 'ofcore';
2
+ import type { FinanceOpenItemScope, FinanceOpenItemType } from './OpenItemContract.js';
3
+ export type FinanceReconciliationStatus = 'matched' | 'missing' | 'under' | 'over' | 'mismatch';
4
+ export interface FinanceObservedSettlementItem {
5
+ openItemId: string;
6
+ openItemType?: FinanceOpenItemType;
7
+ observedAmount: number;
8
+ observedAt?: string;
9
+ reference?: string;
10
+ counterpartyRef?: string;
11
+ documentRef?: string;
12
+ }
13
+ export interface FinanceOpenItemReconciliationInput extends FinanceOpenItemScope {
14
+ observations: FinanceObservedSettlementItem[];
15
+ toleranceAmount?: number;
16
+ }
17
+ export interface FinanceOpenItemReconciliationRow extends ScopeRef {
18
+ financeDomainId?: string;
19
+ ledgerProfileId?: string;
20
+ openItemId: string;
21
+ openItemType?: FinanceOpenItemType;
22
+ accountId?: string;
23
+ counterpartyRef?: string;
24
+ documentRef?: string;
25
+ dueAt?: string;
26
+ expectedAmount: number;
27
+ observedAmount: number;
28
+ varianceAmount: number;
29
+ status: FinanceReconciliationStatus;
30
+ reason?: string;
31
+ observedReferences: string[];
32
+ }
33
+ export interface FinanceOpenItemReconciliationSummary {
34
+ openItemType?: FinanceOpenItemType;
35
+ totalExpectedAmount: number;
36
+ totalObservedAmount: number;
37
+ totalVarianceAmount: number;
38
+ rows: FinanceOpenItemReconciliationRow[];
39
+ }
40
+ export interface FinanceReconciliationServiceContractV2 {
41
+ reconcileOpenItems(input: FinanceOpenItemReconciliationInput): Promise<ResponseEnvelope<FinanceOpenItemReconciliationSummary>>;
42
+ }
@@ -0,0 +1,14 @@
1
+ import type { JournalLineInput } from './JournalContract.js';
2
+ export type FinanceTaxPostingDirection = 'payable' | 'receivable';
3
+ export interface FinanceTaxComponentInput {
4
+ taxCode?: string;
5
+ amount: number;
6
+ accountId: string;
7
+ direction: FinanceTaxPostingDirection;
8
+ memo?: string;
9
+ }
10
+ export interface FinanceTaxPostingInput {
11
+ components: FinanceTaxComponentInput[];
12
+ memoPrefix?: string;
13
+ }
14
+ export declare function buildFinanceTaxPostingLines(input: FinanceTaxPostingInput): JournalLineInput[];
package/dist/index.d.ts CHANGED
@@ -5,9 +5,14 @@ export * from './services/OffinanceEnvelopeService.js';
5
5
  export * from './services/responseEnvelope.js';
6
6
  export * from './contracts/AccountContract.js';
7
7
  export * from './contracts/JournalContract.js';
8
+ export * from './contracts/OpenItemContract.js';
9
+ export * from './contracts/ReconciliationContract.js';
10
+ export * from './contracts/ComplianceExportContract.js';
11
+ export * from './contracts/CashMovementContract.js';
8
12
  export * from './contracts/FiscalContract.js';
9
13
  export * from './contracts/BudgetContract.js';
10
14
  export * from './contracts/AdapterContract.js';
15
+ export * from './contracts/TaxContract.js';
11
16
  export * from './adapters/builders.js';
12
17
  export * from './adapters/accountMapping.js';
13
18
  export * from './adapters/scopedBuilders.js';
@@ -16,6 +21,10 @@ export * from './reporting/financialStatements.js';
16
21
  export * from './reporting/closing.js';
17
22
  export * from './reporting/exporters.js';
18
23
  export * from './reporting/budget.js';
24
+ export * from './reporting/openItems.js';
25
+ export * from './reporting/reconciliation.js';
26
+ export * from './reporting/complianceExport.js';
27
+ export * from './reporting/cashMovements.js';
19
28
  export * from './events/catalog.js';
20
29
  export * from './events/replay.js';
21
30
  export * from './domain/chartOfAccounts.js';
package/dist/index.esm.js CHANGED
@@ -1,2 +1,3 @@
1
- function D(r){if(!Array.isArray(r)||r.length===0)return{ok:!1,totalDebit:0,totalCredit:0,reason:"JOURNAL_LINES_EMPTY"};let e=0,t=0;for(let n of r){if(!n||!n.accountId)return{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_ACCOUNT_REQUIRED"};if(n.debit<0||n.credit<0)return{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_NEGATIVE_AMOUNT"};e+=n.debit,t+=n.credit}return Math.abs(e-t)>1e-6?{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_NOT_BALANCED"}:{ok:!0,totalDebit:e,totalCredit:t}}var R=class{constructor(e){this.state={accounts:e?.accounts??new Map,periods:e?.periods??new Map,journals:e?.journals??new Map,balances:e?.balances??new Map,rapbPlans:e?.rapbPlans??new Map}}createAccount(e){if(!e.id||!e.code||!e.name)throw new Error("FINANCE_ACCOUNT_REQUIRED_FIELDS");if(this.state.accounts.has(e.id))throw new Error("FINANCE_ACCOUNT_ALREADY_EXISTS");if(Array.from(this.state.accounts.values()).some(n=>n.code===e.code))throw new Error("FINANCE_ACCOUNT_CODE_DUPLICATE");return this.state.accounts.set(e.id,{...e}),{...e}}listAccounts(){return Array.from(this.state.accounts.values()).map(e=>({...e})).sort((e,t)=>e.code.localeCompare(t.code))}openFiscalPeriod(e){if(!e.id||!e.tenantId||!e.code||!e.startDate||!e.endDate)throw new Error("FISCAL_PERIOD_REQUIRED_FIELDS");if(this.state.periods.has(e.id))throw new Error("FISCAL_PERIOD_ALREADY_EXISTS");if(Date.parse(e.startDate)>Date.parse(e.endDate))throw new Error("FISCAL_PERIOD_INVALID_RANGE");let t={...e,status:"open"};return this.state.periods.set(t.id,t),{...t}}closeFiscalPeriod(e){let t=this.state.periods.get(e);if(!t)throw new Error("FISCAL_PERIOD_NOT_FOUND");let n={...t,status:"closed"};return this.state.periods.set(e,n),{...n}}listFiscalPeriods(){return Array.from(this.state.periods.values()).map(e=>({...e})).sort((e,t)=>e.startDate.localeCompare(t.startDate))}createJournalDraft(e){if(!e.id||!e.tenantId||!e.occurredAt)throw new Error("JOURNAL_REQUIRED_FIELDS");if(this.state.journals.has(e.id))throw new Error("JOURNAL_ALREADY_EXISTS");this.assertJournalLinesKnownAccounts(e.lines),this.assertJournalPeriodOpen(e.occurredAt);let t=D(e.lines);if(!t.ok)throw new Error(t.reason??"JOURNAL_INVALID");let n={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,lines:e.lines.map(a=>({...a})),status:"draft"};return this.state.journals.set(n.id,n),{...n,lines:n.lines.map(a=>({...a}))}}postJournal(e,t=new Date().toISOString()){let n=this.state.journals.get(e);if(!n)throw new Error("JOURNAL_NOT_FOUND");if(n.status==="posted"||n.status==="reversed")return{...n,lines:n.lines.map(o=>({...o}))};this.applyLinesToBalance(n.lines);let a={...n,status:"posted",postedAt:t};return this.state.journals.set(e,a),{...a,lines:a.lines.map(o=>({...o}))}}reverseJournal(e,t){let n=this.state.journals.get(e);if(!n)throw new Error("JOURNAL_NOT_FOUND");if(n.status!=="posted")throw new Error("JOURNAL_NOT_POSTED");if(this.state.journals.has(t))throw new Error("JOURNAL_ALREADY_EXISTS");let a=n.lines.map(i=>({accountId:i.accountId,debit:i.credit,credit:i.debit,memo:i.memo})),o=this.createJournalDraft({id:t,tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,occurredAt:n.occurredAt,reference:`reversal:${n.id}`,lines:a});return this.postJournal(o.id)}getTrialBalance(){return this.getTrialBalanceByScope()}getTrialBalanceByScope(e){let t=this.computeScopedBalances(e);return this.listAccounts().map(a=>{let o=t.get(a.id)??{debit:0,credit:0};return{accountId:a.id,accountCode:a.code,accountName:a.name,accountType:a.type,debit:o.debit,credit:o.credit,net:o.debit-o.credit}})}listJournals(e){return Array.from(this.state.journals.values()).filter(t=>this.matchesScope(t,e)).map(t=>({...t,lines:t.lines.map(n=>({...n}))})).sort((t,n)=>t.occurredAt.localeCompare(n.occurredAt))}assertJournalLinesKnownAccounts(e){for(let t of e)if(!this.state.accounts.has(t.accountId))throw new Error("JOURNAL_ACCOUNT_NOT_FOUND")}assertJournalPeriodOpen(e){if(this.state.periods.size===0)return;let t=this.findPeriodByDate(e);if(!t)throw new Error("FISCAL_PERIOD_NOT_FOUND_FOR_DATE");if(t.status!=="open")throw new Error("FISCAL_PERIOD_CLOSED")}findPeriodByDate(e){let t=Date.parse(e);for(let n of this.state.periods.values()){let a=Date.parse(n.startDate),o=Date.parse(n.endDate);if(t>=a&&t<=o)return n}return null}applyLinesToBalance(e){for(let t of e){let n=this.state.balances.get(t.accountId)??{debit:0,credit:0};n.debit+=t.debit,n.credit+=t.credit,this.state.balances.set(t.accountId,n)}}computeScopedBalances(e){if(!e||!e.tenantId&&!e.branchId&&!e.financeDomainId&&!e.ledgerProfileId&&!e.occurredFrom&&!e.occurredTo)return this.state.balances;let t=new Map;for(let n of this.state.journals.values())if(n.status==="posted"&&this.matchesScope(n,e))for(let a of n.lines){let o=t.get(a.accountId)??{debit:0,credit:0};o.debit+=a.debit,o.credit+=a.credit,t.set(a.accountId,o)}return t}matchesScope(e,t){return t?!(t.tenantId&&e.tenantId!==t.tenantId||t.branchId&&e.branchId!==t.branchId||t.financeDomainId&&e.financeDomainId!==t.financeDomainId||t.ledgerProfileId&&e.ledgerProfileId!==t.ledgerProfileId||t.occurredFrom&&e.occurredAt<t.occurredFrom||t.occurredTo&&e.occurredAt>t.occurredTo):!0}createRapb(e){if(!e.id||!e.tenantId||!e.periodCode||!e.title)throw new Error("RAPB_REQUIRED_FIELDS");if(!e.lines||e.lines.length===0)throw new Error("RAPB_LINES_REQUIRED");if(this.state.rapbPlans.has(e.id))throw new Error("RAPB_ALREADY_EXISTS");if(e.lines.some(a=>a.budgetedDebit<0||a.budgetedCredit<0))throw new Error("RAPB_NEGATIVE_AMOUNT");let t=e.lines.map(a=>{let o=this.state.accounts.get(a.accountId);if(!o)throw new Error(`RAPB_ACCOUNT_NOT_FOUND:${a.accountId}`);let i=a.budgetedDebit-a.budgetedCredit;return{accountId:a.accountId,accountCode:o.code,accountName:o.name,accountType:o.type,budgetedDebit:a.budgetedDebit,budgetedCredit:a.budgetedCredit,budgetedNet:i}}),n={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,periodCode:e.periodCode,title:e.title,status:"draft",lines:t,notes:e.notes,createdAt:new Date().toISOString()};return this.state.rapbPlans.set(n.id,n),n}getRapb(e){return this.state.rapbPlans.get(e)??null}listRapb(e){let t=Array.from(this.state.rapbPlans.values());return e&&(e.tenantId&&(t=t.filter(n=>n.tenantId===e.tenantId)),e.periodCode&&(t=t.filter(n=>n.periodCode===e.periodCode)),e.branchId&&(t=t.filter(n=>n.branchId===e.branchId)),e.financeDomainId&&(t=t.filter(n=>n.financeDomainId===e.financeDomainId)),e.ledgerProfileId&&(t=t.filter(n=>n.ledgerProfileId===e.ledgerProfileId))),t}approveRapb(e,t){let n=this.state.rapbPlans.get(e);if(!n)throw new Error("RAPB_NOT_FOUND");let a=typeof t=="string"?t:t.approvedBy;if(n.status==="approved")throw new Error("RAPB_ALREADY_APPROVED");let o={...n,status:"approved",approvedAt:new Date().toISOString(),approvedBy:a};return this.state.rapbPlans.set(e,o),o}evaluateVariance(e){let t=this.state.rapbPlans.get(e);if(!t)throw new Error("RAPB_NOT_FOUND");let n=this.getTrialBalance(),a=new Map(n.map(d=>[d.accountId,d])),o=0,i=0,s=0,u=0,I=t.lines.map(d=>{let P=a.get(d.accountId),m=P?.debit??0,f=P?.credit??0,v=m-f;return d.accountType==="revenue"?(o+=d.budgetedCredit-d.budgetedDebit,i+=f-m):d.accountType==="expense"&&(s+=d.budgetedDebit-d.budgetedCredit,u+=m-f),{accountId:d.accountId,accountCode:d.accountCode,accountName:d.accountName,accountType:d.accountType,budgetedDebit:d.budgetedDebit,budgetedCredit:d.budgetedCredit,budgetedNet:d.budgetedNet,actualDebit:m,actualCredit:f,actualNet:v,varianceDebit:m-d.budgetedDebit,varianceCredit:f-d.budgetedCredit,varianceNet:v-d.budgetedNet}}),A=o-s,S=i-u;return{rapbId:e,periodCode:t.periodCode,evaluatedAt:new Date().toISOString(),lines:I,totalBudgetedRevenue:o,totalActualRevenue:i,totalBudgetedExpense:s,totalActualExpense:u,budgetedNetIncome:A,actualNetIncome:S,netVariance:S-A}}};import{CoreRuntime as ae}from"ofcore";import{InMemoryDbAdapter as oe}from"ofcore";import{asReadonlyStore as ie,createStore as ce}from"ofcore";var c={accounts:"ofinance_accounts",periods:"ofinance_periods",journals:"ofinance_journals",journalLines:"ofinance_journal_lines",rapbPlans:"ofinance_rapb_plans",rapbLines:"ofinance_rapb_lines",histories:"ofinance_histories"},ee=[{name:c.accounts,columns:[{name:"id",type:"string"},{name:"code",type:"string",isIndexed:!0},{name:"name",type:"string"},{name:"type",type:"string",isIndexed:!0},{name:"currency",type:"string"},{name:"isActive",type:"boolean",isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.periods,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"code",type:"string",isIndexed:!0},{name:"startDate",type:"string",isIndexed:!0},{name:"endDate",type:"string",isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.journals,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"occurredAt",type:"string",isIndexed:!0},{name:"reference",type:"string",isOptional:!0,isIndexed:!0},{name:"evidenceRef",type:"string",isOptional:!0,isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"postedAt",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.journalLines,columns:[{name:"id",type:"string"},{name:"journalId",type:"string",isIndexed:!0},{name:"accountId",type:"string",isIndexed:!0},{name:"debit",type:"number"},{name:"credit",type:"number"},{name:"memo",type:"string",isOptional:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.rapbPlans,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"periodCode",type:"string",isIndexed:!0},{name:"title",type:"string",isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"notes",type:"string",isOptional:!0},{name:"createdAt",type:"string",isIndexed:!0},{name:"approvedAt",type:"string",isOptional:!0,isIndexed:!0},{name:"approvedBy",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.rapbLines,columns:[{name:"id",type:"string"},{name:"rapbId",type:"string",isIndexed:!0},{name:"accountId",type:"string",isIndexed:!0},{name:"accountCode",type:"string",isIndexed:!0},{name:"accountName",type:"string"},{name:"accountType",type:"string",isIndexed:!0},{name:"budgetedDebit",type:"number"},{name:"budgetedCredit",type:"number"},{name:"budgetedNet",type:"number"},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.histories,columns:[{name:"id",type:"string"},{name:"tableName",type:"string",isIndexed:!0},{name:"recordId",type:"string",isIndexed:!0},{name:"action",type:"string",isIndexed:!0},{name:"changes",type:"json",isOptional:!0},{name:"timestamp",type:"string",isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0}]}];function _(){return ee.map(r=>({...r,columns:r.columns.map(e=>({...e}))}))}var J=[{toVersion:1,up:async r=>{let e=_();for(let t of e)try{await r.addTable(t)}catch{}}},{toVersion:2,up:async r=>{let e=_().filter(t=>t.name==="ofinance_rapb_plans"||t.name==="ofinance_rapb_lines");for(let t of e)try{await r.addTable(t)}catch{}}},{toVersion:3,up:async r=>{try{await r.addColumn("ofinance_journals",{name:"evidenceRef",type:"string",isOptional:!0,isIndexed:!0})}catch{}}}];var te={logInfo(){},logWarn(){},logError(){}};async function w(r,e=te){e.logInfo("[offinance] starting database migration process");let t=[...J].sort((o,i)=>o.toVersion-i.toVersion),n=t.length>0?t[t.length-1].toVersion:0,a=await r.getSchemaVersion();if((a==null||a<0)&&(a=0),a>=n){e.logInfo(`[offinance] database already up-to-date at v${a}`);return}for(let o of t)o.toVersion>a&&(e.logInfo(`[offinance] applying migration v${o.toVersion}`),await o.up(r),await r.setSchemaVersion(o.toVersion),a=o.toVersion);e.logInfo(`[offinance] migration completed at v${a}`)}function l(r,e){return{data:r,meta:{request_id:e??null,timestamp:new Date().toISOString()}}}function M(r,e,t={}){return{error:{code:r,message:e,details:t.details,retryable:t.retryable,correlationId:t.correlationId,timestamp:new Date().toISOString()},meta:{request_id:t.requestId??null,timestamp:new Date().toISOString()}}}function p(r,e="FINANCE_NOT_IMPLEMENTED",t="Unhandled offinance error."){return r instanceof Error?M(e,r.message||t):M(e,t)}var T=class{constructor(e){this.legacy=e;this.accountService={createAccount:async t=>{try{return l(await this.legacy.accountService.createAccount(t))}catch(n){return p(n)}},listAccounts:async()=>{try{return l(await this.legacy.accountService.listAccounts())}catch(t){return p(t)}}},this.journalService={createJournalDraft:async t=>{try{return l(await this.legacy.journalService.createJournalDraft(t))}catch(n){return p(n)}},postJournal:async(t,n)=>{try{return l(await this.legacy.journalService.postJournal(t,n))}catch(a){return p(a)}},reverseJournal:async(t,n)=>{try{return l(await this.legacy.journalService.reverseJournal(t,n))}catch(a){return p(a)}},listJournals:async t=>{try{return l(await this.legacy.journalService.listJournals(t))}catch(n){return p(n)}}},this.fiscalService={openFiscalPeriod:async t=>{try{return l(await this.legacy.fiscalService.openFiscalPeriod(t))}catch(n){return p(n)}},closeFiscalPeriod:async t=>{try{return l(await this.legacy.fiscalService.closeFiscalPeriod(t))}catch(n){return p(n)}},listFiscalPeriods:async()=>{try{return l(await this.legacy.fiscalService.listFiscalPeriods())}catch(t){return p(t)}},getTrialBalance:async()=>{try{return l(await this.legacy.fiscalService.getTrialBalance())}catch(t){return p(t)}},getTrialBalanceByScope:async t=>{try{return l(await this.legacy.fiscalService.getTrialBalanceByScope(t))}catch(n){return p(n)}}},this.rapbService={createRapb:async t=>{try{return l(await this.legacy.rapbService.createRapb(t))}catch(n){return p(n)}},getRapb:async t=>{try{return l(await this.legacy.rapbService.getRapb(t))}catch(n){return p(n)}},listRapb:async t=>{try{return l(await this.legacy.rapbService.listRapb(t))}catch(n){return p(n)}},approveRapb:async(t,n)=>{try{return l(await this.legacy.rapbService.approveRapb(t,n))}catch(a){return p(a)}},evaluateVariance:async t=>{try{return l(await this.legacy.rapbService.evaluateVariance(t))}catch(n){return p(n)}}}}};function B(r){return new T({accountService:r,journalService:r,fiscalService:r,rapbService:r})}function b(r){return JSON.parse(JSON.stringify(r))}function g(){return new Date().toISOString()}function ne(r,e){return`${r}:${e}:${Date.now()}:${Math.random().toString(36).slice(2,8)}`}function re(r,e){return!r||r.deleted?!1:e?!(e.tenantId&&r.tenantId!==e.tenantId||e.branchId&&r.branchId!==e.branchId||e.financeDomainId&&r.financeDomainId!==e.financeDomainId||e.ledgerProfileId&&r.ledgerProfileId!==e.ledgerProfileId||e.occurredFrom&&r.occurredAt&&r.occurredAt<e.occurredFrom||e.occurredTo&&r.occurredAt&&r.occurredAt>e.occurredTo):!0}var F=class{constructor(e){this.dbAdapter=e}async createAccount(e){if(!e.id||!e.code||!e.name)throw new Error("FINANCE_ACCOUNT_REQUIRED_FIELDS");let t=await this.dbAdapter.get(c.accounts,e.id);if(t&&!t.deleted)throw new Error("FINANCE_ACCOUNT_ALREADY_EXISTS");if((await this.dbAdapter.query(c.accounts,{filters:{and:[{field:"code",value:e.code},{field:"deleted",value:!1}]}})).some(i=>i.id!==e.id))throw new Error("FINANCE_ACCOUNT_CODE_DUPLICATE");let a=g(),o={...b(e),lastModified:a,deleted:!1};return t?await this.dbAdapter.update(c.accounts,e.id,o):await this.dbAdapter.create(c.accounts,o),await this.writeHistory("accounts",e.id,"UPSERT",o),b(e)}async listAccounts(){return(await this.dbAdapter.query(c.accounts,{filters:{field:"deleted",value:!1}})).map(({lastModified:t,deleted:n,...a})=>b(a)).sort((t,n)=>t.code.localeCompare(n.code))}async createJournalDraft(e){if(!e.id||!e.tenantId||!e.occurredAt)throw new Error("JOURNAL_REQUIRED_FIELDS");if(!e.ledgerProfileId)throw new Error("JOURNAL_REQUIRED_FIELDS");let t=await this.dbAdapter.get(c.journals,e.id);if(t&&!t.deleted)throw new Error("JOURNAL_ALREADY_EXISTS");await this.assertJournalLinesKnownAccounts(e.lines),await this.assertJournalPeriodOpen(e);let n=D(e.lines);if(!n.ok)throw new Error(n.reason??"JOURNAL_INVALID");let a=g(),o={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,evidenceRef:e.evidenceRef,status:"draft",postedAt:void 0,lastModified:a,deleted:!1};await this.dbAdapter.create(c.journals,o);for(let i=0;i<e.lines.length;i+=1){let s=e.lines[i],u={id:`${e.id}:line:${i}`,journalId:e.id,accountId:s.accountId,debit:s.debit,credit:s.credit,memo:s.memo,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:a,deleted:!1};await this.dbAdapter.create(c.journalLines,u),await this.writeHistory("journal_lines",u.id,"UPSERT",u)}return await this.writeHistory("journals",e.id,"UPSERT",o),this.toJournalEntry(o,e.lines)}async postJournal(e,t=g()){let n=await this.requireJournal(e),a=await this.listJournalLines(e);if(n.status==="posted"||n.status==="reversed")return this.toJournalEntry(n,a);let o={...n,status:"posted",postedAt:t,lastModified:g()};return await this.dbAdapter.update(c.journals,e,o),await this.writeHistory("journals",e,"UPSERT",o),this.toJournalEntry(o,a)}async reverseJournal(e,t){let n=await this.requireJournal(e);if(n.status!=="posted")throw new Error("JOURNAL_NOT_POSTED");let a=await this.listJournalLines(e),o=await this.createJournalDraft({id:t,tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,occurredAt:n.occurredAt,reference:`reversal:${n.id}`,evidenceRef:n.evidenceRef,lines:a.map(i=>({accountId:i.accountId,debit:i.credit,credit:i.debit,memo:i.memo}))});return this.postJournal(o.id)}async listJournals(e){let n=(await this.dbAdapter.query(c.journals,{filters:{field:"deleted",value:!1}})).filter(o=>re(o,e)).sort((o,i)=>o.occurredAt.localeCompare(i.occurredAt)),a=[];for(let o of n){let i=await this.listJournalLines(o.id);a.push(this.toJournalEntry(o,i))}return a}async openFiscalPeriod(e){if(!e.id||!e.tenantId||!e.code||!e.startDate||!e.endDate)throw new Error("FISCAL_PERIOD_REQUIRED_FIELDS");if(Date.parse(e.startDate)>Date.parse(e.endDate))throw new Error("FISCAL_PERIOD_INVALID_RANGE");let t=await this.dbAdapter.get(c.periods,e.id);if(t&&!t.deleted)throw new Error("FISCAL_PERIOD_ALREADY_EXISTS");let n=g(),a={...b(e),status:"open",lastModified:n,deleted:!1};return t?await this.dbAdapter.update(c.periods,e.id,a):await this.dbAdapter.create(c.periods,a),await this.writeHistory("periods",e.id,"UPSERT",a),this.toPeriod(a)}async closeFiscalPeriod(e){let t=await this.dbAdapter.get(c.periods,e);if(!t||t.deleted)throw new Error("FISCAL_PERIOD_NOT_FOUND");let n={...t,status:"closed",lastModified:g()};return await this.dbAdapter.update(c.periods,e,n),await this.writeHistory("periods",e,"UPSERT",n),this.toPeriod(n)}async listFiscalPeriods(){return(await this.dbAdapter.query(c.periods,{filters:{field:"deleted",value:!1}})).map(t=>this.toPeriod(t)).sort((t,n)=>t.startDate.localeCompare(n.startDate))}async getTrialBalance(){return this.getTrialBalanceByScope()}async getTrialBalanceByScope(e){let t=await this.listAccounts(),a=(await this.listJournals(e)).filter(i=>i.status==="posted"),o=new Map;for(let i of a)for(let s of i.lines){let u=o.get(s.accountId)??{debit:0,credit:0};u.debit+=Number(s.debit||0),u.credit+=Number(s.credit||0),o.set(s.accountId,u)}return t.map(i=>{let s=o.get(i.id)??{debit:0,credit:0};return{accountId:i.id,accountCode:i.code,accountName:i.name,accountType:i.type,debit:s.debit,credit:s.credit,net:s.debit-s.credit}})}async createRapb(e){if(!e.id||!e.tenantId||!e.periodCode||!e.title)throw new Error("RAPB_REQUIRED_FIELDS");if(!e.lines||e.lines.length===0)throw new Error("RAPB_LINES_REQUIRED");if(e.lines.some(i=>i.budgetedDebit<0||i.budgetedCredit<0))throw new Error("RAPB_NEGATIVE_AMOUNT");let t=await this.dbAdapter.get(c.rapbPlans,e.id);if(t&&!t.deleted)throw new Error("RAPB_ALREADY_EXISTS");let n=g(),a=[];for(let i=0;i<e.lines.length;i+=1){let s=e.lines[i],u=await this.dbAdapter.get(c.accounts,s.accountId);if(!u||u.deleted)throw new Error(`RAPB_ACCOUNT_NOT_FOUND:${s.accountId}`);a.push({id:`${e.id}:line:${i}`,rapbId:e.id,accountId:s.accountId,accountCode:u.code,accountName:u.name,accountType:u.type,budgetedDebit:s.budgetedDebit,budgetedCredit:s.budgetedCredit,budgetedNet:s.budgetedDebit-s.budgetedCredit,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:n,deleted:!1})}let o={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,periodCode:e.periodCode,title:e.title,status:"draft",notes:e.notes,createdAt:n,approvedAt:void 0,approvedBy:void 0,lastModified:n,deleted:!1};await this.dbAdapter.create(c.rapbPlans,o),await this.writeHistory("rapb_plans",e.id,"UPSERT",o);for(let i of a)await this.dbAdapter.create(c.rapbLines,i),await this.writeHistory("rapb_lines",i.id,"UPSERT",i);return this.toRapbPlan(o,a)}async getRapb(e){let t=await this.dbAdapter.get(c.rapbPlans,e);if(!t||t.deleted)return null;let n=await this.listRapbLines(e);return this.toRapbPlan(t,n)}async listRapb(e){let n=await this.dbAdapter.query(c.rapbPlans,{filters:{field:"deleted",value:!1}});e&&(e.tenantId&&(n=n.filter(o=>o.tenantId===e.tenantId)),e.periodCode&&(n=n.filter(o=>o.periodCode===e.periodCode)),e.branchId&&(n=n.filter(o=>o.branchId===e.branchId)),e.financeDomainId&&(n=n.filter(o=>o.financeDomainId===e.financeDomainId)),e.ledgerProfileId&&(n=n.filter(o=>o.ledgerProfileId===e.ledgerProfileId)));let a=[];for(let o of n.sort((i,s)=>i.createdAt.localeCompare(s.createdAt))){let i=await this.listRapbLines(o.id);a.push(this.toRapbPlan(o,i))}return a}async approveRapb(e,t){let n=await this.dbAdapter.get(c.rapbPlans,e);if(!n||n.deleted)throw new Error("RAPB_NOT_FOUND");if(n.status==="approved")throw new Error("RAPB_ALREADY_APPROVED");let a=typeof t=="string"?t:t.approvedBy,o={...n,status:"approved",approvedAt:g(),approvedBy:a,lastModified:g()};await this.dbAdapter.update(c.rapbPlans,e,o),await this.writeHistory("rapb_plans",e,"UPSERT",o);let i=await this.listRapbLines(e);return this.toRapbPlan(o,i)}async evaluateVariance(e){let t=await this.getRapb(e);if(!t)throw new Error("RAPB_NOT_FOUND");let n=await this.getTrialBalanceByScope({tenantId:t.tenantId,branchId:t.branchId,financeDomainId:t.financeDomainId,ledgerProfileId:t.ledgerProfileId}),a=new Map(n.map(d=>[d.accountId,d])),o=0,i=0,s=0,u=0,I=t.lines.map(d=>{let P=a.get(d.accountId),m=P?.debit??0,f=P?.credit??0,v=m-f;return d.accountType==="revenue"?(o+=d.budgetedCredit-d.budgetedDebit,i+=f-m):d.accountType==="expense"&&(s+=d.budgetedDebit-d.budgetedCredit,u+=m-f),{accountId:d.accountId,accountCode:d.accountCode,accountName:d.accountName,accountType:d.accountType,budgetedDebit:d.budgetedDebit,budgetedCredit:d.budgetedCredit,budgetedNet:d.budgetedNet,actualDebit:m,actualCredit:f,actualNet:v,varianceDebit:m-d.budgetedDebit,varianceCredit:f-d.budgetedCredit,varianceNet:v-d.budgetedNet}}),A=o-s,S=i-u;return{rapbId:e,periodCode:t.periodCode,evaluatedAt:g(),lines:I,totalBudgetedRevenue:o,totalActualRevenue:i,totalBudgetedExpense:s,totalActualExpense:u,budgetedNetIncome:A,actualNetIncome:S,netVariance:S-A}}async assertJournalLinesKnownAccounts(e){for(let t of e){let n=await this.dbAdapter.get(c.accounts,t.accountId);if(!n||n.deleted)throw new Error("JOURNAL_ACCOUNT_NOT_FOUND")}}async assertJournalPeriodOpen(e){let t=await this.dbAdapter.query(c.periods,{filters:{field:"deleted",value:!1}});if(t.length===0)return;let n=t.find(a=>!(a.tenantId!==e.tenantId||Date.parse(a.startDate)>Date.parse(e.occurredAt)||Date.parse(a.endDate)<Date.parse(e.occurredAt)||e.ledgerProfileId&&a.ledgerProfileId&&a.ledgerProfileId!==e.ledgerProfileId||e.financeDomainId&&a.financeDomainId&&a.financeDomainId!==e.financeDomainId));if(!n)throw new Error("FISCAL_PERIOD_NOT_FOUND_FOR_DATE");if(n.status!=="open")throw new Error("FISCAL_PERIOD_CLOSED")}async requireJournal(e){let t=await this.dbAdapter.get(c.journals,e);if(!t||t.deleted)throw new Error("JOURNAL_NOT_FOUND");return t}async listJournalLines(e){return(await this.dbAdapter.query(c.journalLines,{filters:{and:[{field:"journalId",value:e},{field:"deleted",value:!1}]}})).sort((n,a)=>n.id.localeCompare(a.id))}async listRapbLines(e){return(await this.dbAdapter.query(c.rapbLines,{filters:{and:[{field:"rapbId",value:e},{field:"deleted",value:!1}]}})).sort((n,a)=>n.id.localeCompare(a.id))}toJournalEntry(e,t){let{lastModified:n,deleted:a,...o}=e;return{...b(o),lines:t.map(i=>b(i))}}toPeriod(e){let{lastModified:t,deleted:n,...a}=e;return b(a)}toRapbPlan(e,t){let{lastModified:n,deleted:a,...o}=e;return{...b(o),lines:t.map(({id:i,rapbId:s,lastModified:u,deleted:I,...A})=>b(A))}}async writeHistory(e,t,n,a){let o=a,i={id:ne(e,t),tableName:e,recordId:t,action:n,changes:b(o),timestamp:g(),tenantId:typeof o.tenantId=="string"?o.tenantId:void 0,branchId:typeof o.branchId=="string"?o.branchId:void 0,financeDomainId:typeof o.financeDomainId=="string"?o.financeDomainId:void 0,ledgerProfileId:typeof o.ledgerProfileId=="string"?o.ledgerProfileId:void 0};await this.dbAdapter.create(c.histories,i)}};async function U(r){await w(r);let e=new F(r);return{financeService:B({createAccount:e.createAccount.bind(e),listAccounts:e.listAccounts.bind(e),createJournalDraft:e.createJournalDraft.bind(e),postJournal:e.postJournal.bind(e),reverseJournal:e.reverseJournal.bind(e),listJournals:e.listJournals.bind(e),openFiscalPeriod:e.openFiscalPeriod.bind(e),closeFiscalPeriod:e.closeFiscalPeriod.bind(e),listFiscalPeriods:e.listFiscalPeriods.bind(e),getTrialBalance:e.getTrialBalance.bind(e),getTrialBalanceByScope:e.getTrialBalanceByScope.bind(e),createRapb:e.createRapb.bind(e),getRapb:e.getRapb.bind(e),listRapb:e.listRapb.bind(e),approveRapb:e.approveRapb.bind(e),evaluateVariance:e.evaluateVariance.bind(e)})}}var L=class{constructor(e,t){this.runtime=e;this.runtimeStateStore=t;this.runtimeStore=ie(this.runtimeStateStore)}static builder(){return new N}get registry(){return this.runtime.registry}async start(e={}){this.runtimeStateStore.setState({phase:"starting",started:!1,lastError:null,lastTransitionAt:new Date().toISOString(),startCount:this.runtimeStateStore.getState().startCount,stopCount:this.runtimeStateStore.getState().stopCount});try{await this.runtime.start(e),this.domainServices=this.runtime.domainServices,this.runtimeStateStore.setState(t=>({...t,phase:"started",started:!0,startCount:t.startCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(t){throw this.runtimeStateStore.setState(n=>({...n,phase:"error",started:!1,lastError:t instanceof Error?t.message:String(t),lastTransitionAt:new Date().toISOString()})),t}}async stop(){this.runtimeStateStore.setState(e=>({...e,phase:"stopping",started:this.runtime.isStarted(),lastError:null,lastTransitionAt:new Date().toISOString()}));try{await this.runtime.stop(),this.runtimeStateStore.setState(e=>({...e,phase:"stopped",started:!1,stopCount:e.stopCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(e){throw this.runtimeStateStore.setState(t=>({...t,phase:"error",started:this.runtime.isStarted(),lastError:e instanceof Error?e.message:String(e),lastTransitionAt:new Date().toISOString()})),e}}isStarted(){return this.runtime.isStarted()}},N=class{constructor(){this.runtimeBuilder=ae.builder();this.runtimeHooks={};this.runtimeBuilder.withDbAdapter(()=>new oe)}withPlatformAdapter(e){return this.runtimeBuilder.withPlatformAdapter(e),this}withDbAdapter(e){return this.runtimeBuilder.withDbAdapter(e),this}withHttpAdapter(e){return this.runtimeBuilder.withHttpAdapter(e),this}withSocketAdapter(e){return this.runtimeBuilder.withSocketAdapter(e),this}withLoggerAdapter(e){return this.runtimeBuilder.withLoggerAdapter(e),this}withActivitySink(e){return this.runtimeBuilder.withActivitySink(e),this}withExtension(e,t){return this.runtimeBuilder.withExtension(e,t),this}withDomainServicesFactory(e){return this.domainServicesFactory=e,this}withRuntimeHooks(e){return this.runtimeHooks={...this.runtimeHooks,...e},this}build(){let e=ce({phase:"idle",started:!1,startCount:0,stopCount:0,lastError:null,lastTransitionAt:new Date().toISOString()}),t={runMigrations:async a=>{let o=a.registry?.dbAdapter;if(!o)throw new Error("OFINANCE_DB_ADAPTER_REQUIRED");await w(o,a.registry?.loggerAdapter),this.runtimeHooks.runMigrations&&await this.runtimeHooks.runMigrations(a)},...this.runtimeHooks,createDomainServices:async a=>{if(this.domainServicesFactory)return this.domainServicesFactory();let o=a.registry?.dbAdapter;if(!o)throw new Error("OFINANCE_DB_ADAPTER_REQUIRED");return U(o)}};this.runtimeBuilder.withHooks(t);let n=this.runtimeBuilder.build();return new L(n,e)}};function y(r,e,t){return{id:r.journalId,tenantId:r.tenantId,branchId:r.branchId,financeDomainId:r.financeDomainId,ledgerProfileId:r.ledgerProfileId,occurredAt:r.occurredAt,reference:t?`${r.reference??""}${t}`:r.reference,evidenceRef:r.evidenceRef,lines:e}}function h(r,e){if(!Number.isFinite(r)||r<=0)throw new Error(e)}function j(r,e){h(e.grossAmount,"POS_SALE_INVALID_GROSS_AMOUNT");let t=e.discountAmount??0,n=e.taxAmount??0;if(t<0||n<0)throw new Error("POS_SALE_NEGATIVE_COMPONENT");let a=e.grossAmount,o=a-t+n,i=[{accountId:e.paymentAccountId,debit:o,credit:0,memo:"POS sale payment"},{accountId:e.revenueAccountId,debit:0,credit:a,memo:"POS sale revenue"}];if(t>0){if(!e.discountAccountId)throw new Error("POS_SALE_DISCOUNT_ACCOUNT_REQUIRED");i.push({accountId:e.discountAccountId,debit:t,credit:0,memo:"POS sale discount"})}if(n>0){if(!e.taxPayableAccountId)throw new Error("POS_SALE_TAX_ACCOUNT_REQUIRED");i.push({accountId:e.taxPayableAccountId,debit:0,credit:n,memo:"POS sale tax payable"})}return y(r,i)}function V(r,e){return h(e.principalAmount,"COOP_LOAN_INVALID_PRINCIPAL"),y(r,[{accountId:e.receivableAccountId,debit:e.principalAmount,credit:0,memo:"Loan receivable principal"},{accountId:e.cashAccountId,debit:0,credit:e.principalAmount,memo:"Loan cash out"}])}function k(r,e){return h(e.amount,"COOP_SAVING_INVALID_AMOUNT"),y(r,[{accountId:e.cashAccountId,debit:e.amount,credit:0,memo:"Saving deposit cash in"},{accountId:e.savingLiabilityAccountId,debit:0,credit:e.amount,memo:"Saving liability increase"}])}function H(r,e){return h(e.amount,"COOP_SAVING_WITHDRAWAL_INVALID_AMOUNT"),y(r,[{accountId:e.savingLiabilityAccountId,debit:e.amount,credit:0,memo:"Saving liability decrease"},{accountId:e.cashAccountId,debit:0,credit:e.amount,memo:"Saving withdrawal cash out"}])}function q(r,e){h(e.principalAmount,"COOP_LOAN_REPAYMENT_INVALID_PRINCIPAL");let t=e.serviceAmount??0,n=e.penaltyAmount??0;if(t<0||n<0)throw new Error("COOP_LOAN_REPAYMENT_NEGATIVE_COMPONENT");if(t>0&&!e.serviceRevenueAccountId)throw new Error("COOP_LOAN_REPAYMENT_SERVICE_ACCOUNT_REQUIRED");if(n>0&&!e.penaltyRevenueAccountId)throw new Error("COOP_LOAN_REPAYMENT_PENALTY_ACCOUNT_REQUIRED");let a=e.principalAmount+t+n,o=[{accountId:e.cashAccountId,debit:a,credit:0,memo:"Loan repayment cash in"},{accountId:e.receivableAccountId,debit:0,credit:e.principalAmount,memo:"Loan receivable principal repayment"}];return t>0&&o.push({accountId:e.serviceRevenueAccountId,debit:0,credit:t,memo:"Loan service revenue"}),n>0&&o.push({accountId:e.penaltyRevenueAccountId,debit:0,credit:n,memo:"Loan penalty revenue"}),y(r,o)}function Ue(r,e){if(h(e.amount,"COOP_SHU_PARTICIPATION_INVALID_AMOUNT"),!r.evidenceRef?.trim())throw new Error("COOP_SHU_PARTICIPATION_EVIDENCE_REQUIRED");return y(r,[{accountId:e.debitAccountId,debit:e.amount,credit:0,memo:e.memo??"Coop SHU participation manual recap debit"},{accountId:e.creditAccountId,debit:0,credit:e.amount,memo:e.memo??"Coop SHU participation manual recap credit"}])}function $(r,e){return e?{...r,...e}:{...r}}function C(r){let e=r.tenantId?r.scopedMapping.byTenant?.[r.tenantId]:void 0,t=r.tenantId&&r.branchId?`${r.tenantId}:${r.branchId}`:"",n=t?r.scopedMapping.byBranch?.[t]:void 0;return $($(r.scopedMapping.default,e),n)}function Q(r){return C(r)}function W(r){return C(r)}function Y(r){return C(r)}function G(r){return C(r)}function X(r){return C(r)}function qe(r,e){let{scopedAccountMapping:t,...n}=e,a=Q({tenantId:r.tenantId,branchId:r.branchId,scopedMapping:t});return j(r,{...n,...a})}function $e(r,e){let{scopedAccountMapping:t,...n}=e,a=W({tenantId:r.tenantId,branchId:r.branchId,scopedMapping:t});return V(r,{...n,...a})}function Qe(r,e){let{scopedAccountMapping:t,...n}=e,a=G({tenantId:r.tenantId,branchId:r.branchId,scopedMapping:t});return k(r,{...n,...a})}function We(r,e){let{scopedAccountMapping:t,...n}=e,a=X({tenantId:r.tenantId,branchId:r.branchId,scopedMapping:t});return H(r,{...n,...a})}function Ye(r,e){let{scopedAccountMapping:t,...n}=e,a=Y({tenantId:r.tenantId,branchId:r.branchId,scopedMapping:t});return q(r,{...n,...a})}function O(r){return!!(r&&typeof r=="object"&&r.error)}function x(r){return r.startsWith("ofinance_")?`offinance_${r.slice(9)}`:r}async function se(r,e,t){let n=await r.accountService.listAccounts();if(O(n))throw new Error(n.error.message||n.error.code||"FINANCE_ACCOUNT_LIST_FAILED");let a=new Set((n.data||[]).map(o=>o.id));for(let o of e){if(a.has(o.id))continue;let i=await r.accountService.createAccount(o);if(O(i))throw new Error(i.error.message||i.error.code||"FINANCE_ACCOUNT_CREATE_FAILED");await t?.({changeId:`offinance:account:${o.id}`,entity:"FinanceAccount",table:x(c.accounts),type:"CREATE",data:o})}}async function K(r,e,t){return r.query(e,{filters:{and:t}})}async function de(r,e,t){if(!t)return;let n=await K(r,c.journals,[{field:"id",value:e.id}]),a=await K(r,c.journalLines,[{field:"journalId",value:e.id}]);n.length===0&&(n=[{id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,status:e.status,postedAt:e.postedAt,lastModified:e.postedAt||e.occurredAt,deleted:!1}]),a.length===0&&(a=e.lines.map((o,i)=>({id:`${e.id}:line:${i}`,journalId:e.id,accountId:o.accountId,debit:o.debit,credit:o.credit,memo:o.memo,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:e.postedAt||e.occurredAt,deleted:!1})));for(let o of n)await t({changeId:`offinance:journal:${o.id}`,entity:"FinanceJournalEntry",table:x(c.journals),type:"CREATE",data:o});for(let o of a)await t({changeId:`offinance:journal-line:${o.id}`,entity:"FinanceJournalLine",table:x(c.journalLines),type:"CREATE",data:o})}function Ke(r){return async e=>{let t=r.resolveFinanceServices();if(!t)throw new Error(r.missingServicesErrorCode||"FINANCE_SERVICES_UNAVAILABLE");let n=r.resolveLedgerProfileId().trim();if(!n)throw new Error(r.missingLedgerProfileErrorCode||"FINANCE_LEDGER_PROFILE_REQUIRED");let a=r.resolveSyncEnqueuer?.()??null;await se(t,r.requiredAccounts,a);let o=r.buildJournalDraft(e,n),i=await t.journalService.createJournalDraft(o);if(O(i)&&i.error.code!=="JOURNAL_ALREADY_EXISTS")throw new Error(i.error.message||i.error.code||"FINANCE_JOURNAL_CREATE_FAILED");let s=await t.journalService.postJournal(o.id,o.occurredAt);if(O(s))throw new Error(s.error.message||s.error.code||"FINANCE_JOURNAL_POST_FAILED");await de(r.dbAdapter,s.data,a)}}function ue(r){switch(r.accountType){case"asset":case"expense":return r.debit-r.credit;case"liability":case"equity":case"revenue":return r.credit-r.debit;default:return 0}}function E(r,e){return r.filter(t=>t.accountType===e).reduce((t,n)=>t+ue(n),0)}function Ze(r){let e=E(r,"revenue"),t=E(r,"expense");return{revenue:e,expense:t,netIncome:e-t}}function et(r){return{assets:E(r,"asset"),liabilities:E(r,"liability"),equity:E(r,"equity")}}function z(r){return r.accountType==="revenue"?r.credit-r.debit:r.accountType==="expense"?r.debit-r.credit:0}function nt(r){let e=r.filter(n=>n.accountType==="revenue").reduce((n,a)=>n+Math.max(0,z(a)),0),t=r.filter(n=>n.accountType==="expense").reduce((n,a)=>n+Math.max(0,z(a)),0);return{operatingInflow:e,operatingOutflow:t,netOperatingCashflow:e-t}}function rt(r,e){let t=[],n=0;for(let a of e){if(a.accountType==="revenue"){let o=a.credit-a.debit;o>0&&(t.push({accountId:a.accountId,debit:o,credit:0,memo:"Close revenue account"}),n+=o)}if(a.accountType==="expense"){let o=a.debit-a.credit;o>0&&(t.push({accountId:a.accountId,debit:0,credit:o,memo:"Close expense account"}),n-=o)}}return n>0?t.push({accountId:r.retainedEarningsAccountId,debit:0,credit:n,memo:"Retained earnings from period close"}):n<0&&t.push({accountId:r.retainedEarningsAccountId,debit:Math.abs(n),credit:0,memo:"Retained earnings from period close"}),{id:r.journalId,tenantId:r.tenantId,branchId:r.branchId,financeDomainId:r.financeDomainId,ledgerProfileId:r.ledgerProfileId,occurredAt:r.occurredAt,reference:r.reference,lines:t}}function ot(r){return{version:"v1",generatedAt:r.generatedAt??new Date().toISOString(),payload:{trialBalance:r.trialBalance.map(e=>({...e})),incomeStatement:{...r.incomeStatement},balanceSheet:{...r.balanceSheet}}}}function le(r){return r.accountType==="revenue"?r.credit-r.debit:r.accountType==="expense"?r.debit-r.credit:0}function Z(r,e){return e===0?r===0?1:0:Number((r/e).toFixed(4))}function ct(r,e){let t=e.map(a=>{let s=((a.accountCodes?.length?r.filter(I=>a.accountCodes?.includes(I.accountCode)):null)??r.filter(I=>a.accountType?I.accountType===a.accountType:!1)).reduce((I,A)=>I+le(A),0),u=s-a.plannedAmount;return{id:a.id,label:a.label,plannedAmount:a.plannedAmount,actualAmount:s,varianceAmount:u,achievementRatio:Z(s,a.plannedAmount)}}),n=t.reduce((a,o)=>(a.plannedAmount+=o.plannedAmount,a.actualAmount+=o.actualAmount,a.varianceAmount+=o.varianceAmount,a),{plannedAmount:0,actualAmount:0,varianceAmount:0});return{rows:t,totals:{...n,achievementRatio:Z(n.actualAmount,n.plannedAmount)}}}function pe(r,e){switch(e.type){case"finance.account.created":r.createAccount(e.payload);return;case"finance.period.opened":r.openFiscalPeriod(e.payload);return;case"finance.period.closed":r.closeFiscalPeriod(e.payload.periodId);return;case"finance.journal.drafted":r.createJournalDraft(e.payload);return;case"finance.journal.posted":r.postJournal(e.payload.journalId,e.payload.postedAt);return;case"finance.journal.reversed":r.reverseJournal(e.payload.journalId,e.payload.reversalId);return;default:throw new Error("FINANCE_EVENT_UNSUPPORTED")}}function ut(r){let e=new R;for(let t of r)pe(e,t);return e}var me=[{id:"coa-cash",code:"1101",name:"Kas",type:"asset"},{id:"coa-bank",code:"1102",name:"Bank",type:"asset"},{id:"coa-ar",code:"1201",name:"Piutang Usaha",type:"asset"},{id:"coa-ap",code:"2101",name:"Utang Usaha",type:"liability"},{id:"coa-retained",code:"3201",name:"Laba Ditahan",type:"equity"},{id:"coa-revenue",code:"4101",name:"Pendapatan Operasional",type:"revenue"},{id:"coa-expense",code:"5101",name:"Biaya Operasional",type:"expense"}];function pt(r="IDR"){return me.map(e=>({id:e.id,code:e.code,name:e.name,type:e.type,currency:r,isActive:!0}))}var fe=[{id:"coop-coa-cash",code:"1101",name:"Kas",type:"asset"},{id:"coop-coa-bank",code:"1102",name:"Bank",type:"asset"},{id:"coop-coa-loan-ar",code:"1201",name:"Piutang Pinjaman Anggota",type:"asset"},{id:"coop-coa-other-ar",code:"1202",name:"Piutang Lain-lain",type:"asset"},{id:"coop-coa-prepaid",code:"1301",name:"Biaya Dibayar Dimuka",type:"asset"},{id:"coop-coa-fixed-asset",code:"1401",name:"Aset Tetap",type:"asset"},{id:"coop-coa-accum-depr",code:"1402",name:"Akumulasi Penyusutan",type:"asset"},{id:"coop-coa-simp-pokok",code:"2101",name:"Simpanan Pokok",type:"liability"},{id:"coop-coa-simp-wajib",code:"2102",name:"Simpanan Wajib",type:"liability"},{id:"coop-coa-simp-sukarela",code:"2103",name:"Simpanan Sukarela",type:"liability"},{id:"coop-coa-simp-berjangka",code:"2104",name:"Simpanan Berjangka",type:"liability"},{id:"coop-coa-ap",code:"2201",name:"Utang Usaha",type:"liability"},{id:"coop-coa-ext-loan",code:"2301",name:"Pinjaman Luar",type:"liability"},{id:"coop-coa-tax-payable",code:"2401",name:"Utang Pajak",type:"liability"},{id:"coop-coa-modal-awal",code:"3101",name:"Modal Awal",type:"equity"},{id:"coop-coa-cadangan-umum",code:"3201",name:"Dana Cadangan Umum",type:"equity"},{id:"coop-coa-cadangan-tujuan",code:"3202",name:"Dana Cadangan Tujuan",type:"equity"},{id:"coop-coa-shu-prior",code:"3301",name:"SHU Tahun Lalu",type:"equity"},{id:"coop-coa-shu-current",code:"3302",name:"SHU Berjalan",type:"equity"},{id:"coop-coa-shu-reserve",code:"3303",name:"Dana SHU Belum Dibagi",type:"equity"},{id:"coop-coa-jasa-pinjaman",code:"4101",name:"Pendapatan Jasa Pinjaman",type:"revenue"},{id:"coop-coa-provisi",code:"4102",name:"Pendapatan Provisi",type:"revenue"},{id:"coop-coa-rev-other",code:"4103",name:"Pendapatan Lain-lain",type:"revenue"},{id:"coop-coa-beban-bunga",code:"5101",name:"Beban Bunga Simpanan",type:"expense"},{id:"coop-coa-beban-ops",code:"5102",name:"Beban Operasional",type:"expense"},{id:"coop-coa-beban-gaji",code:"5103",name:"Beban Gaji dan Tunjangan",type:"expense"},{id:"coop-coa-beban-admin",code:"5104",name:"Beban Administrasi",type:"expense"},{id:"coop-coa-beban-depr",code:"5105",name:"Beban Penyusutan",type:"expense"},{id:"coop-coa-prov-kredit",code:"5106",name:"Cadangan Kerugian Piutang",type:"expense"}];function mt(r="IDR"){return fe.map(e=>({id:e.id,code:e.code,name:e.name,type:e.type,currency:r,isActive:!0}))}function ft(r){let e=new Set,t=new Set;for(let n of r){if(!n.id||!n.code||!n.name)return{ok:!1,reason:"COA_REQUIRED_FIELDS"};if(e.has(n.id))return{ok:!1,reason:"COA_DUPLICATE_ID"};if(t.has(n.code))return{ok:!1,reason:"COA_DUPLICATE_CODE"};e.add(n.id),t.add(n.code)}return{ok:!0}}export{me as CANONICAL_COA_TEMPLATES,fe as COOP_COA_TEMPLATES,c as OFINANCE_TABLES,R as OffinanceCore,T as OffinanceEnvelopeService,L as OfinanceRuntimeCore,N as OfinanceRuntimeCoreBuilder,pe as applyFinanceDomainEvent,w as applyPendingMigrations,et as buildBalanceSheet,ct as buildBudgetVsRealization,nt as buildCashflowBaseline,rt as buildClosingJournalDraft,ot as buildFinanceExportEnvelope,Ze as buildIncomeStatement,V as buildJournalFromCoopLoanDisbursement,q as buildJournalFromCoopLoanRepayment,k as buildJournalFromCoopSavingDeposit,H as buildJournalFromCoopSavingWithdrawal,Ue as buildJournalFromCoopShuParticipationManualRecap,j as buildJournalFromPosSale,$e as buildJournalFromScopedCoopLoanDisbursement,Ye as buildJournalFromScopedCoopLoanRepayment,Qe as buildJournalFromScopedCoopSavingDeposit,We as buildJournalFromScopedCoopSavingWithdrawal,qe as buildJournalFromScopedPosSale,pt as createCanonicalCoA,mt as createCoopCoA,U as createDbAdapterOfinanceServices,Ke as createFinanceProjectionSink,B as createOffinanceEnvelopeService,p as mapOffinanceErrorToEnvelope,ut as replayFinanceDomainEvents,W as resolveCoopLoanDisbursementAccountMapping,Y as resolveCoopLoanRepaymentAccountMapping,G as resolveCoopSavingDepositAccountMapping,X as resolveCoopSavingWithdrawalAccountMapping,Q as resolvePosSaleAccountMapping,C as resolveScopedAccountMapping,M as toOffinanceFailureEnvelope,l as toOffinanceSuccessEnvelope,ft as validateCoaIntegrity,D as validateJournalBalance};
1
+ function P(n){if(!Array.isArray(n)||n.length===0)return{ok:!1,totalDebit:0,totalCredit:0,reason:"JOURNAL_LINES_EMPTY"};let e=0,t=0;for(let r of n){if(!r||!r.accountId)return{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_ACCOUNT_REQUIRED"};if(r.debit<0||r.credit<0)return{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_NEGATIVE_AMOUNT"};e+=r.debit,t+=r.credit}return Math.abs(e-t)>1e-6?{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_NOT_BALANCED"}:{ok:!0,totalDebit:e,totalCredit:t}}var ue=[{key:"current",label:"Current",maxDaysPastDue:0},{key:"1-30",label:"1-30 days",minDaysPastDue:1,maxDaysPastDue:30},{key:"31-60",label:"31-60 days",minDaysPastDue:31,maxDaysPastDue:60},{key:"61-90",label:"61-90 days",minDaysPastDue:61,maxDaysPastDue:90},{key:"90+",label:"90+ days",minDaysPastDue:91}];function pe(n,e,t){return n==="receivable"?e-t:t-e}function le(n,e){return[n.tenantId??"",n.branchId??"",n.financeDomainId??"",n.ledgerProfileId??"",e.accountId,e.openItemType??"",e.openItemId??""].join("::")}function V(n){return n<0?"overpaid":Math.abs(n)<1e-6?"settled":"open"}function me(n,e){if(!e)return 0;let t=Date.parse(n)-Date.parse(e);return!Number.isFinite(t)||t<=0?0:Math.floor(t/864e5)}function Ie(n,e){return e?!(e.tenantId&&n.tenantId!==e.tenantId||e.branchId&&n.branchId!==e.branchId||e.financeDomainId&&n.financeDomainId!==e.financeDomainId||e.ledgerProfileId&&n.ledgerProfileId!==e.ledgerProfileId||e.openItemType&&n.openItemType!==e.openItemType||e.counterpartyRef&&n.counterpartyRef!==e.counterpartyRef||!e.includeSettled&&n.status==="settled"):!0}function O(n){for(let e of n){let t=!!(e.openItemId||e.openItemType),r=!!(e.counterpartyRef||e.documentRef||e.dueAt);if(!(!t&&!r)){if(!e.openItemId)throw new Error("JOURNAL_OPEN_ITEM_ID_REQUIRED");if(!e.openItemType)throw new Error("JOURNAL_OPEN_ITEM_TYPE_REQUIRED");if(e.openItemType!=="receivable"&&e.openItemType!=="payable")throw new Error("JOURNAL_OPEN_ITEM_TYPE_INVALID");if(e.dueAt&&Number.isNaN(Date.parse(e.dueAt)))throw new Error("JOURNAL_OPEN_ITEM_DUE_AT_INVALID")}}}function F(n,e){let t=new Map;for(let r of n)if(r.status==="posted")for(let a of r.lines){if(!a.openItemId||!a.openItemType)continue;let o=le(r,a),i=pe(a.openItemType,a.debit,a.credit),c=t.get(o);if(!c){let s={tenantId:r.tenantId,branchId:r.branchId,financeDomainId:r.financeDomainId,ledgerProfileId:r.ledgerProfileId,openItemId:a.openItemId,openItemType:a.openItemType,accountId:a.accountId,counterpartyRef:a.counterpartyRef,documentRef:a.documentRef,dueAt:a.dueAt,originatedAt:r.occurredAt,lastActivityAt:r.occurredAt,originalAmount:i>0?i:0,settledAmount:i<0?Math.abs(i):0,outstandingAmount:i,status:V(i)};t.set(o,{item:s});continue}c.item.originatedAt=c.item.originatedAt<r.occurredAt?c.item.originatedAt:r.occurredAt,c.item.lastActivityAt=c.item.lastActivityAt>r.occurredAt?c.item.lastActivityAt:r.occurredAt,c.item.counterpartyRef=a.counterpartyRef??c.item.counterpartyRef,c.item.documentRef=a.documentRef??c.item.documentRef,c.item.dueAt=a.dueAt??c.item.dueAt,i>0?c.item.originalAmount+=i:i<0&&(c.item.settledAmount+=Math.abs(i)),c.item.outstandingAmount+=i,c.item.status=V(c.item.outstandingAmount)}return Array.from(t.values()).map(({item:r})=>({...r})).filter(r=>Ie(r,e)).sort((r,a)=>r.originatedAt!==a.originatedAt?r.originatedAt.localeCompare(a.originatedAt):r.openItemId.localeCompare(a.openItemId))}function D(n,e){if(Number.isNaN(Date.parse(e.asOf)))throw new Error("FINANCE_OPEN_ITEM_AGING_AS_OF_INVALID");let t=(e.buckets?.length?e.buckets:ue).map(a=>({...a,amount:0,itemCount:0})),r=0;for(let a of n){if(a.outstandingAmount<=0)continue;r+=a.outstandingAmount;let o=me(e.asOf,a.dueAt),i=t.find(c=>{let s=c.minDaysPastDue??Number.NEGATIVE_INFINITY,p=c.maxDaysPastDue??Number.POSITIVE_INFINITY;return o>=s&&o<=p});if(!i)throw new Error("FINANCE_OPEN_ITEM_AGING_BUCKET_UNRESOLVED");i.amount+=a.outstandingAmount,i.itemCount+=1}return{asOf:e.asOf,openItemType:e.openItemType,totalOutstanding:r,buckets:t}}function H(n,e){return`${e??""}::${n}`}function fe(n){if(!n.openItemId?.trim())throw new Error("FINANCE_RECONCILIATION_OPEN_ITEM_ID_REQUIRED");if(!Number.isFinite(n.observedAmount)||n.observedAmount<0)throw new Error("FINANCE_RECONCILIATION_OBSERVED_AMOUNT_INVALID");if(n.openItemType&&n.openItemType!=="receivable"&&n.openItemType!=="payable")throw new Error("FINANCE_RECONCILIATION_OPEN_ITEM_TYPE_INVALID")}function ge(n,e){let t=new Map;for(let r of n){fe(r);let a=r.openItemType??e,o=H(r.openItemId,a),i=t.get(o);if(!i){t.set(o,{openItemId:r.openItemId,openItemType:a,observedAmount:r.observedAmount,counterpartyRef:r.counterpartyRef,documentRef:r.documentRef,references:r.reference?[r.reference]:[]});continue}i.observedAmount+=r.observedAmount,i.counterpartyRef=r.counterpartyRef??i.counterpartyRef,i.documentRef=r.documentRef??i.documentRef,r.reference&&i.references.push(r.reference)}return t}function ye(n,e,t){let r=n.outstandingAmount,a=e?.observedAmount??0,o=a-r;if(!e)return{tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,openItemId:n.openItemId,openItemType:n.openItemType,accountId:n.accountId,counterpartyRef:n.counterpartyRef,documentRef:n.documentRef,dueAt:n.dueAt,expectedAmount:r,observedAmount:a,varianceAmount:o,status:"missing",reason:"FINANCE_RECONCILIATION_OBSERVATION_MISSING",observedReferences:[]};let i=e.counterpartyRef&&n.counterpartyRef&&e.counterpartyRef!==n.counterpartyRef||e.documentRef&&n.documentRef&&e.documentRef!==n.documentRef,c="matched",s;return i?(c="mismatch",s="FINANCE_RECONCILIATION_METADATA_MISMATCH"):Math.abs(o)<=t?c="matched":o<0?(c="under",s="FINANCE_RECONCILIATION_OBSERVED_UNDER"):o>0&&(c="over",s="FINANCE_RECONCILIATION_OBSERVED_OVER"),{tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,openItemId:n.openItemId,openItemType:n.openItemType,accountId:n.accountId,counterpartyRef:n.counterpartyRef,documentRef:n.documentRef,dueAt:n.dueAt,expectedAmount:r,observedAmount:a,varianceAmount:o,status:c,reason:s,observedReferences:[...e.references]}}function Ae(n,e){return{tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,openItemId:n.openItemId,openItemType:n.openItemType??e.openItemType,counterpartyRef:n.counterpartyRef,documentRef:n.documentRef,expectedAmount:0,observedAmount:n.observedAmount,varianceAmount:n.observedAmount,status:"mismatch",reason:"FINANCE_RECONCILIATION_EXPECTED_ITEM_NOT_FOUND",observedReferences:[...n.references]}}function w(n,e){let t=e.toleranceAmount??0;if(!Number.isFinite(t)||t<0)throw new Error("FINANCE_RECONCILIATION_TOLERANCE_INVALID");let r=ge(e.observations,e.openItemType),a=[];for(let s of n){let p=H(s.openItemId,s.openItemType),f=r.get(p);a.push(ye(s,f,t)),r.delete(p)}for(let s of r.values())a.push(Ae(s,e));a.sort((s,p)=>(s.financeDomainId??"")!==(p.financeDomainId??"")?(s.financeDomainId??"").localeCompare(p.financeDomainId??""):(s.ledgerProfileId??"")!==(p.ledgerProfileId??"")?(s.ledgerProfileId??"").localeCompare(p.ledgerProfileId??""):s.openItemId.localeCompare(p.openItemId));let o=a.reduce((s,p)=>s+p.expectedAmount,0),i=a.reduce((s,p)=>s+p.observedAmount,0),c=a.reduce((s,p)=>s+p.varianceAmount,0);return{openItemType:e.openItemType,totalExpectedAmount:o,totalObservedAmount:i,totalVarianceAmount:c,rows:a}}function be(n){if(!Array.isArray(n.trackedAccountIds)||n.trackedAccountIds.length===0)throw new Error("FINANCE_CASH_MOVEMENT_TRACKED_ACCOUNTS_REQUIRED");let e=new Set(n.trackedAccountIds.map(t=>t.trim()).filter(Boolean));if(e.size===0)throw new Error("FINANCE_CASH_MOVEMENT_TRACKED_ACCOUNTS_REQUIRED");return e}function he(n,e){return!(e.tenantId&&n.tenantId!==e.tenantId||e.branchId&&n.branchId!==e.branchId||e.financeDomainId&&n.financeDomainId!==e.financeDomainId||e.ledgerProfileId&&n.ledgerProfileId!==e.ledgerProfileId||e.occurredFrom&&n.occurredAt<e.occurredFrom||e.occurredTo&&n.occurredAt>e.occurredTo)}function _(n,e){let t=be(e),r=[];for(let a of n){if(a.status!=="posted"||!he(a,e))continue;let o=a.lines.filter(l=>t.has(l.accountId)&&(l.debit>0||l.credit>0));if(o.length===0)continue;let i=Array.from(new Set(o.map(l=>l.accountId))).sort(),c=Array.from(new Set(a.lines.filter(l=>!t.has(l.accountId)&&(l.debit>0||l.credit>0)).map(l=>l.accountId))).sort(),s=o.some(l=>l.debit>0),p=o.some(l=>l.credit>0),f=i.length>1&&s&&p;for(let l of o)l.debit>0&&r.push({journalId:a.id,tenantId:a.tenantId,branchId:a.branchId,financeDomainId:a.financeDomainId,ledgerProfileId:a.ledgerProfileId,occurredAt:a.occurredAt,reference:a.reference,evidenceRef:a.evidenceRef,accountId:l.accountId,direction:f?"transfer_in":"in",amount:l.debit,counterpartAccountIds:c,trackedAccountIdsInJournal:i}),l.credit>0&&r.push({journalId:a.id,tenantId:a.tenantId,branchId:a.branchId,financeDomainId:a.financeDomainId,ledgerProfileId:a.ledgerProfileId,occurredAt:a.occurredAt,reference:a.reference,evidenceRef:a.evidenceRef,accountId:l.accountId,direction:f?"transfer_out":"out",amount:l.credit,counterpartAccountIds:c,trackedAccountIdsInJournal:i})}return r.sort((a,o)=>a.occurredAt!==o.occurredAt?a.occurredAt.localeCompare(o.occurredAt):a.journalId!==o.journalId?a.journalId.localeCompare(o.journalId):a.accountId.localeCompare(o.accountId))}function T(n){let e=0,t=0,r=0,a=0;for(let o of n)o.direction==="in"&&(e+=o.amount),o.direction==="out"&&(t+=o.amount),o.direction==="transfer_in"&&(r+=o.amount),o.direction==="transfer_out"&&(a+=o.amount);return{totalInflow:e,totalOutflow:t,totalTransferIn:r,totalTransferOut:a,netExternalMovement:e-t,entries:n.map(o=>({...o,counterpartAccountIds:[...o.counterpartAccountIds],trackedAccountIdsInJournal:[...o.trackedAccountIdsInJournal]}))}}var N=class{constructor(e){this.state={accounts:e?.accounts??new Map,periods:e?.periods??new Map,journals:e?.journals??new Map,balances:e?.balances??new Map,rapbPlans:e?.rapbPlans??new Map}}createAccount(e){if(!e.id||!e.code||!e.name)throw new Error("FINANCE_ACCOUNT_REQUIRED_FIELDS");if(this.state.accounts.has(e.id))throw new Error("FINANCE_ACCOUNT_ALREADY_EXISTS");if(Array.from(this.state.accounts.values()).some(r=>r.code===e.code))throw new Error("FINANCE_ACCOUNT_CODE_DUPLICATE");return this.state.accounts.set(e.id,{...e}),{...e}}listAccounts(){return Array.from(this.state.accounts.values()).map(e=>({...e})).sort((e,t)=>e.code.localeCompare(t.code))}openFiscalPeriod(e){if(!e.id||!e.tenantId||!e.code||!e.startDate||!e.endDate)throw new Error("FISCAL_PERIOD_REQUIRED_FIELDS");if(this.state.periods.has(e.id))throw new Error("FISCAL_PERIOD_ALREADY_EXISTS");if(Date.parse(e.startDate)>Date.parse(e.endDate))throw new Error("FISCAL_PERIOD_INVALID_RANGE");let t={...e,status:"open"};return this.state.periods.set(t.id,t),{...t}}closeFiscalPeriod(e){let t=this.state.periods.get(e);if(!t)throw new Error("FISCAL_PERIOD_NOT_FOUND");let r={...t,status:"closed"};return this.state.periods.set(e,r),{...r}}listFiscalPeriods(){return Array.from(this.state.periods.values()).map(e=>({...e})).sort((e,t)=>e.startDate.localeCompare(t.startDate))}createJournalDraft(e){if(!e.id||!e.tenantId||!e.occurredAt)throw new Error("JOURNAL_REQUIRED_FIELDS");if(this.state.journals.has(e.id))throw new Error("JOURNAL_ALREADY_EXISTS");this.assertJournalLinesKnownAccounts(e.lines),this.assertJournalPeriodOpen(e.occurredAt),O(e.lines);let t=P(e.lines);if(!t.ok)throw new Error(t.reason??"JOURNAL_INVALID");let r={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,evidenceRef:e.evidenceRef,lines:e.lines.map(a=>({...a})),status:"draft"};return this.state.journals.set(r.id,r),{...r,lines:r.lines.map(a=>({...a}))}}postJournal(e,t=new Date().toISOString()){let r=this.state.journals.get(e);if(!r)throw new Error("JOURNAL_NOT_FOUND");if(r.status==="posted"||r.status==="reversed")return{...r,lines:r.lines.map(o=>({...o}))};this.applyLinesToBalance(r.lines);let a={...r,status:"posted",postedAt:t};return this.state.journals.set(e,a),{...a,lines:a.lines.map(o=>({...o}))}}reverseJournal(e,t){let r=this.state.journals.get(e);if(!r)throw new Error("JOURNAL_NOT_FOUND");if(r.status!=="posted")throw new Error("JOURNAL_NOT_POSTED");if(this.state.journals.has(t))throw new Error("JOURNAL_ALREADY_EXISTS");let a=r.lines.map(i=>({accountId:i.accountId,debit:i.credit,credit:i.debit,memo:i.memo,openItemId:i.openItemId,openItemType:i.openItemType,counterpartyRef:i.counterpartyRef,documentRef:i.documentRef,dueAt:i.dueAt})),o=this.createJournalDraft({id:t,tenantId:r.tenantId,branchId:r.branchId,financeDomainId:r.financeDomainId,ledgerProfileId:r.ledgerProfileId,occurredAt:r.occurredAt,reference:`reversal:${r.id}`,evidenceRef:r.evidenceRef,lines:a});return this.postJournal(o.id)}getTrialBalance(){return this.getTrialBalanceByScope()}getTrialBalanceByScope(e){let t=this.computeScopedBalances(e);return this.listAccounts().map(a=>{let o=t.get(a.id)??{debit:0,credit:0};return{accountId:a.id,accountCode:a.code,accountName:a.name,accountType:a.type,debit:o.debit,credit:o.credit,net:o.debit-o.credit}})}listJournals(e){return Array.from(this.state.journals.values()).filter(t=>this.matchesScope(t,e)).map(t=>({...t,lines:t.lines.map(r=>({...r}))})).sort((t,r)=>t.occurredAt.localeCompare(r.occurredAt))}listOpenItems(e){return F(this.listJournals(e),e)}getOpenItemAging(e){return D(this.listOpenItems(e),e)}reconcileOpenItems(e){return w(this.listOpenItems(e),e)}listCashBankMovements(e){return _(this.listJournals(e),e)}summarizeCashBankMovements(e){return T(this.listCashBankMovements(e))}assertJournalLinesKnownAccounts(e){for(let t of e)if(!this.state.accounts.has(t.accountId))throw new Error("JOURNAL_ACCOUNT_NOT_FOUND")}assertJournalPeriodOpen(e){if(this.state.periods.size===0)return;let t=this.findPeriodByDate(e);if(!t)throw new Error("FISCAL_PERIOD_NOT_FOUND_FOR_DATE");if(t.status!=="open")throw new Error("FISCAL_PERIOD_CLOSED")}findPeriodByDate(e){let t=Date.parse(e);for(let r of this.state.periods.values()){let a=Date.parse(r.startDate),o=Date.parse(r.endDate);if(t>=a&&t<=o)return r}return null}applyLinesToBalance(e){for(let t of e){let r=this.state.balances.get(t.accountId)??{debit:0,credit:0};r.debit+=t.debit,r.credit+=t.credit,this.state.balances.set(t.accountId,r)}}computeScopedBalances(e){if(!e||!e.tenantId&&!e.branchId&&!e.financeDomainId&&!e.ledgerProfileId&&!e.occurredFrom&&!e.occurredTo)return this.state.balances;let t=new Map;for(let r of this.state.journals.values())if(r.status==="posted"&&this.matchesScope(r,e))for(let a of r.lines){let o=t.get(a.accountId)??{debit:0,credit:0};o.debit+=a.debit,o.credit+=a.credit,t.set(a.accountId,o)}return t}matchesScope(e,t){return t?!(t.tenantId&&e.tenantId!==t.tenantId||t.branchId&&e.branchId!==t.branchId||t.financeDomainId&&e.financeDomainId!==t.financeDomainId||t.ledgerProfileId&&e.ledgerProfileId!==t.ledgerProfileId||t.occurredFrom&&e.occurredAt<t.occurredFrom||t.occurredTo&&e.occurredAt>t.occurredTo):!0}createRapb(e){if(!e.id||!e.tenantId||!e.periodCode||!e.title)throw new Error("RAPB_REQUIRED_FIELDS");if(!e.lines||e.lines.length===0)throw new Error("RAPB_LINES_REQUIRED");if(this.state.rapbPlans.has(e.id))throw new Error("RAPB_ALREADY_EXISTS");if(e.lines.some(a=>a.budgetedDebit<0||a.budgetedCredit<0))throw new Error("RAPB_NEGATIVE_AMOUNT");let t=e.lines.map(a=>{let o=this.state.accounts.get(a.accountId);if(!o)throw new Error(`RAPB_ACCOUNT_NOT_FOUND:${a.accountId}`);let i=a.budgetedDebit-a.budgetedCredit;return{accountId:a.accountId,accountCode:o.code,accountName:o.name,accountType:o.type,budgetedDebit:a.budgetedDebit,budgetedCredit:a.budgetedCredit,budgetedNet:i}}),r={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,periodCode:e.periodCode,title:e.title,status:"draft",lines:t,notes:e.notes,createdAt:new Date().toISOString()};return this.state.rapbPlans.set(r.id,r),r}getRapb(e){return this.state.rapbPlans.get(e)??null}listRapb(e){let t=Array.from(this.state.rapbPlans.values());return e&&(e.tenantId&&(t=t.filter(r=>r.tenantId===e.tenantId)),e.periodCode&&(t=t.filter(r=>r.periodCode===e.periodCode)),e.branchId&&(t=t.filter(r=>r.branchId===e.branchId)),e.financeDomainId&&(t=t.filter(r=>r.financeDomainId===e.financeDomainId)),e.ledgerProfileId&&(t=t.filter(r=>r.ledgerProfileId===e.ledgerProfileId))),t}approveRapb(e,t){let r=this.state.rapbPlans.get(e);if(!r)throw new Error("RAPB_NOT_FOUND");let a=typeof t=="string"?t:t.approvedBy;if(r.status==="approved")throw new Error("RAPB_ALREADY_APPROVED");let o={...r,status:"approved",approvedAt:new Date().toISOString(),approvedBy:a};return this.state.rapbPlans.set(e,o),o}evaluateVariance(e){let t=this.state.rapbPlans.get(e);if(!t)throw new Error("RAPB_NOT_FOUND");let r=this.getTrialBalance(),a=new Map(r.map(u=>[u.accountId,u])),o=0,i=0,c=0,s=0,p=t.lines.map(u=>{let C=a.get(u.accountId),g=C?.debit??0,y=C?.credit??0,E=g-y;return u.accountType==="revenue"?(o+=u.budgetedCredit-u.budgetedDebit,i+=y-g):u.accountType==="expense"&&(c+=u.budgetedDebit-u.budgetedCredit,s+=g-y),{accountId:u.accountId,accountCode:u.accountCode,accountName:u.accountName,accountType:u.accountType,budgetedDebit:u.budgetedDebit,budgetedCredit:u.budgetedCredit,budgetedNet:u.budgetedNet,actualDebit:g,actualCredit:y,actualNet:E,varianceDebit:g-u.budgetedDebit,varianceCredit:y-u.budgetedCredit,varianceNet:E-u.budgetedNet}}),f=o-c,l=i-s;return{rapbId:e,periodCode:t.periodCode,evaluatedAt:new Date().toISOString(),lines:p,totalBudgetedRevenue:o,totalActualRevenue:i,totalBudgetedExpense:c,totalActualExpense:s,budgetedNetIncome:f,actualNetIncome:l,netVariance:l-f}}};import{CoreRuntime as Re}from"ofcore";import{InMemoryDbAdapter as Pe}from"ofcore";import{asReadonlyStore as Oe,createStore as Fe}from"ofcore";var d={accounts:"ofinance_accounts",periods:"ofinance_periods",journals:"ofinance_journals",journalLines:"ofinance_journal_lines",rapbPlans:"ofinance_rapb_plans",rapbLines:"ofinance_rapb_lines",histories:"ofinance_histories"},Se=[{name:d.accounts,columns:[{name:"id",type:"string"},{name:"code",type:"string",isIndexed:!0},{name:"name",type:"string"},{name:"type",type:"string",isIndexed:!0},{name:"currency",type:"string"},{name:"isActive",type:"boolean",isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.periods,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"code",type:"string",isIndexed:!0},{name:"startDate",type:"string",isIndexed:!0},{name:"endDate",type:"string",isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.journals,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"occurredAt",type:"string",isIndexed:!0},{name:"reference",type:"string",isOptional:!0,isIndexed:!0},{name:"evidenceRef",type:"string",isOptional:!0,isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"postedAt",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.journalLines,columns:[{name:"id",type:"string"},{name:"journalId",type:"string",isIndexed:!0},{name:"accountId",type:"string",isIndexed:!0},{name:"debit",type:"number"},{name:"credit",type:"number"},{name:"memo",type:"string",isOptional:!0},{name:"openItemId",type:"string",isOptional:!0,isIndexed:!0},{name:"openItemType",type:"string",isOptional:!0,isIndexed:!0},{name:"counterpartyRef",type:"string",isOptional:!0,isIndexed:!0},{name:"documentRef",type:"string",isOptional:!0,isIndexed:!0},{name:"dueAt",type:"string",isOptional:!0,isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.rapbPlans,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"periodCode",type:"string",isIndexed:!0},{name:"title",type:"string",isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"notes",type:"string",isOptional:!0},{name:"createdAt",type:"string",isIndexed:!0},{name:"approvedAt",type:"string",isOptional:!0,isIndexed:!0},{name:"approvedBy",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.rapbLines,columns:[{name:"id",type:"string"},{name:"rapbId",type:"string",isIndexed:!0},{name:"accountId",type:"string",isIndexed:!0},{name:"accountCode",type:"string",isIndexed:!0},{name:"accountName",type:"string"},{name:"accountType",type:"string",isIndexed:!0},{name:"budgetedDebit",type:"number"},{name:"budgetedCredit",type:"number"},{name:"budgetedNet",type:"number"},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.histories,columns:[{name:"id",type:"string"},{name:"tableName",type:"string",isIndexed:!0},{name:"recordId",type:"string",isIndexed:!0},{name:"action",type:"string",isIndexed:!0},{name:"changes",type:"json",isOptional:!0},{name:"timestamp",type:"string",isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0}]}];function B(){return Se.map(n=>({...n,columns:n.columns.map(e=>({...e}))}))}var Q=[{toVersion:1,up:async n=>{let e=B();for(let t of e)try{await n.addTable(t)}catch{}}},{toVersion:2,up:async n=>{let e=B().filter(t=>t.name==="ofinance_rapb_plans"||t.name==="ofinance_rapb_lines");for(let t of e)try{await n.addTable(t)}catch{}}},{toVersion:3,up:async n=>{try{await n.addColumn("ofinance_journals",{name:"evidenceRef",type:"string",isOptional:!0,isIndexed:!0})}catch{}}},{toVersion:4,up:async n=>{let e=[{name:"openItemId",type:"string",isOptional:!0,isIndexed:!0},{name:"openItemType",type:"string",isOptional:!0,isIndexed:!0},{name:"counterpartyRef",type:"string",isOptional:!0,isIndexed:!0},{name:"documentRef",type:"string",isOptional:!0,isIndexed:!0},{name:"dueAt",type:"string",isOptional:!0,isIndexed:!0}];for(let t of e)try{await n.addColumn("ofinance_journal_lines",t)}catch{}}}];var Ce={logInfo(){},logWarn(){},logError(){}};async function L(n,e=Ce){e.logInfo("[offinance] starting database migration process");let t=[...Q].sort((o,i)=>o.toVersion-i.toVersion),r=t.length>0?t[t.length-1].toVersion:0,a=await n.getSchemaVersion();if((a==null||a<0)&&(a=0),a>=r){e.logInfo(`[offinance] database already up-to-date at v${a}`);return}for(let o of t)o.toVersion>a&&(e.logInfo(`[offinance] applying migration v${o.toVersion}`),await o.up(n),await n.setSchemaVersion(o.toVersion),a=o.toVersion);e.logInfo(`[offinance] migration completed at v${a}`)}function m(n,e){return{data:n,meta:{request_id:e??null,timestamp:new Date().toISOString()}}}function q(n,e,t={}){return{error:{code:n,message:e,details:t.details,retryable:t.retryable,correlationId:t.correlationId,timestamp:new Date().toISOString()},meta:{request_id:t.requestId??null,timestamp:new Date().toISOString()}}}function I(n,e="FINANCE_NOT_IMPLEMENTED",t="Unhandled offinance error."){return n instanceof Error?q(e,n.message||t):q(e,t)}var J=class{constructor(e){this.legacy=e;this.accountService={createAccount:async t=>{try{return m(await this.legacy.accountService.createAccount(t))}catch(r){return I(r)}},listAccounts:async()=>{try{return m(await this.legacy.accountService.listAccounts())}catch(t){return I(t)}}},this.journalService={createJournalDraft:async t=>{try{return m(await this.legacy.journalService.createJournalDraft(t))}catch(r){return I(r)}},postJournal:async(t,r)=>{try{return m(await this.legacy.journalService.postJournal(t,r))}catch(a){return I(a)}},reverseJournal:async(t,r)=>{try{return m(await this.legacy.journalService.reverseJournal(t,r))}catch(a){return I(a)}},listJournals:async t=>{try{return m(await this.legacy.journalService.listJournals(t))}catch(r){return I(r)}}},this.fiscalService={openFiscalPeriod:async t=>{try{return m(await this.legacy.fiscalService.openFiscalPeriod(t))}catch(r){return I(r)}},closeFiscalPeriod:async t=>{try{return m(await this.legacy.fiscalService.closeFiscalPeriod(t))}catch(r){return I(r)}},listFiscalPeriods:async()=>{try{return m(await this.legacy.fiscalService.listFiscalPeriods())}catch(t){return I(t)}},getTrialBalance:async()=>{try{return m(await this.legacy.fiscalService.getTrialBalance())}catch(t){return I(t)}},getTrialBalanceByScope:async t=>{try{return m(await this.legacy.fiscalService.getTrialBalanceByScope(t))}catch(r){return I(r)}}},this.rapbService={createRapb:async t=>{try{return m(await this.legacy.rapbService.createRapb(t))}catch(r){return I(r)}},getRapb:async t=>{try{return m(await this.legacy.rapbService.getRapb(t))}catch(r){return I(r)}},listRapb:async t=>{try{return m(await this.legacy.rapbService.listRapb(t))}catch(r){return I(r)}},approveRapb:async(t,r)=>{try{return m(await this.legacy.rapbService.approveRapb(t,r))}catch(a){return I(a)}},evaluateVariance:async t=>{try{return m(await this.legacy.rapbService.evaluateVariance(t))}catch(r){return I(r)}}},this.openItemService={listOpenItems:async t=>{try{return m(await this.legacy.openItemService.listOpenItems(t))}catch(r){return I(r)}},getOpenItemAging:async t=>{try{return m(await this.legacy.openItemService.getOpenItemAging(t))}catch(r){return I(r)}}},this.reconciliationService={reconcileOpenItems:async t=>{try{return m(await this.legacy.reconciliationService.reconcileOpenItems(t))}catch(r){return I(r)}}},this.cashMovementService={listCashBankMovements:async t=>{try{return m(await this.legacy.cashMovementService.listCashBankMovements(t))}catch(r){return I(r)}},summarizeCashBankMovements:async t=>{try{return m(await this.legacy.cashMovementService.summarizeCashBankMovements(t))}catch(r){return I(r)}}}}};function $(n){return new J({accountService:n,journalService:n,fiscalService:n,rapbService:n,openItemService:n,reconciliationService:n,cashMovementService:n})}function b(n){return JSON.parse(JSON.stringify(n))}function A(){return new Date().toISOString()}function Ee(n,e){return`${n}:${e}:${Date.now()}:${Math.random().toString(36).slice(2,8)}`}function ve(n,e){return!n||n.deleted?!1:e?!(e.tenantId&&n.tenantId!==e.tenantId||e.branchId&&n.branchId!==e.branchId||e.financeDomainId&&n.financeDomainId!==e.financeDomainId||e.ledgerProfileId&&n.ledgerProfileId!==e.ledgerProfileId||e.occurredFrom&&n.occurredAt&&n.occurredAt<e.occurredFrom||e.occurredTo&&n.occurredAt&&n.occurredAt>e.occurredTo):!0}var x=class{constructor(e){this.dbAdapter=e}async createAccount(e){if(!e.id||!e.code||!e.name)throw new Error("FINANCE_ACCOUNT_REQUIRED_FIELDS");let t=await this.dbAdapter.get(d.accounts,e.id);if(t&&!t.deleted)throw new Error("FINANCE_ACCOUNT_ALREADY_EXISTS");if((await this.dbAdapter.query(d.accounts,{filters:{and:[{field:"code",value:e.code},{field:"deleted",value:!1}]}})).some(i=>i.id!==e.id))throw new Error("FINANCE_ACCOUNT_CODE_DUPLICATE");let a=A(),o={...b(e),lastModified:a,deleted:!1};return t?await this.dbAdapter.update(d.accounts,e.id,o):await this.dbAdapter.create(d.accounts,o),await this.writeHistory("accounts",e.id,"UPSERT",o),b(e)}async listAccounts(){return(await this.dbAdapter.query(d.accounts,{filters:{field:"deleted",value:!1}})).map(({lastModified:t,deleted:r,...a})=>b(a)).sort((t,r)=>t.code.localeCompare(r.code))}async createJournalDraft(e){if(!e.id||!e.tenantId||!e.occurredAt)throw new Error("JOURNAL_REQUIRED_FIELDS");if(!e.ledgerProfileId)throw new Error("JOURNAL_REQUIRED_FIELDS");let t=await this.dbAdapter.get(d.journals,e.id);if(t&&!t.deleted)throw new Error("JOURNAL_ALREADY_EXISTS");await this.assertJournalLinesKnownAccounts(e.lines),await this.assertJournalPeriodOpen(e),O(e.lines);let r=P(e.lines);if(!r.ok)throw new Error(r.reason??"JOURNAL_INVALID");let a=A(),o={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,evidenceRef:e.evidenceRef,status:"draft",postedAt:void 0,lastModified:a,deleted:!1};await this.dbAdapter.create(d.journals,o);for(let i=0;i<e.lines.length;i+=1){let c=e.lines[i],s={id:`${e.id}:line:${i}`,journalId:e.id,accountId:c.accountId,debit:c.debit,credit:c.credit,memo:c.memo,openItemId:c.openItemId,openItemType:c.openItemType,counterpartyRef:c.counterpartyRef,documentRef:c.documentRef,dueAt:c.dueAt,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:a,deleted:!1};await this.dbAdapter.create(d.journalLines,s),await this.writeHistory("journal_lines",s.id,"UPSERT",s)}return await this.writeHistory("journals",e.id,"UPSERT",o),this.toJournalEntry(o,e.lines)}async postJournal(e,t=A()){let r=await this.requireJournal(e),a=await this.listJournalLines(e);if(r.status==="posted"||r.status==="reversed")return this.toJournalEntry(r,a);let o={...r,status:"posted",postedAt:t,lastModified:A()};return await this.dbAdapter.update(d.journals,e,o),await this.writeHistory("journals",e,"UPSERT",o),this.toJournalEntry(o,a)}async reverseJournal(e,t){let r=await this.requireJournal(e);if(r.status!=="posted")throw new Error("JOURNAL_NOT_POSTED");let a=await this.listJournalLines(e),o=await this.createJournalDraft({id:t,tenantId:r.tenantId,branchId:r.branchId,financeDomainId:r.financeDomainId,ledgerProfileId:r.ledgerProfileId,occurredAt:r.occurredAt,reference:`reversal:${r.id}`,evidenceRef:r.evidenceRef,lines:a.map(i=>({accountId:i.accountId,debit:i.credit,credit:i.debit,memo:i.memo,openItemId:i.openItemId,openItemType:i.openItemType,counterpartyRef:i.counterpartyRef,documentRef:i.documentRef,dueAt:i.dueAt}))});return this.postJournal(o.id)}async listJournals(e){let r=(await this.dbAdapter.query(d.journals,{filters:{field:"deleted",value:!1}})).filter(o=>ve(o,e)).sort((o,i)=>o.occurredAt.localeCompare(i.occurredAt)),a=[];for(let o of r){let i=await this.listJournalLines(o.id);a.push(this.toJournalEntry(o,i))}return a}async listOpenItems(e){return F(await this.listJournals(e),e)}async getOpenItemAging(e){return D(await this.listOpenItems(e),e)}async reconcileOpenItems(e){return w(await this.listOpenItems(e),e)}async listCashBankMovements(e){return _(await this.listJournals(e),e)}async summarizeCashBankMovements(e){return T(await this.listCashBankMovements(e))}async openFiscalPeriod(e){if(!e.id||!e.tenantId||!e.code||!e.startDate||!e.endDate)throw new Error("FISCAL_PERIOD_REQUIRED_FIELDS");if(Date.parse(e.startDate)>Date.parse(e.endDate))throw new Error("FISCAL_PERIOD_INVALID_RANGE");let t=await this.dbAdapter.get(d.periods,e.id);if(t&&!t.deleted)throw new Error("FISCAL_PERIOD_ALREADY_EXISTS");let r=A(),a={...b(e),status:"open",lastModified:r,deleted:!1};return t?await this.dbAdapter.update(d.periods,e.id,a):await this.dbAdapter.create(d.periods,a),await this.writeHistory("periods",e.id,"UPSERT",a),this.toPeriod(a)}async closeFiscalPeriod(e){let t=await this.dbAdapter.get(d.periods,e);if(!t||t.deleted)throw new Error("FISCAL_PERIOD_NOT_FOUND");let r={...t,status:"closed",lastModified:A()};return await this.dbAdapter.update(d.periods,e,r),await this.writeHistory("periods",e,"UPSERT",r),this.toPeriod(r)}async listFiscalPeriods(){return(await this.dbAdapter.query(d.periods,{filters:{field:"deleted",value:!1}})).map(t=>this.toPeriod(t)).sort((t,r)=>t.startDate.localeCompare(r.startDate))}async getTrialBalance(){return this.getTrialBalanceByScope()}async getTrialBalanceByScope(e){let t=await this.listAccounts(),a=(await this.listJournals(e)).filter(i=>i.status==="posted"),o=new Map;for(let i of a)for(let c of i.lines){let s=o.get(c.accountId)??{debit:0,credit:0};s.debit+=Number(c.debit||0),s.credit+=Number(c.credit||0),o.set(c.accountId,s)}return t.map(i=>{let c=o.get(i.id)??{debit:0,credit:0};return{accountId:i.id,accountCode:i.code,accountName:i.name,accountType:i.type,debit:c.debit,credit:c.credit,net:c.debit-c.credit}})}async createRapb(e){if(!e.id||!e.tenantId||!e.periodCode||!e.title)throw new Error("RAPB_REQUIRED_FIELDS");if(!e.lines||e.lines.length===0)throw new Error("RAPB_LINES_REQUIRED");if(e.lines.some(i=>i.budgetedDebit<0||i.budgetedCredit<0))throw new Error("RAPB_NEGATIVE_AMOUNT");let t=await this.dbAdapter.get(d.rapbPlans,e.id);if(t&&!t.deleted)throw new Error("RAPB_ALREADY_EXISTS");let r=A(),a=[];for(let i=0;i<e.lines.length;i+=1){let c=e.lines[i],s=await this.dbAdapter.get(d.accounts,c.accountId);if(!s||s.deleted)throw new Error(`RAPB_ACCOUNT_NOT_FOUND:${c.accountId}`);a.push({id:`${e.id}:line:${i}`,rapbId:e.id,accountId:c.accountId,accountCode:s.code,accountName:s.name,accountType:s.type,budgetedDebit:c.budgetedDebit,budgetedCredit:c.budgetedCredit,budgetedNet:c.budgetedDebit-c.budgetedCredit,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:r,deleted:!1})}let o={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,periodCode:e.periodCode,title:e.title,status:"draft",notes:e.notes,createdAt:r,approvedAt:void 0,approvedBy:void 0,lastModified:r,deleted:!1};await this.dbAdapter.create(d.rapbPlans,o),await this.writeHistory("rapb_plans",e.id,"UPSERT",o);for(let i of a)await this.dbAdapter.create(d.rapbLines,i),await this.writeHistory("rapb_lines",i.id,"UPSERT",i);return this.toRapbPlan(o,a)}async getRapb(e){let t=await this.dbAdapter.get(d.rapbPlans,e);if(!t||t.deleted)return null;let r=await this.listRapbLines(e);return this.toRapbPlan(t,r)}async listRapb(e){let r=await this.dbAdapter.query(d.rapbPlans,{filters:{field:"deleted",value:!1}});e&&(e.tenantId&&(r=r.filter(o=>o.tenantId===e.tenantId)),e.periodCode&&(r=r.filter(o=>o.periodCode===e.periodCode)),e.branchId&&(r=r.filter(o=>o.branchId===e.branchId)),e.financeDomainId&&(r=r.filter(o=>o.financeDomainId===e.financeDomainId)),e.ledgerProfileId&&(r=r.filter(o=>o.ledgerProfileId===e.ledgerProfileId)));let a=[];for(let o of r.sort((i,c)=>i.createdAt.localeCompare(c.createdAt))){let i=await this.listRapbLines(o.id);a.push(this.toRapbPlan(o,i))}return a}async approveRapb(e,t){let r=await this.dbAdapter.get(d.rapbPlans,e);if(!r||r.deleted)throw new Error("RAPB_NOT_FOUND");if(r.status==="approved")throw new Error("RAPB_ALREADY_APPROVED");let a=typeof t=="string"?t:t.approvedBy,o={...r,status:"approved",approvedAt:A(),approvedBy:a,lastModified:A()};await this.dbAdapter.update(d.rapbPlans,e,o),await this.writeHistory("rapb_plans",e,"UPSERT",o);let i=await this.listRapbLines(e);return this.toRapbPlan(o,i)}async evaluateVariance(e){let t=await this.getRapb(e);if(!t)throw new Error("RAPB_NOT_FOUND");let r=await this.getTrialBalanceByScope({tenantId:t.tenantId,branchId:t.branchId,financeDomainId:t.financeDomainId,ledgerProfileId:t.ledgerProfileId}),a=new Map(r.map(u=>[u.accountId,u])),o=0,i=0,c=0,s=0,p=t.lines.map(u=>{let C=a.get(u.accountId),g=C?.debit??0,y=C?.credit??0,E=g-y;return u.accountType==="revenue"?(o+=u.budgetedCredit-u.budgetedDebit,i+=y-g):u.accountType==="expense"&&(c+=u.budgetedDebit-u.budgetedCredit,s+=g-y),{accountId:u.accountId,accountCode:u.accountCode,accountName:u.accountName,accountType:u.accountType,budgetedDebit:u.budgetedDebit,budgetedCredit:u.budgetedCredit,budgetedNet:u.budgetedNet,actualDebit:g,actualCredit:y,actualNet:E,varianceDebit:g-u.budgetedDebit,varianceCredit:y-u.budgetedCredit,varianceNet:E-u.budgetedNet}}),f=o-c,l=i-s;return{rapbId:e,periodCode:t.periodCode,evaluatedAt:A(),lines:p,totalBudgetedRevenue:o,totalActualRevenue:i,totalBudgetedExpense:c,totalActualExpense:s,budgetedNetIncome:f,actualNetIncome:l,netVariance:l-f}}async assertJournalLinesKnownAccounts(e){for(let t of e){let r=await this.dbAdapter.get(d.accounts,t.accountId);if(!r||r.deleted)throw new Error("JOURNAL_ACCOUNT_NOT_FOUND")}}async assertJournalPeriodOpen(e){let t=await this.dbAdapter.query(d.periods,{filters:{field:"deleted",value:!1}});if(t.length===0)return;let r=t.find(a=>!(a.tenantId!==e.tenantId||Date.parse(a.startDate)>Date.parse(e.occurredAt)||Date.parse(a.endDate)<Date.parse(e.occurredAt)||e.ledgerProfileId&&a.ledgerProfileId&&a.ledgerProfileId!==e.ledgerProfileId||e.financeDomainId&&a.financeDomainId&&a.financeDomainId!==e.financeDomainId));if(!r)throw new Error("FISCAL_PERIOD_NOT_FOUND_FOR_DATE");if(r.status!=="open")throw new Error("FISCAL_PERIOD_CLOSED")}async requireJournal(e){let t=await this.dbAdapter.get(d.journals,e);if(!t||t.deleted)throw new Error("JOURNAL_NOT_FOUND");return t}async listJournalLines(e){return(await this.dbAdapter.query(d.journalLines,{filters:{and:[{field:"journalId",value:e},{field:"deleted",value:!1}]}})).sort((r,a)=>r.id.localeCompare(a.id))}async listRapbLines(e){return(await this.dbAdapter.query(d.rapbLines,{filters:{and:[{field:"rapbId",value:e},{field:"deleted",value:!1}]}})).sort((r,a)=>r.id.localeCompare(a.id))}toJournalEntry(e,t){let{lastModified:r,deleted:a,...o}=e;return{...b(o),lines:t.map(i=>b(i))}}toPeriod(e){let{lastModified:t,deleted:r,...a}=e;return b(a)}toRapbPlan(e,t){let{lastModified:r,deleted:a,...o}=e;return{...b(o),lines:t.map(({id:i,rapbId:c,lastModified:s,deleted:p,...f})=>b(f))}}async writeHistory(e,t,r,a){let o=a,i={id:Ee(e,t),tableName:e,recordId:t,action:r,changes:b(o),timestamp:A(),tenantId:typeof o.tenantId=="string"?o.tenantId:void 0,branchId:typeof o.branchId=="string"?o.branchId:void 0,financeDomainId:typeof o.financeDomainId=="string"?o.financeDomainId:void 0,ledgerProfileId:typeof o.ledgerProfileId=="string"?o.ledgerProfileId:void 0};await this.dbAdapter.create(d.histories,i)}};async function G(n){await L(n);let e=new x(n);return{financeService:$({createAccount:e.createAccount.bind(e),listAccounts:e.listAccounts.bind(e),createJournalDraft:e.createJournalDraft.bind(e),postJournal:e.postJournal.bind(e),reverseJournal:e.reverseJournal.bind(e),listJournals:e.listJournals.bind(e),openFiscalPeriod:e.openFiscalPeriod.bind(e),closeFiscalPeriod:e.closeFiscalPeriod.bind(e),listFiscalPeriods:e.listFiscalPeriods.bind(e),getTrialBalance:e.getTrialBalance.bind(e),getTrialBalanceByScope:e.getTrialBalanceByScope.bind(e),createRapb:e.createRapb.bind(e),getRapb:e.getRapb.bind(e),listRapb:e.listRapb.bind(e),approveRapb:e.approveRapb.bind(e),evaluateVariance:e.evaluateVariance.bind(e),listOpenItems:e.listOpenItems.bind(e),getOpenItemAging:e.getOpenItemAging.bind(e),reconcileOpenItems:e.reconcileOpenItems.bind(e),listCashBankMovements:e.listCashBankMovements.bind(e),summarizeCashBankMovements:e.summarizeCashBankMovements.bind(e)})}}var k=class{constructor(e,t){this.runtime=e;this.runtimeStateStore=t;this.runtimeStore=Oe(this.runtimeStateStore)}static builder(){return new j}get registry(){return this.runtime.registry}async start(e={}){this.runtimeStateStore.setState({phase:"starting",started:!1,lastError:null,lastTransitionAt:new Date().toISOString(),startCount:this.runtimeStateStore.getState().startCount,stopCount:this.runtimeStateStore.getState().stopCount});try{await this.runtime.start(e),this.domainServices=this.runtime.domainServices,this.runtimeStateStore.setState(t=>({...t,phase:"started",started:!0,startCount:t.startCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(t){throw this.runtimeStateStore.setState(r=>({...r,phase:"error",started:!1,lastError:t instanceof Error?t.message:String(t),lastTransitionAt:new Date().toISOString()})),t}}async stop(){this.runtimeStateStore.setState(e=>({...e,phase:"stopping",started:this.runtime.isStarted(),lastError:null,lastTransitionAt:new Date().toISOString()}));try{await this.runtime.stop(),this.runtimeStateStore.setState(e=>({...e,phase:"stopped",started:!1,stopCount:e.stopCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(e){throw this.runtimeStateStore.setState(t=>({...t,phase:"error",started:this.runtime.isStarted(),lastError:e instanceof Error?e.message:String(e),lastTransitionAt:new Date().toISOString()})),e}}isStarted(){return this.runtime.isStarted()}},j=class{constructor(){this.runtimeBuilder=Re.builder();this.runtimeHooks={};this.runtimeBuilder.withDbAdapter(()=>new Pe)}withPlatformAdapter(e){return this.runtimeBuilder.withPlatformAdapter(e),this}withDbAdapter(e){return this.runtimeBuilder.withDbAdapter(e),this}withHttpAdapter(e){return this.runtimeBuilder.withHttpAdapter(e),this}withSocketAdapter(e){return this.runtimeBuilder.withSocketAdapter(e),this}withLoggerAdapter(e){return this.runtimeBuilder.withLoggerAdapter(e),this}withActivitySink(e){return this.runtimeBuilder.withActivitySink(e),this}withExtension(e,t){return this.runtimeBuilder.withExtension(e,t),this}withDomainServicesFactory(e){return this.domainServicesFactory=e,this}withRuntimeHooks(e){return this.runtimeHooks={...this.runtimeHooks,...e},this}build(){let e=Fe({phase:"idle",started:!1,startCount:0,stopCount:0,lastError:null,lastTransitionAt:new Date().toISOString()}),t={runMigrations:async a=>{let o=a.registry?.dbAdapter;if(!o)throw new Error("OFINANCE_DB_ADAPTER_REQUIRED");await L(o,a.registry?.loggerAdapter),this.runtimeHooks.runMigrations&&await this.runtimeHooks.runMigrations(a)},...this.runtimeHooks,createDomainServices:async a=>{if(this.domainServicesFactory)return this.domainServicesFactory();let o=a.registry?.dbAdapter;if(!o)throw new Error("OFINANCE_DB_ADAPTER_REQUIRED");return G(o)}};this.runtimeBuilder.withHooks(t);let r=this.runtimeBuilder.build();return new k(r,e)}};function Y(n){return!Array.isArray(n.components)||n.components.length===0?[]:n.components.map(e=>{if(!e.accountId?.trim())throw new Error("FINANCE_TAX_ACCOUNT_REQUIRED");if(!Number.isFinite(e.amount)||e.amount<=0)throw new Error("FINANCE_TAX_AMOUNT_INVALID");if(e.direction!=="payable"&&e.direction!=="receivable")throw new Error("FINANCE_TAX_DIRECTION_INVALID");let t=`${n.memoPrefix??"Finance tax"} ${e.direction}`;return{accountId:e.accountId,debit:e.direction==="receivable"?e.amount:0,credit:e.direction==="payable"?e.amount:0,memo:e.memo??t}})}function h(n,e,t){return{id:n.journalId,tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,occurredAt:n.occurredAt,reference:t?`${n.reference??""}${t}`:n.reference,evidenceRef:n.evidenceRef,lines:e}}function S(n,e){if(!Number.isFinite(n)||n<=0)throw new Error(e)}function z(n,e){S(e.grossAmount,"POS_SALE_INVALID_GROSS_AMOUNT");let t=e.discountAmount??0,r=e.taxAmount??0;if(t<0||r<0)throw new Error("POS_SALE_NEGATIVE_COMPONENT");let a=e.grossAmount,o=a-t+r,i=[{accountId:e.paymentAccountId,debit:o,credit:0,memo:"POS sale payment"},{accountId:e.revenueAccountId,debit:0,credit:a,memo:"POS sale revenue"}];if(t>0){if(!e.discountAccountId)throw new Error("POS_SALE_DISCOUNT_ACCOUNT_REQUIRED");i.push({accountId:e.discountAccountId,debit:t,credit:0,memo:"POS sale discount"})}if(r>0){if(!e.taxPayableAccountId)throw new Error("POS_SALE_TAX_ACCOUNT_REQUIRED");i.push(...Y({memoPrefix:"POS sale tax",components:[{accountId:e.taxPayableAccountId,amount:r,direction:"payable",memo:"POS sale tax payable"}]}))}return h(n,i)}function W(n,e){return S(e.principalAmount,"COOP_LOAN_INVALID_PRINCIPAL"),h(n,[{accountId:e.receivableAccountId,debit:e.principalAmount,credit:0,memo:"Loan receivable principal"},{accountId:e.cashAccountId,debit:0,credit:e.principalAmount,memo:"Loan cash out"}])}function X(n,e){return S(e.amount,"COOP_SAVING_INVALID_AMOUNT"),h(n,[{accountId:e.cashAccountId,debit:e.amount,credit:0,memo:"Saving deposit cash in"},{accountId:e.savingLiabilityAccountId,debit:0,credit:e.amount,memo:"Saving liability increase"}])}function K(n,e){return S(e.amount,"COOP_SAVING_WITHDRAWAL_INVALID_AMOUNT"),h(n,[{accountId:e.savingLiabilityAccountId,debit:e.amount,credit:0,memo:"Saving liability decrease"},{accountId:e.cashAccountId,debit:0,credit:e.amount,memo:"Saving withdrawal cash out"}])}function Z(n,e){S(e.principalAmount,"COOP_LOAN_REPAYMENT_INVALID_PRINCIPAL");let t=e.serviceAmount??0,r=e.penaltyAmount??0;if(t<0||r<0)throw new Error("COOP_LOAN_REPAYMENT_NEGATIVE_COMPONENT");if(t>0&&!e.serviceRevenueAccountId)throw new Error("COOP_LOAN_REPAYMENT_SERVICE_ACCOUNT_REQUIRED");if(r>0&&!e.penaltyRevenueAccountId)throw new Error("COOP_LOAN_REPAYMENT_PENALTY_ACCOUNT_REQUIRED");let a=e.principalAmount+t+r,o=[{accountId:e.cashAccountId,debit:a,credit:0,memo:"Loan repayment cash in"},{accountId:e.receivableAccountId,debit:0,credit:e.principalAmount,memo:"Loan receivable principal repayment"}];return t>0&&o.push({accountId:e.serviceRevenueAccountId,debit:0,credit:t,memo:"Loan service revenue"}),r>0&&o.push({accountId:e.penaltyRevenueAccountId,debit:0,credit:r,memo:"Loan penalty revenue"}),h(n,o)}function vn(n,e){if(S(e.amount,"COOP_SHU_PARTICIPATION_INVALID_AMOUNT"),!n.evidenceRef?.trim())throw new Error("COOP_SHU_PARTICIPATION_EVIDENCE_REQUIRED");return h(n,[{accountId:e.debitAccountId,debit:e.amount,credit:0,memo:e.memo??"Coop SHU participation manual recap debit"},{accountId:e.creditAccountId,debit:0,credit:e.amount,memo:e.memo??"Coop SHU participation manual recap credit"}])}function ee(n,e){return e?{...n,...e}:{...n}}function v(n){let e=n.tenantId?n.scopedMapping.byTenant?.[n.tenantId]:void 0,t=n.tenantId&&n.branchId?`${n.tenantId}:${n.branchId}`:"",r=t?n.scopedMapping.byBranch?.[t]:void 0;return ee(ee(n.scopedMapping.default,e),r)}function ne(n){return v(n)}function te(n){return v(n)}function re(n){return v(n)}function ae(n){return v(n)}function oe(n){return v(n)}function Dn(n,e){let{scopedAccountMapping:t,...r}=e,a=ne({tenantId:n.tenantId,branchId:n.branchId,scopedMapping:t});return z(n,{...r,...a})}function wn(n,e){let{scopedAccountMapping:t,...r}=e,a=te({tenantId:n.tenantId,branchId:n.branchId,scopedMapping:t});return W(n,{...r,...a})}function _n(n,e){let{scopedAccountMapping:t,...r}=e,a=ae({tenantId:n.tenantId,branchId:n.branchId,scopedMapping:t});return X(n,{...r,...a})}function Tn(n,e){let{scopedAccountMapping:t,...r}=e,a=oe({tenantId:n.tenantId,branchId:n.branchId,scopedMapping:t});return K(n,{...r,...a})}function Nn(n,e){let{scopedAccountMapping:t,...r}=e,a=re({tenantId:n.tenantId,branchId:n.branchId,scopedMapping:t});return Z(n,{...r,...a})}function M(n){return!!(n&&typeof n=="object"&&n.error)}function U(n){return n.startsWith("ofinance_")?`offinance_${n.slice(9)}`:n}async function De(n,e,t){let r=await n.accountService.listAccounts();if(M(r))throw new Error(r.error.message||r.error.code||"FINANCE_ACCOUNT_LIST_FAILED");let a=new Set((r.data||[]).map(o=>o.id));for(let o of e){if(a.has(o.id))continue;let i=await n.accountService.createAccount(o);if(M(i))throw new Error(i.error.message||i.error.code||"FINANCE_ACCOUNT_CREATE_FAILED");await t?.({changeId:`offinance:account:${o.id}`,entity:"FinanceAccount",table:U(d.accounts),type:"CREATE",data:o})}}async function ie(n,e,t){return n.query(e,{filters:{and:t}})}async function we(n,e,t){if(!t)return;let r=await ie(n,d.journals,[{field:"id",value:e.id}]),a=await ie(n,d.journalLines,[{field:"journalId",value:e.id}]);r.length===0&&(r=[{id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,status:e.status,postedAt:e.postedAt,lastModified:e.postedAt||e.occurredAt,deleted:!1}]),a.length===0&&(a=e.lines.map((o,i)=>({id:`${e.id}:line:${i}`,journalId:e.id,accountId:o.accountId,debit:o.debit,credit:o.credit,memo:o.memo,openItemId:o.openItemId,openItemType:o.openItemType,counterpartyRef:o.counterpartyRef,documentRef:o.documentRef,dueAt:o.dueAt,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:e.postedAt||e.occurredAt,deleted:!1})));for(let o of r)await t({changeId:`offinance:journal:${o.id}`,entity:"FinanceJournalEntry",table:U(d.journals),type:"CREATE",data:o});for(let o of a)await t({changeId:`offinance:journal-line:${o.id}`,entity:"FinanceJournalLine",table:U(d.journalLines),type:"CREATE",data:o})}function Mn(n){return async e=>{let t=n.resolveFinanceServices();if(!t)throw new Error(n.missingServicesErrorCode||"FINANCE_SERVICES_UNAVAILABLE");let r=n.resolveLedgerProfileId().trim();if(!r)throw new Error(n.missingLedgerProfileErrorCode||"FINANCE_LEDGER_PROFILE_REQUIRED");let a=n.resolveSyncEnqueuer?.()??null;await De(t,n.requiredAccounts,a);let o=n.buildJournalDraft(e,r),i=await t.journalService.createJournalDraft(o);if(M(i)&&i.error.code!=="JOURNAL_ALREADY_EXISTS")throw new Error(i.error.message||i.error.code||"FINANCE_JOURNAL_CREATE_FAILED");let c=await t.journalService.postJournal(o.id,o.occurredAt);if(M(c))throw new Error(c.error.message||c.error.code||"FINANCE_JOURNAL_POST_FAILED");await we(n.dbAdapter,c.data,a)}}function _e(n){switch(n.accountType){case"asset":case"expense":return n.debit-n.credit;case"liability":case"equity":case"revenue":return n.credit-n.debit;default:return 0}}function R(n,e){return n.filter(t=>t.accountType===e).reduce((t,r)=>t+_e(r),0)}function Jn(n){let e=R(n,"revenue"),t=R(n,"expense");return{revenue:e,expense:t,netIncome:e-t}}function kn(n){return{assets:R(n,"asset"),liabilities:R(n,"liability"),equity:R(n,"equity")}}function ce(n){return n.accountType==="revenue"?n.credit-n.debit:n.accountType==="expense"?n.debit-n.credit:0}function Un(n){let e=n.filter(r=>r.accountType==="revenue").reduce((r,a)=>r+Math.max(0,ce(a)),0),t=n.filter(r=>r.accountType==="expense").reduce((r,a)=>r+Math.max(0,ce(a)),0);return{operatingInflow:e,operatingOutflow:t,netOperatingCashflow:e-t}}function Vn(n,e){let t=[],r=0;for(let a of e){if(a.accountType==="revenue"){let o=a.credit-a.debit;o>0&&(t.push({accountId:a.accountId,debit:o,credit:0,memo:"Close revenue account"}),r+=o)}if(a.accountType==="expense"){let o=a.debit-a.credit;o>0&&(t.push({accountId:a.accountId,debit:0,credit:o,memo:"Close expense account"}),r-=o)}}return r>0?t.push({accountId:n.retainedEarningsAccountId,debit:0,credit:r,memo:"Retained earnings from period close"}):r<0&&t.push({accountId:n.retainedEarningsAccountId,debit:Math.abs(r),credit:0,memo:"Retained earnings from period close"}),{id:n.journalId,tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,occurredAt:n.occurredAt,reference:n.reference,lines:t}}function Te(n){return Array.isArray(n)?n.length:n&&typeof n=="object"?1:n===null||typeof n>"u"?0:1}function Ne(n){return n==="json"?"application/json":"text/csv"}function Le(n,e){if(n==="json")return`${JSON.stringify(e,null,2)}
2
+ `;if(typeof e!="string")throw new Error("FINANCE_COMPLIANCE_EXPORT_CSV_PAYLOAD_STRING_REQUIRED");return e}function xe(n){let e=2166136261;for(let t=0;t<n.length;t+=1)e^=n.charCodeAt(t),e=Math.imul(e,16777619);return`fnv1a32-${(e>>>0).toString(16).padStart(8,"0")}`}function Me(n){if(!n.key?.trim())throw new Error("FINANCE_COMPLIANCE_EXPORT_DATASET_KEY_REQUIRED");if(!n.fileName?.trim())throw new Error("FINANCE_COMPLIANCE_EXPORT_FILE_NAME_REQUIRED");if(n.format!=="json"&&n.format!=="csv")throw new Error("FINANCE_COMPLIANCE_EXPORT_FORMAT_INVALID")}function Be(n){return n??"custom"}function se(n){if(!Array.isArray(n.datasets)||n.datasets.length===0)throw new Error("FINANCE_COMPLIANCE_EXPORT_DATASETS_REQUIRED");let e=new Set,t={},r=[];for(let o of n.datasets){if(Me(o),e.has(o.key))throw new Error("FINANCE_COMPLIANCE_EXPORT_DATASET_KEY_DUPLICATE");e.add(o.key);let i=Le(o.format,o.payload);t[o.fileName]=i,r.push({key:o.key,fileName:o.fileName,format:o.format,semantic:Be(o.semantic),contentType:o.contentType??Ne(o.format),recordCount:Te(o.payload),checksum:xe(i)})}return{contract:{contractVersion:"fcx-v1",tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,generatedAt:n.generatedAt??new Date().toISOString(),period:{from:n.period?.from??null,to:n.period?.to??null,label:n.period?.label??null},currency:{baseCurrencyCode:n.baseCurrencyCode??"IDR"},datasets:r,summary:{datasetCount:r.length,totalRecordCount:r.reduce((o,i)=>o+i.recordCount,0)}},files:t}}function $n(n){return{version:"v1",generatedAt:n.generatedAt??new Date().toISOString(),payload:{trialBalance:n.trialBalance.map(e=>({...e})),incomeStatement:{...n.incomeStatement},balanceSheet:{...n.balanceSheet}}}}function Gn(n){let e=[{key:"trial-balance",fileName:"trial_balance.json",format:"json",semantic:"trial_balance",payload:n.trialBalance},{key:"income-statement",fileName:"income_statement.json",format:"json",semantic:"income_statement",payload:n.incomeStatement},{key:"balance-sheet",fileName:"balance_sheet.json",format:"json",semantic:"balance_sheet",payload:n.balanceSheet}];return typeof n.openItems<"u"&&e.push({key:"open-items",fileName:"open_items.json",format:"json",semantic:"open_items",payload:n.openItems}),typeof n.agingSummary<"u"&&e.push({key:"aging-summary",fileName:"aging_summary.json",format:"json",semantic:"aging_summary",payload:n.agingSummary}),typeof n.reconciliationSummary<"u"&&e.push({key:"reconciliation-summary",fileName:"reconciliation_summary.json",format:"json",semantic:"reconciliation",payload:n.reconciliationSummary}),typeof n.cashMovements<"u"&&e.push({key:"cash-movements",fileName:"cash_movements.json",format:"json",semantic:"cash_movements",payload:n.cashMovements}),se({tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,generatedAt:n.generatedAt,period:n.period,baseCurrencyCode:n.baseCurrencyCode,datasets:e})}function Je(n){return n.accountType==="revenue"?n.credit-n.debit:n.accountType==="expense"?n.debit-n.credit:0}function de(n,e){return e===0?n===0?1:0:Number((n/e).toFixed(4))}function zn(n,e){let t=e.map(a=>{let c=((a.accountCodes?.length?n.filter(p=>a.accountCodes?.includes(p.accountCode)):null)??n.filter(p=>a.accountType?p.accountType===a.accountType:!1)).reduce((p,f)=>p+Je(f),0),s=c-a.plannedAmount;return{id:a.id,label:a.label,plannedAmount:a.plannedAmount,actualAmount:c,varianceAmount:s,achievementRatio:de(c,a.plannedAmount)}}),r=t.reduce((a,o)=>(a.plannedAmount+=o.plannedAmount,a.actualAmount+=o.actualAmount,a.varianceAmount+=o.varianceAmount,a),{plannedAmount:0,actualAmount:0,varianceAmount:0});return{rows:t,totals:{...r,achievementRatio:de(r.actualAmount,r.plannedAmount)}}}function ke(n,e){switch(e.type){case"finance.account.created":n.createAccount(e.payload);return;case"finance.period.opened":n.openFiscalPeriod(e.payload);return;case"finance.period.closed":n.closeFiscalPeriod(e.payload.periodId);return;case"finance.journal.drafted":n.createJournalDraft(e.payload);return;case"finance.journal.posted":n.postJournal(e.payload.journalId,e.payload.postedAt);return;case"finance.journal.reversed":n.reverseJournal(e.payload.journalId,e.payload.reversalId);return;default:throw new Error("FINANCE_EVENT_UNSUPPORTED")}}function Kn(n){let e=new N;for(let t of n)ke(e,t);return e}var je=[{id:"coa-cash",code:"1101",name:"Kas",type:"asset"},{id:"coa-bank",code:"1102",name:"Bank",type:"asset"},{id:"coa-ar",code:"1201",name:"Piutang Usaha",type:"asset"},{id:"coa-ap",code:"2101",name:"Utang Usaha",type:"liability"},{id:"coa-retained",code:"3201",name:"Laba Ditahan",type:"equity"},{id:"coa-revenue",code:"4101",name:"Pendapatan Operasional",type:"revenue"},{id:"coa-expense",code:"5101",name:"Biaya Operasional",type:"expense"}];function et(n="IDR"){return je.map(e=>({id:e.id,code:e.code,name:e.name,type:e.type,currency:n,isActive:!0}))}var Ue=[{id:"coop-coa-cash",code:"1101",name:"Kas",type:"asset"},{id:"coop-coa-bank",code:"1102",name:"Bank",type:"asset"},{id:"coop-coa-loan-ar",code:"1201",name:"Piutang Pinjaman Anggota",type:"asset"},{id:"coop-coa-other-ar",code:"1202",name:"Piutang Lain-lain",type:"asset"},{id:"coop-coa-prepaid",code:"1301",name:"Biaya Dibayar Dimuka",type:"asset"},{id:"coop-coa-fixed-asset",code:"1401",name:"Aset Tetap",type:"asset"},{id:"coop-coa-accum-depr",code:"1402",name:"Akumulasi Penyusutan",type:"asset"},{id:"coop-coa-simp-pokok",code:"2101",name:"Simpanan Pokok",type:"liability"},{id:"coop-coa-simp-wajib",code:"2102",name:"Simpanan Wajib",type:"liability"},{id:"coop-coa-simp-sukarela",code:"2103",name:"Simpanan Sukarela",type:"liability"},{id:"coop-coa-simp-berjangka",code:"2104",name:"Simpanan Berjangka",type:"liability"},{id:"coop-coa-ap",code:"2201",name:"Utang Usaha",type:"liability"},{id:"coop-coa-ext-loan",code:"2301",name:"Pinjaman Luar",type:"liability"},{id:"coop-coa-tax-payable",code:"2401",name:"Utang Pajak",type:"liability"},{id:"coop-coa-modal-awal",code:"3101",name:"Modal Awal",type:"equity"},{id:"coop-coa-cadangan-umum",code:"3201",name:"Dana Cadangan Umum",type:"equity"},{id:"coop-coa-cadangan-tujuan",code:"3202",name:"Dana Cadangan Tujuan",type:"equity"},{id:"coop-coa-shu-prior",code:"3301",name:"SHU Tahun Lalu",type:"equity"},{id:"coop-coa-shu-current",code:"3302",name:"SHU Berjalan",type:"equity"},{id:"coop-coa-shu-reserve",code:"3303",name:"Dana SHU Belum Dibagi",type:"equity"},{id:"coop-coa-jasa-pinjaman",code:"4101",name:"Pendapatan Jasa Pinjaman",type:"revenue"},{id:"coop-coa-provisi",code:"4102",name:"Pendapatan Provisi",type:"revenue"},{id:"coop-coa-rev-other",code:"4103",name:"Pendapatan Lain-lain",type:"revenue"},{id:"coop-coa-beban-bunga",code:"5101",name:"Beban Bunga Simpanan",type:"expense"},{id:"coop-coa-beban-ops",code:"5102",name:"Beban Operasional",type:"expense"},{id:"coop-coa-beban-gaji",code:"5103",name:"Beban Gaji dan Tunjangan",type:"expense"},{id:"coop-coa-beban-admin",code:"5104",name:"Beban Administrasi",type:"expense"},{id:"coop-coa-beban-depr",code:"5105",name:"Beban Penyusutan",type:"expense"},{id:"coop-coa-prov-kredit",code:"5106",name:"Cadangan Kerugian Piutang",type:"expense"}];function nt(n="IDR"){return Ue.map(e=>({id:e.id,code:e.code,name:e.name,type:e.type,currency:n,isActive:!0}))}function tt(n){let e=new Set,t=new Set;for(let r of n){if(!r.id||!r.code||!r.name)return{ok:!1,reason:"COA_REQUIRED_FIELDS"};if(e.has(r.id))return{ok:!1,reason:"COA_DUPLICATE_ID"};if(t.has(r.code))return{ok:!1,reason:"COA_DUPLICATE_CODE"};e.add(r.id),t.add(r.code)}return{ok:!0}}export{je as CANONICAL_COA_TEMPLATES,Ue as COOP_COA_TEMPLATES,d as OFINANCE_TABLES,N as OffinanceCore,J as OffinanceEnvelopeService,k as OfinanceRuntimeCore,j as OfinanceRuntimeCoreBuilder,ke as applyFinanceDomainEvent,L as applyPendingMigrations,kn as buildBalanceSheet,zn as buildBudgetVsRealization,Un as buildCashflowBaseline,Vn as buildClosingJournalDraft,se as buildFinanceComplianceExportBundle,$n as buildFinanceExportEnvelope,D as buildFinanceOpenItemAging,Gn as buildFinanceOperationalComplianceBundle,Y as buildFinanceTaxPostingLines,Jn as buildIncomeStatement,W as buildJournalFromCoopLoanDisbursement,Z as buildJournalFromCoopLoanRepayment,X as buildJournalFromCoopSavingDeposit,K as buildJournalFromCoopSavingWithdrawal,vn as buildJournalFromCoopShuParticipationManualRecap,z as buildJournalFromPosSale,wn as buildJournalFromScopedCoopLoanDisbursement,Nn as buildJournalFromScopedCoopLoanRepayment,_n as buildJournalFromScopedCoopSavingDeposit,Tn as buildJournalFromScopedCoopSavingWithdrawal,Dn as buildJournalFromScopedPosSale,et as createCanonicalCoA,nt as createCoopCoA,G as createDbAdapterOfinanceServices,Mn as createFinanceProjectionSink,$ as createOffinanceEnvelopeService,I as mapOffinanceErrorToEnvelope,_ as projectFinanceCashBankMovements,F as projectFinanceOpenItems,w as reconcileFinanceOpenItems,Kn as replayFinanceDomainEvents,te as resolveCoopLoanDisbursementAccountMapping,re as resolveCoopLoanRepaymentAccountMapping,ae as resolveCoopSavingDepositAccountMapping,oe as resolveCoopSavingWithdrawalAccountMapping,ne as resolvePosSaleAccountMapping,v as resolveScopedAccountMapping,T as summarizeFinanceCashBankMovements,q as toOffinanceFailureEnvelope,m as toOffinanceSuccessEnvelope,tt as validateCoaIntegrity,P as validateJournalBalance,O as validateOpenItemLineMetadata};
2
3
  /*! For license information please see index.esm.js.LEGAL.txt */
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
- "use strict";var x=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var se=Object.getOwnPropertyNames;var de=Object.prototype.hasOwnProperty;var ue=(r,e)=>{for(var t in e)x(r,t,{get:e[t],enumerable:!0})},le=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of se(e))!de.call(r,a)&&a!==t&&x(r,a,{get:()=>e[a],enumerable:!(n=ce(e,a))||n.enumerable});return r};var pe=r=>le(x({},"__esModule",{value:!0}),r);var Be={};ue(Be,{CANONICAL_COA_TEMPLATES:()=>oe,COOP_COA_TEMPLATES:()=>ie,OFINANCE_TABLES:()=>c,OffinanceCore:()=>D,OffinanceEnvelopeService:()=>F,OfinanceRuntimeCore:()=>_,OfinanceRuntimeCoreBuilder:()=>T,applyFinanceDomainEvent:()=>ae,applyPendingMigrations:()=>R,buildBalanceSheet:()=>we,buildBudgetVsRealization:()=>Le,buildCashflowBaseline:()=>Fe,buildClosingJournalDraft:()=>Oe,buildFinanceExportEnvelope:()=>_e,buildIncomeStatement:()=>Re,buildJournalFromCoopLoanDisbursement:()=>V,buildJournalFromCoopLoanRepayment:()=>q,buildJournalFromCoopSavingDeposit:()=>k,buildJournalFromCoopSavingWithdrawal:()=>H,buildJournalFromCoopShuParticipationManualRecap:()=>be,buildJournalFromPosSale:()=>j,buildJournalFromScopedCoopLoanDisbursement:()=>ye,buildJournalFromScopedCoopLoanRepayment:()=>Pe,buildJournalFromScopedCoopSavingDeposit:()=>he,buildJournalFromScopedCoopSavingWithdrawal:()=>Se,buildJournalFromScopedPosSale:()=>Ae,createCanonicalCoA:()=>xe,createCoopCoA:()=>Je,createDbAdapterOfinanceServices:()=>U,createFinanceProjectionSink:()=>Ee,createOffinanceEnvelopeService:()=>B,mapOffinanceErrorToEnvelope:()=>p,replayFinanceDomainEvents:()=>Ne,resolveCoopLoanDisbursementAccountMapping:()=>Q,resolveCoopLoanRepaymentAccountMapping:()=>W,resolveCoopSavingDepositAccountMapping:()=>Y,resolveCoopSavingWithdrawalAccountMapping:()=>G,resolvePosSaleAccountMapping:()=>$,resolveScopedAccountMapping:()=>S,toOffinanceFailureEnvelope:()=>M,toOffinanceSuccessEnvelope:()=>l,validateCoaIntegrity:()=>Me,validateJournalBalance:()=>E});module.exports=pe(Be);function E(r){if(!Array.isArray(r)||r.length===0)return{ok:!1,totalDebit:0,totalCredit:0,reason:"JOURNAL_LINES_EMPTY"};let e=0,t=0;for(let n of r){if(!n||!n.accountId)return{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_ACCOUNT_REQUIRED"};if(n.debit<0||n.credit<0)return{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_NEGATIVE_AMOUNT"};e+=n.debit,t+=n.credit}return Math.abs(e-t)>1e-6?{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_NOT_BALANCED"}:{ok:!0,totalDebit:e,totalCredit:t}}var D=class{constructor(e){this.state={accounts:e?.accounts??new Map,periods:e?.periods??new Map,journals:e?.journals??new Map,balances:e?.balances??new Map,rapbPlans:e?.rapbPlans??new Map}}createAccount(e){if(!e.id||!e.code||!e.name)throw new Error("FINANCE_ACCOUNT_REQUIRED_FIELDS");if(this.state.accounts.has(e.id))throw new Error("FINANCE_ACCOUNT_ALREADY_EXISTS");if(Array.from(this.state.accounts.values()).some(n=>n.code===e.code))throw new Error("FINANCE_ACCOUNT_CODE_DUPLICATE");return this.state.accounts.set(e.id,{...e}),{...e}}listAccounts(){return Array.from(this.state.accounts.values()).map(e=>({...e})).sort((e,t)=>e.code.localeCompare(t.code))}openFiscalPeriod(e){if(!e.id||!e.tenantId||!e.code||!e.startDate||!e.endDate)throw new Error("FISCAL_PERIOD_REQUIRED_FIELDS");if(this.state.periods.has(e.id))throw new Error("FISCAL_PERIOD_ALREADY_EXISTS");if(Date.parse(e.startDate)>Date.parse(e.endDate))throw new Error("FISCAL_PERIOD_INVALID_RANGE");let t={...e,status:"open"};return this.state.periods.set(t.id,t),{...t}}closeFiscalPeriod(e){let t=this.state.periods.get(e);if(!t)throw new Error("FISCAL_PERIOD_NOT_FOUND");let n={...t,status:"closed"};return this.state.periods.set(e,n),{...n}}listFiscalPeriods(){return Array.from(this.state.periods.values()).map(e=>({...e})).sort((e,t)=>e.startDate.localeCompare(t.startDate))}createJournalDraft(e){if(!e.id||!e.tenantId||!e.occurredAt)throw new Error("JOURNAL_REQUIRED_FIELDS");if(this.state.journals.has(e.id))throw new Error("JOURNAL_ALREADY_EXISTS");this.assertJournalLinesKnownAccounts(e.lines),this.assertJournalPeriodOpen(e.occurredAt);let t=E(e.lines);if(!t.ok)throw new Error(t.reason??"JOURNAL_INVALID");let n={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,lines:e.lines.map(a=>({...a})),status:"draft"};return this.state.journals.set(n.id,n),{...n,lines:n.lines.map(a=>({...a}))}}postJournal(e,t=new Date().toISOString()){let n=this.state.journals.get(e);if(!n)throw new Error("JOURNAL_NOT_FOUND");if(n.status==="posted"||n.status==="reversed")return{...n,lines:n.lines.map(o=>({...o}))};this.applyLinesToBalance(n.lines);let a={...n,status:"posted",postedAt:t};return this.state.journals.set(e,a),{...a,lines:a.lines.map(o=>({...o}))}}reverseJournal(e,t){let n=this.state.journals.get(e);if(!n)throw new Error("JOURNAL_NOT_FOUND");if(n.status!=="posted")throw new Error("JOURNAL_NOT_POSTED");if(this.state.journals.has(t))throw new Error("JOURNAL_ALREADY_EXISTS");let a=n.lines.map(i=>({accountId:i.accountId,debit:i.credit,credit:i.debit,memo:i.memo})),o=this.createJournalDraft({id:t,tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,occurredAt:n.occurredAt,reference:`reversal:${n.id}`,lines:a});return this.postJournal(o.id)}getTrialBalance(){return this.getTrialBalanceByScope()}getTrialBalanceByScope(e){let t=this.computeScopedBalances(e);return this.listAccounts().map(a=>{let o=t.get(a.id)??{debit:0,credit:0};return{accountId:a.id,accountCode:a.code,accountName:a.name,accountType:a.type,debit:o.debit,credit:o.credit,net:o.debit-o.credit}})}listJournals(e){return Array.from(this.state.journals.values()).filter(t=>this.matchesScope(t,e)).map(t=>({...t,lines:t.lines.map(n=>({...n}))})).sort((t,n)=>t.occurredAt.localeCompare(n.occurredAt))}assertJournalLinesKnownAccounts(e){for(let t of e)if(!this.state.accounts.has(t.accountId))throw new Error("JOURNAL_ACCOUNT_NOT_FOUND")}assertJournalPeriodOpen(e){if(this.state.periods.size===0)return;let t=this.findPeriodByDate(e);if(!t)throw new Error("FISCAL_PERIOD_NOT_FOUND_FOR_DATE");if(t.status!=="open")throw new Error("FISCAL_PERIOD_CLOSED")}findPeriodByDate(e){let t=Date.parse(e);for(let n of this.state.periods.values()){let a=Date.parse(n.startDate),o=Date.parse(n.endDate);if(t>=a&&t<=o)return n}return null}applyLinesToBalance(e){for(let t of e){let n=this.state.balances.get(t.accountId)??{debit:0,credit:0};n.debit+=t.debit,n.credit+=t.credit,this.state.balances.set(t.accountId,n)}}computeScopedBalances(e){if(!e||!e.tenantId&&!e.branchId&&!e.financeDomainId&&!e.ledgerProfileId&&!e.occurredFrom&&!e.occurredTo)return this.state.balances;let t=new Map;for(let n of this.state.journals.values())if(n.status==="posted"&&this.matchesScope(n,e))for(let a of n.lines){let o=t.get(a.accountId)??{debit:0,credit:0};o.debit+=a.debit,o.credit+=a.credit,t.set(a.accountId,o)}return t}matchesScope(e,t){return t?!(t.tenantId&&e.tenantId!==t.tenantId||t.branchId&&e.branchId!==t.branchId||t.financeDomainId&&e.financeDomainId!==t.financeDomainId||t.ledgerProfileId&&e.ledgerProfileId!==t.ledgerProfileId||t.occurredFrom&&e.occurredAt<t.occurredFrom||t.occurredTo&&e.occurredAt>t.occurredTo):!0}createRapb(e){if(!e.id||!e.tenantId||!e.periodCode||!e.title)throw new Error("RAPB_REQUIRED_FIELDS");if(!e.lines||e.lines.length===0)throw new Error("RAPB_LINES_REQUIRED");if(this.state.rapbPlans.has(e.id))throw new Error("RAPB_ALREADY_EXISTS");if(e.lines.some(a=>a.budgetedDebit<0||a.budgetedCredit<0))throw new Error("RAPB_NEGATIVE_AMOUNT");let t=e.lines.map(a=>{let o=this.state.accounts.get(a.accountId);if(!o)throw new Error(`RAPB_ACCOUNT_NOT_FOUND:${a.accountId}`);let i=a.budgetedDebit-a.budgetedCredit;return{accountId:a.accountId,accountCode:o.code,accountName:o.name,accountType:o.type,budgetedDebit:a.budgetedDebit,budgetedCredit:a.budgetedCredit,budgetedNet:i}}),n={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,periodCode:e.periodCode,title:e.title,status:"draft",lines:t,notes:e.notes,createdAt:new Date().toISOString()};return this.state.rapbPlans.set(n.id,n),n}getRapb(e){return this.state.rapbPlans.get(e)??null}listRapb(e){let t=Array.from(this.state.rapbPlans.values());return e&&(e.tenantId&&(t=t.filter(n=>n.tenantId===e.tenantId)),e.periodCode&&(t=t.filter(n=>n.periodCode===e.periodCode)),e.branchId&&(t=t.filter(n=>n.branchId===e.branchId)),e.financeDomainId&&(t=t.filter(n=>n.financeDomainId===e.financeDomainId)),e.ledgerProfileId&&(t=t.filter(n=>n.ledgerProfileId===e.ledgerProfileId))),t}approveRapb(e,t){let n=this.state.rapbPlans.get(e);if(!n)throw new Error("RAPB_NOT_FOUND");let a=typeof t=="string"?t:t.approvedBy;if(n.status==="approved")throw new Error("RAPB_ALREADY_APPROVED");let o={...n,status:"approved",approvedAt:new Date().toISOString(),approvedBy:a};return this.state.rapbPlans.set(e,o),o}evaluateVariance(e){let t=this.state.rapbPlans.get(e);if(!t)throw new Error("RAPB_NOT_FOUND");let n=this.getTrialBalance(),a=new Map(n.map(d=>[d.accountId,d])),o=0,i=0,s=0,u=0,I=t.lines.map(d=>{let v=a.get(d.accountId),m=v?.debit??0,f=v?.credit??0,C=m-f;return d.accountType==="revenue"?(o+=d.budgetedCredit-d.budgetedDebit,i+=f-m):d.accountType==="expense"&&(s+=d.budgetedDebit-d.budgetedCredit,u+=m-f),{accountId:d.accountId,accountCode:d.accountCode,accountName:d.accountName,accountType:d.accountType,budgetedDebit:d.budgetedDebit,budgetedCredit:d.budgetedCredit,budgetedNet:d.budgetedNet,actualDebit:m,actualCredit:f,actualNet:C,varianceDebit:m-d.budgetedDebit,varianceCredit:f-d.budgetedCredit,varianceNet:C-d.budgetedNet}}),A=o-s,P=i-u;return{rapbId:e,periodCode:t.periodCode,evaluatedAt:new Date().toISOString(),lines:I,totalBudgetedRevenue:o,totalActualRevenue:i,totalBudgetedExpense:s,totalActualExpense:u,budgetedNetIncome:A,actualNetIncome:P,netVariance:P-A}}};var z=require("ofcore"),Z=require("ofcore"),L=require("ofcore");var c={accounts:"ofinance_accounts",periods:"ofinance_periods",journals:"ofinance_journals",journalLines:"ofinance_journal_lines",rapbPlans:"ofinance_rapb_plans",rapbLines:"ofinance_rapb_lines",histories:"ofinance_histories"},me=[{name:c.accounts,columns:[{name:"id",type:"string"},{name:"code",type:"string",isIndexed:!0},{name:"name",type:"string"},{name:"type",type:"string",isIndexed:!0},{name:"currency",type:"string"},{name:"isActive",type:"boolean",isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.periods,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"code",type:"string",isIndexed:!0},{name:"startDate",type:"string",isIndexed:!0},{name:"endDate",type:"string",isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.journals,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"occurredAt",type:"string",isIndexed:!0},{name:"reference",type:"string",isOptional:!0,isIndexed:!0},{name:"evidenceRef",type:"string",isOptional:!0,isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"postedAt",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.journalLines,columns:[{name:"id",type:"string"},{name:"journalId",type:"string",isIndexed:!0},{name:"accountId",type:"string",isIndexed:!0},{name:"debit",type:"number"},{name:"credit",type:"number"},{name:"memo",type:"string",isOptional:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.rapbPlans,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"periodCode",type:"string",isIndexed:!0},{name:"title",type:"string",isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"notes",type:"string",isOptional:!0},{name:"createdAt",type:"string",isIndexed:!0},{name:"approvedAt",type:"string",isOptional:!0,isIndexed:!0},{name:"approvedBy",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.rapbLines,columns:[{name:"id",type:"string"},{name:"rapbId",type:"string",isIndexed:!0},{name:"accountId",type:"string",isIndexed:!0},{name:"accountCode",type:"string",isIndexed:!0},{name:"accountName",type:"string"},{name:"accountType",type:"string",isIndexed:!0},{name:"budgetedDebit",type:"number"},{name:"budgetedCredit",type:"number"},{name:"budgetedNet",type:"number"},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:c.histories,columns:[{name:"id",type:"string"},{name:"tableName",type:"string",isIndexed:!0},{name:"recordId",type:"string",isIndexed:!0},{name:"action",type:"string",isIndexed:!0},{name:"changes",type:"json",isOptional:!0},{name:"timestamp",type:"string",isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0}]}];function J(){return me.map(r=>({...r,columns:r.columns.map(e=>({...e}))}))}var K=[{toVersion:1,up:async r=>{let e=J();for(let t of e)try{await r.addTable(t)}catch{}}},{toVersion:2,up:async r=>{let e=J().filter(t=>t.name==="ofinance_rapb_plans"||t.name==="ofinance_rapb_lines");for(let t of e)try{await r.addTable(t)}catch{}}},{toVersion:3,up:async r=>{try{await r.addColumn("ofinance_journals",{name:"evidenceRef",type:"string",isOptional:!0,isIndexed:!0})}catch{}}}];var fe={logInfo(){},logWarn(){},logError(){}};async function R(r,e=fe){e.logInfo("[offinance] starting database migration process");let t=[...K].sort((o,i)=>o.toVersion-i.toVersion),n=t.length>0?t[t.length-1].toVersion:0,a=await r.getSchemaVersion();if((a==null||a<0)&&(a=0),a>=n){e.logInfo(`[offinance] database already up-to-date at v${a}`);return}for(let o of t)o.toVersion>a&&(e.logInfo(`[offinance] applying migration v${o.toVersion}`),await o.up(r),await r.setSchemaVersion(o.toVersion),a=o.toVersion);e.logInfo(`[offinance] migration completed at v${a}`)}function l(r,e){return{data:r,meta:{request_id:e??null,timestamp:new Date().toISOString()}}}function M(r,e,t={}){return{error:{code:r,message:e,details:t.details,retryable:t.retryable,correlationId:t.correlationId,timestamp:new Date().toISOString()},meta:{request_id:t.requestId??null,timestamp:new Date().toISOString()}}}function p(r,e="FINANCE_NOT_IMPLEMENTED",t="Unhandled offinance error."){return r instanceof Error?M(e,r.message||t):M(e,t)}var F=class{constructor(e){this.legacy=e;this.accountService={createAccount:async t=>{try{return l(await this.legacy.accountService.createAccount(t))}catch(n){return p(n)}},listAccounts:async()=>{try{return l(await this.legacy.accountService.listAccounts())}catch(t){return p(t)}}},this.journalService={createJournalDraft:async t=>{try{return l(await this.legacy.journalService.createJournalDraft(t))}catch(n){return p(n)}},postJournal:async(t,n)=>{try{return l(await this.legacy.journalService.postJournal(t,n))}catch(a){return p(a)}},reverseJournal:async(t,n)=>{try{return l(await this.legacy.journalService.reverseJournal(t,n))}catch(a){return p(a)}},listJournals:async t=>{try{return l(await this.legacy.journalService.listJournals(t))}catch(n){return p(n)}}},this.fiscalService={openFiscalPeriod:async t=>{try{return l(await this.legacy.fiscalService.openFiscalPeriod(t))}catch(n){return p(n)}},closeFiscalPeriod:async t=>{try{return l(await this.legacy.fiscalService.closeFiscalPeriod(t))}catch(n){return p(n)}},listFiscalPeriods:async()=>{try{return l(await this.legacy.fiscalService.listFiscalPeriods())}catch(t){return p(t)}},getTrialBalance:async()=>{try{return l(await this.legacy.fiscalService.getTrialBalance())}catch(t){return p(t)}},getTrialBalanceByScope:async t=>{try{return l(await this.legacy.fiscalService.getTrialBalanceByScope(t))}catch(n){return p(n)}}},this.rapbService={createRapb:async t=>{try{return l(await this.legacy.rapbService.createRapb(t))}catch(n){return p(n)}},getRapb:async t=>{try{return l(await this.legacy.rapbService.getRapb(t))}catch(n){return p(n)}},listRapb:async t=>{try{return l(await this.legacy.rapbService.listRapb(t))}catch(n){return p(n)}},approveRapb:async(t,n)=>{try{return l(await this.legacy.rapbService.approveRapb(t,n))}catch(a){return p(a)}},evaluateVariance:async t=>{try{return l(await this.legacy.rapbService.evaluateVariance(t))}catch(n){return p(n)}}}}};function B(r){return new F({accountService:r,journalService:r,fiscalService:r,rapbService:r})}function b(r){return JSON.parse(JSON.stringify(r))}function g(){return new Date().toISOString()}function ge(r,e){return`${r}:${e}:${Date.now()}:${Math.random().toString(36).slice(2,8)}`}function Ie(r,e){return!r||r.deleted?!1:e?!(e.tenantId&&r.tenantId!==e.tenantId||e.branchId&&r.branchId!==e.branchId||e.financeDomainId&&r.financeDomainId!==e.financeDomainId||e.ledgerProfileId&&r.ledgerProfileId!==e.ledgerProfileId||e.occurredFrom&&r.occurredAt&&r.occurredAt<e.occurredFrom||e.occurredTo&&r.occurredAt&&r.occurredAt>e.occurredTo):!0}var O=class{constructor(e){this.dbAdapter=e}async createAccount(e){if(!e.id||!e.code||!e.name)throw new Error("FINANCE_ACCOUNT_REQUIRED_FIELDS");let t=await this.dbAdapter.get(c.accounts,e.id);if(t&&!t.deleted)throw new Error("FINANCE_ACCOUNT_ALREADY_EXISTS");if((await this.dbAdapter.query(c.accounts,{filters:{and:[{field:"code",value:e.code},{field:"deleted",value:!1}]}})).some(i=>i.id!==e.id))throw new Error("FINANCE_ACCOUNT_CODE_DUPLICATE");let a=g(),o={...b(e),lastModified:a,deleted:!1};return t?await this.dbAdapter.update(c.accounts,e.id,o):await this.dbAdapter.create(c.accounts,o),await this.writeHistory("accounts",e.id,"UPSERT",o),b(e)}async listAccounts(){return(await this.dbAdapter.query(c.accounts,{filters:{field:"deleted",value:!1}})).map(({lastModified:t,deleted:n,...a})=>b(a)).sort((t,n)=>t.code.localeCompare(n.code))}async createJournalDraft(e){if(!e.id||!e.tenantId||!e.occurredAt)throw new Error("JOURNAL_REQUIRED_FIELDS");if(!e.ledgerProfileId)throw new Error("JOURNAL_REQUIRED_FIELDS");let t=await this.dbAdapter.get(c.journals,e.id);if(t&&!t.deleted)throw new Error("JOURNAL_ALREADY_EXISTS");await this.assertJournalLinesKnownAccounts(e.lines),await this.assertJournalPeriodOpen(e);let n=E(e.lines);if(!n.ok)throw new Error(n.reason??"JOURNAL_INVALID");let a=g(),o={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,evidenceRef:e.evidenceRef,status:"draft",postedAt:void 0,lastModified:a,deleted:!1};await this.dbAdapter.create(c.journals,o);for(let i=0;i<e.lines.length;i+=1){let s=e.lines[i],u={id:`${e.id}:line:${i}`,journalId:e.id,accountId:s.accountId,debit:s.debit,credit:s.credit,memo:s.memo,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:a,deleted:!1};await this.dbAdapter.create(c.journalLines,u),await this.writeHistory("journal_lines",u.id,"UPSERT",u)}return await this.writeHistory("journals",e.id,"UPSERT",o),this.toJournalEntry(o,e.lines)}async postJournal(e,t=g()){let n=await this.requireJournal(e),a=await this.listJournalLines(e);if(n.status==="posted"||n.status==="reversed")return this.toJournalEntry(n,a);let o={...n,status:"posted",postedAt:t,lastModified:g()};return await this.dbAdapter.update(c.journals,e,o),await this.writeHistory("journals",e,"UPSERT",o),this.toJournalEntry(o,a)}async reverseJournal(e,t){let n=await this.requireJournal(e);if(n.status!=="posted")throw new Error("JOURNAL_NOT_POSTED");let a=await this.listJournalLines(e),o=await this.createJournalDraft({id:t,tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,occurredAt:n.occurredAt,reference:`reversal:${n.id}`,evidenceRef:n.evidenceRef,lines:a.map(i=>({accountId:i.accountId,debit:i.credit,credit:i.debit,memo:i.memo}))});return this.postJournal(o.id)}async listJournals(e){let n=(await this.dbAdapter.query(c.journals,{filters:{field:"deleted",value:!1}})).filter(o=>Ie(o,e)).sort((o,i)=>o.occurredAt.localeCompare(i.occurredAt)),a=[];for(let o of n){let i=await this.listJournalLines(o.id);a.push(this.toJournalEntry(o,i))}return a}async openFiscalPeriod(e){if(!e.id||!e.tenantId||!e.code||!e.startDate||!e.endDate)throw new Error("FISCAL_PERIOD_REQUIRED_FIELDS");if(Date.parse(e.startDate)>Date.parse(e.endDate))throw new Error("FISCAL_PERIOD_INVALID_RANGE");let t=await this.dbAdapter.get(c.periods,e.id);if(t&&!t.deleted)throw new Error("FISCAL_PERIOD_ALREADY_EXISTS");let n=g(),a={...b(e),status:"open",lastModified:n,deleted:!1};return t?await this.dbAdapter.update(c.periods,e.id,a):await this.dbAdapter.create(c.periods,a),await this.writeHistory("periods",e.id,"UPSERT",a),this.toPeriod(a)}async closeFiscalPeriod(e){let t=await this.dbAdapter.get(c.periods,e);if(!t||t.deleted)throw new Error("FISCAL_PERIOD_NOT_FOUND");let n={...t,status:"closed",lastModified:g()};return await this.dbAdapter.update(c.periods,e,n),await this.writeHistory("periods",e,"UPSERT",n),this.toPeriod(n)}async listFiscalPeriods(){return(await this.dbAdapter.query(c.periods,{filters:{field:"deleted",value:!1}})).map(t=>this.toPeriod(t)).sort((t,n)=>t.startDate.localeCompare(n.startDate))}async getTrialBalance(){return this.getTrialBalanceByScope()}async getTrialBalanceByScope(e){let t=await this.listAccounts(),a=(await this.listJournals(e)).filter(i=>i.status==="posted"),o=new Map;for(let i of a)for(let s of i.lines){let u=o.get(s.accountId)??{debit:0,credit:0};u.debit+=Number(s.debit||0),u.credit+=Number(s.credit||0),o.set(s.accountId,u)}return t.map(i=>{let s=o.get(i.id)??{debit:0,credit:0};return{accountId:i.id,accountCode:i.code,accountName:i.name,accountType:i.type,debit:s.debit,credit:s.credit,net:s.debit-s.credit}})}async createRapb(e){if(!e.id||!e.tenantId||!e.periodCode||!e.title)throw new Error("RAPB_REQUIRED_FIELDS");if(!e.lines||e.lines.length===0)throw new Error("RAPB_LINES_REQUIRED");if(e.lines.some(i=>i.budgetedDebit<0||i.budgetedCredit<0))throw new Error("RAPB_NEGATIVE_AMOUNT");let t=await this.dbAdapter.get(c.rapbPlans,e.id);if(t&&!t.deleted)throw new Error("RAPB_ALREADY_EXISTS");let n=g(),a=[];for(let i=0;i<e.lines.length;i+=1){let s=e.lines[i],u=await this.dbAdapter.get(c.accounts,s.accountId);if(!u||u.deleted)throw new Error(`RAPB_ACCOUNT_NOT_FOUND:${s.accountId}`);a.push({id:`${e.id}:line:${i}`,rapbId:e.id,accountId:s.accountId,accountCode:u.code,accountName:u.name,accountType:u.type,budgetedDebit:s.budgetedDebit,budgetedCredit:s.budgetedCredit,budgetedNet:s.budgetedDebit-s.budgetedCredit,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:n,deleted:!1})}let o={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,periodCode:e.periodCode,title:e.title,status:"draft",notes:e.notes,createdAt:n,approvedAt:void 0,approvedBy:void 0,lastModified:n,deleted:!1};await this.dbAdapter.create(c.rapbPlans,o),await this.writeHistory("rapb_plans",e.id,"UPSERT",o);for(let i of a)await this.dbAdapter.create(c.rapbLines,i),await this.writeHistory("rapb_lines",i.id,"UPSERT",i);return this.toRapbPlan(o,a)}async getRapb(e){let t=await this.dbAdapter.get(c.rapbPlans,e);if(!t||t.deleted)return null;let n=await this.listRapbLines(e);return this.toRapbPlan(t,n)}async listRapb(e){let n=await this.dbAdapter.query(c.rapbPlans,{filters:{field:"deleted",value:!1}});e&&(e.tenantId&&(n=n.filter(o=>o.tenantId===e.tenantId)),e.periodCode&&(n=n.filter(o=>o.periodCode===e.periodCode)),e.branchId&&(n=n.filter(o=>o.branchId===e.branchId)),e.financeDomainId&&(n=n.filter(o=>o.financeDomainId===e.financeDomainId)),e.ledgerProfileId&&(n=n.filter(o=>o.ledgerProfileId===e.ledgerProfileId)));let a=[];for(let o of n.sort((i,s)=>i.createdAt.localeCompare(s.createdAt))){let i=await this.listRapbLines(o.id);a.push(this.toRapbPlan(o,i))}return a}async approveRapb(e,t){let n=await this.dbAdapter.get(c.rapbPlans,e);if(!n||n.deleted)throw new Error("RAPB_NOT_FOUND");if(n.status==="approved")throw new Error("RAPB_ALREADY_APPROVED");let a=typeof t=="string"?t:t.approvedBy,o={...n,status:"approved",approvedAt:g(),approvedBy:a,lastModified:g()};await this.dbAdapter.update(c.rapbPlans,e,o),await this.writeHistory("rapb_plans",e,"UPSERT",o);let i=await this.listRapbLines(e);return this.toRapbPlan(o,i)}async evaluateVariance(e){let t=await this.getRapb(e);if(!t)throw new Error("RAPB_NOT_FOUND");let n=await this.getTrialBalanceByScope({tenantId:t.tenantId,branchId:t.branchId,financeDomainId:t.financeDomainId,ledgerProfileId:t.ledgerProfileId}),a=new Map(n.map(d=>[d.accountId,d])),o=0,i=0,s=0,u=0,I=t.lines.map(d=>{let v=a.get(d.accountId),m=v?.debit??0,f=v?.credit??0,C=m-f;return d.accountType==="revenue"?(o+=d.budgetedCredit-d.budgetedDebit,i+=f-m):d.accountType==="expense"&&(s+=d.budgetedDebit-d.budgetedCredit,u+=m-f),{accountId:d.accountId,accountCode:d.accountCode,accountName:d.accountName,accountType:d.accountType,budgetedDebit:d.budgetedDebit,budgetedCredit:d.budgetedCredit,budgetedNet:d.budgetedNet,actualDebit:m,actualCredit:f,actualNet:C,varianceDebit:m-d.budgetedDebit,varianceCredit:f-d.budgetedCredit,varianceNet:C-d.budgetedNet}}),A=o-s,P=i-u;return{rapbId:e,periodCode:t.periodCode,evaluatedAt:g(),lines:I,totalBudgetedRevenue:o,totalActualRevenue:i,totalBudgetedExpense:s,totalActualExpense:u,budgetedNetIncome:A,actualNetIncome:P,netVariance:P-A}}async assertJournalLinesKnownAccounts(e){for(let t of e){let n=await this.dbAdapter.get(c.accounts,t.accountId);if(!n||n.deleted)throw new Error("JOURNAL_ACCOUNT_NOT_FOUND")}}async assertJournalPeriodOpen(e){let t=await this.dbAdapter.query(c.periods,{filters:{field:"deleted",value:!1}});if(t.length===0)return;let n=t.find(a=>!(a.tenantId!==e.tenantId||Date.parse(a.startDate)>Date.parse(e.occurredAt)||Date.parse(a.endDate)<Date.parse(e.occurredAt)||e.ledgerProfileId&&a.ledgerProfileId&&a.ledgerProfileId!==e.ledgerProfileId||e.financeDomainId&&a.financeDomainId&&a.financeDomainId!==e.financeDomainId));if(!n)throw new Error("FISCAL_PERIOD_NOT_FOUND_FOR_DATE");if(n.status!=="open")throw new Error("FISCAL_PERIOD_CLOSED")}async requireJournal(e){let t=await this.dbAdapter.get(c.journals,e);if(!t||t.deleted)throw new Error("JOURNAL_NOT_FOUND");return t}async listJournalLines(e){return(await this.dbAdapter.query(c.journalLines,{filters:{and:[{field:"journalId",value:e},{field:"deleted",value:!1}]}})).sort((n,a)=>n.id.localeCompare(a.id))}async listRapbLines(e){return(await this.dbAdapter.query(c.rapbLines,{filters:{and:[{field:"rapbId",value:e},{field:"deleted",value:!1}]}})).sort((n,a)=>n.id.localeCompare(a.id))}toJournalEntry(e,t){let{lastModified:n,deleted:a,...o}=e;return{...b(o),lines:t.map(i=>b(i))}}toPeriod(e){let{lastModified:t,deleted:n,...a}=e;return b(a)}toRapbPlan(e,t){let{lastModified:n,deleted:a,...o}=e;return{...b(o),lines:t.map(({id:i,rapbId:s,lastModified:u,deleted:I,...A})=>b(A))}}async writeHistory(e,t,n,a){let o=a,i={id:ge(e,t),tableName:e,recordId:t,action:n,changes:b(o),timestamp:g(),tenantId:typeof o.tenantId=="string"?o.tenantId:void 0,branchId:typeof o.branchId=="string"?o.branchId:void 0,financeDomainId:typeof o.financeDomainId=="string"?o.financeDomainId:void 0,ledgerProfileId:typeof o.ledgerProfileId=="string"?o.ledgerProfileId:void 0};await this.dbAdapter.create(c.histories,i)}};async function U(r){await R(r);let e=new O(r);return{financeService:B({createAccount:e.createAccount.bind(e),listAccounts:e.listAccounts.bind(e),createJournalDraft:e.createJournalDraft.bind(e),postJournal:e.postJournal.bind(e),reverseJournal:e.reverseJournal.bind(e),listJournals:e.listJournals.bind(e),openFiscalPeriod:e.openFiscalPeriod.bind(e),closeFiscalPeriod:e.closeFiscalPeriod.bind(e),listFiscalPeriods:e.listFiscalPeriods.bind(e),getTrialBalance:e.getTrialBalance.bind(e),getTrialBalanceByScope:e.getTrialBalanceByScope.bind(e),createRapb:e.createRapb.bind(e),getRapb:e.getRapb.bind(e),listRapb:e.listRapb.bind(e),approveRapb:e.approveRapb.bind(e),evaluateVariance:e.evaluateVariance.bind(e)})}}var _=class{constructor(e,t){this.runtime=e;this.runtimeStateStore=t;this.runtimeStore=(0,L.asReadonlyStore)(this.runtimeStateStore)}static builder(){return new T}get registry(){return this.runtime.registry}async start(e={}){this.runtimeStateStore.setState({phase:"starting",started:!1,lastError:null,lastTransitionAt:new Date().toISOString(),startCount:this.runtimeStateStore.getState().startCount,stopCount:this.runtimeStateStore.getState().stopCount});try{await this.runtime.start(e),this.domainServices=this.runtime.domainServices,this.runtimeStateStore.setState(t=>({...t,phase:"started",started:!0,startCount:t.startCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(t){throw this.runtimeStateStore.setState(n=>({...n,phase:"error",started:!1,lastError:t instanceof Error?t.message:String(t),lastTransitionAt:new Date().toISOString()})),t}}async stop(){this.runtimeStateStore.setState(e=>({...e,phase:"stopping",started:this.runtime.isStarted(),lastError:null,lastTransitionAt:new Date().toISOString()}));try{await this.runtime.stop(),this.runtimeStateStore.setState(e=>({...e,phase:"stopped",started:!1,stopCount:e.stopCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(e){throw this.runtimeStateStore.setState(t=>({...t,phase:"error",started:this.runtime.isStarted(),lastError:e instanceof Error?e.message:String(e),lastTransitionAt:new Date().toISOString()})),e}}isStarted(){return this.runtime.isStarted()}},T=class{constructor(){this.runtimeBuilder=z.CoreRuntime.builder();this.runtimeHooks={};this.runtimeBuilder.withDbAdapter(()=>new Z.InMemoryDbAdapter)}withPlatformAdapter(e){return this.runtimeBuilder.withPlatformAdapter(e),this}withDbAdapter(e){return this.runtimeBuilder.withDbAdapter(e),this}withHttpAdapter(e){return this.runtimeBuilder.withHttpAdapter(e),this}withSocketAdapter(e){return this.runtimeBuilder.withSocketAdapter(e),this}withLoggerAdapter(e){return this.runtimeBuilder.withLoggerAdapter(e),this}withActivitySink(e){return this.runtimeBuilder.withActivitySink(e),this}withExtension(e,t){return this.runtimeBuilder.withExtension(e,t),this}withDomainServicesFactory(e){return this.domainServicesFactory=e,this}withRuntimeHooks(e){return this.runtimeHooks={...this.runtimeHooks,...e},this}build(){let e=(0,L.createStore)({phase:"idle",started:!1,startCount:0,stopCount:0,lastError:null,lastTransitionAt:new Date().toISOString()}),t={runMigrations:async a=>{let o=a.registry?.dbAdapter;if(!o)throw new Error("OFINANCE_DB_ADAPTER_REQUIRED");await R(o,a.registry?.loggerAdapter),this.runtimeHooks.runMigrations&&await this.runtimeHooks.runMigrations(a)},...this.runtimeHooks,createDomainServices:async a=>{if(this.domainServicesFactory)return this.domainServicesFactory();let o=a.registry?.dbAdapter;if(!o)throw new Error("OFINANCE_DB_ADAPTER_REQUIRED");return U(o)}};this.runtimeBuilder.withHooks(t);let n=this.runtimeBuilder.build();return new _(n,e)}};function y(r,e,t){return{id:r.journalId,tenantId:r.tenantId,branchId:r.branchId,financeDomainId:r.financeDomainId,ledgerProfileId:r.ledgerProfileId,occurredAt:r.occurredAt,reference:t?`${r.reference??""}${t}`:r.reference,evidenceRef:r.evidenceRef,lines:e}}function h(r,e){if(!Number.isFinite(r)||r<=0)throw new Error(e)}function j(r,e){h(e.grossAmount,"POS_SALE_INVALID_GROSS_AMOUNT");let t=e.discountAmount??0,n=e.taxAmount??0;if(t<0||n<0)throw new Error("POS_SALE_NEGATIVE_COMPONENT");let a=e.grossAmount,o=a-t+n,i=[{accountId:e.paymentAccountId,debit:o,credit:0,memo:"POS sale payment"},{accountId:e.revenueAccountId,debit:0,credit:a,memo:"POS sale revenue"}];if(t>0){if(!e.discountAccountId)throw new Error("POS_SALE_DISCOUNT_ACCOUNT_REQUIRED");i.push({accountId:e.discountAccountId,debit:t,credit:0,memo:"POS sale discount"})}if(n>0){if(!e.taxPayableAccountId)throw new Error("POS_SALE_TAX_ACCOUNT_REQUIRED");i.push({accountId:e.taxPayableAccountId,debit:0,credit:n,memo:"POS sale tax payable"})}return y(r,i)}function V(r,e){return h(e.principalAmount,"COOP_LOAN_INVALID_PRINCIPAL"),y(r,[{accountId:e.receivableAccountId,debit:e.principalAmount,credit:0,memo:"Loan receivable principal"},{accountId:e.cashAccountId,debit:0,credit:e.principalAmount,memo:"Loan cash out"}])}function k(r,e){return h(e.amount,"COOP_SAVING_INVALID_AMOUNT"),y(r,[{accountId:e.cashAccountId,debit:e.amount,credit:0,memo:"Saving deposit cash in"},{accountId:e.savingLiabilityAccountId,debit:0,credit:e.amount,memo:"Saving liability increase"}])}function H(r,e){return h(e.amount,"COOP_SAVING_WITHDRAWAL_INVALID_AMOUNT"),y(r,[{accountId:e.savingLiabilityAccountId,debit:e.amount,credit:0,memo:"Saving liability decrease"},{accountId:e.cashAccountId,debit:0,credit:e.amount,memo:"Saving withdrawal cash out"}])}function q(r,e){h(e.principalAmount,"COOP_LOAN_REPAYMENT_INVALID_PRINCIPAL");let t=e.serviceAmount??0,n=e.penaltyAmount??0;if(t<0||n<0)throw new Error("COOP_LOAN_REPAYMENT_NEGATIVE_COMPONENT");if(t>0&&!e.serviceRevenueAccountId)throw new Error("COOP_LOAN_REPAYMENT_SERVICE_ACCOUNT_REQUIRED");if(n>0&&!e.penaltyRevenueAccountId)throw new Error("COOP_LOAN_REPAYMENT_PENALTY_ACCOUNT_REQUIRED");let a=e.principalAmount+t+n,o=[{accountId:e.cashAccountId,debit:a,credit:0,memo:"Loan repayment cash in"},{accountId:e.receivableAccountId,debit:0,credit:e.principalAmount,memo:"Loan receivable principal repayment"}];return t>0&&o.push({accountId:e.serviceRevenueAccountId,debit:0,credit:t,memo:"Loan service revenue"}),n>0&&o.push({accountId:e.penaltyRevenueAccountId,debit:0,credit:n,memo:"Loan penalty revenue"}),y(r,o)}function be(r,e){if(h(e.amount,"COOP_SHU_PARTICIPATION_INVALID_AMOUNT"),!r.evidenceRef?.trim())throw new Error("COOP_SHU_PARTICIPATION_EVIDENCE_REQUIRED");return y(r,[{accountId:e.debitAccountId,debit:e.amount,credit:0,memo:e.memo??"Coop SHU participation manual recap debit"},{accountId:e.creditAccountId,debit:0,credit:e.amount,memo:e.memo??"Coop SHU participation manual recap credit"}])}function ee(r,e){return e?{...r,...e}:{...r}}function S(r){let e=r.tenantId?r.scopedMapping.byTenant?.[r.tenantId]:void 0,t=r.tenantId&&r.branchId?`${r.tenantId}:${r.branchId}`:"",n=t?r.scopedMapping.byBranch?.[t]:void 0;return ee(ee(r.scopedMapping.default,e),n)}function $(r){return S(r)}function Q(r){return S(r)}function W(r){return S(r)}function Y(r){return S(r)}function G(r){return S(r)}function Ae(r,e){let{scopedAccountMapping:t,...n}=e,a=$({tenantId:r.tenantId,branchId:r.branchId,scopedMapping:t});return j(r,{...n,...a})}function ye(r,e){let{scopedAccountMapping:t,...n}=e,a=Q({tenantId:r.tenantId,branchId:r.branchId,scopedMapping:t});return V(r,{...n,...a})}function he(r,e){let{scopedAccountMapping:t,...n}=e,a=Y({tenantId:r.tenantId,branchId:r.branchId,scopedMapping:t});return k(r,{...n,...a})}function Se(r,e){let{scopedAccountMapping:t,...n}=e,a=G({tenantId:r.tenantId,branchId:r.branchId,scopedMapping:t});return H(r,{...n,...a})}function Pe(r,e){let{scopedAccountMapping:t,...n}=e,a=W({tenantId:r.tenantId,branchId:r.branchId,scopedMapping:t});return q(r,{...n,...a})}function N(r){return!!(r&&typeof r=="object"&&r.error)}function X(r){return r.startsWith("ofinance_")?`offinance_${r.slice(9)}`:r}async function ve(r,e,t){let n=await r.accountService.listAccounts();if(N(n))throw new Error(n.error.message||n.error.code||"FINANCE_ACCOUNT_LIST_FAILED");let a=new Set((n.data||[]).map(o=>o.id));for(let o of e){if(a.has(o.id))continue;let i=await r.accountService.createAccount(o);if(N(i))throw new Error(i.error.message||i.error.code||"FINANCE_ACCOUNT_CREATE_FAILED");await t?.({changeId:`offinance:account:${o.id}`,entity:"FinanceAccount",table:X(c.accounts),type:"CREATE",data:o})}}async function te(r,e,t){return r.query(e,{filters:{and:t}})}async function Ce(r,e,t){if(!t)return;let n=await te(r,c.journals,[{field:"id",value:e.id}]),a=await te(r,c.journalLines,[{field:"journalId",value:e.id}]);n.length===0&&(n=[{id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,status:e.status,postedAt:e.postedAt,lastModified:e.postedAt||e.occurredAt,deleted:!1}]),a.length===0&&(a=e.lines.map((o,i)=>({id:`${e.id}:line:${i}`,journalId:e.id,accountId:o.accountId,debit:o.debit,credit:o.credit,memo:o.memo,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:e.postedAt||e.occurredAt,deleted:!1})));for(let o of n)await t({changeId:`offinance:journal:${o.id}`,entity:"FinanceJournalEntry",table:X(c.journals),type:"CREATE",data:o});for(let o of a)await t({changeId:`offinance:journal-line:${o.id}`,entity:"FinanceJournalLine",table:X(c.journalLines),type:"CREATE",data:o})}function Ee(r){return async e=>{let t=r.resolveFinanceServices();if(!t)throw new Error(r.missingServicesErrorCode||"FINANCE_SERVICES_UNAVAILABLE");let n=r.resolveLedgerProfileId().trim();if(!n)throw new Error(r.missingLedgerProfileErrorCode||"FINANCE_LEDGER_PROFILE_REQUIRED");let a=r.resolveSyncEnqueuer?.()??null;await ve(t,r.requiredAccounts,a);let o=r.buildJournalDraft(e,n),i=await t.journalService.createJournalDraft(o);if(N(i)&&i.error.code!=="JOURNAL_ALREADY_EXISTS")throw new Error(i.error.message||i.error.code||"FINANCE_JOURNAL_CREATE_FAILED");let s=await t.journalService.postJournal(o.id,o.occurredAt);if(N(s))throw new Error(s.error.message||s.error.code||"FINANCE_JOURNAL_POST_FAILED");await Ce(r.dbAdapter,s.data,a)}}function De(r){switch(r.accountType){case"asset":case"expense":return r.debit-r.credit;case"liability":case"equity":case"revenue":return r.credit-r.debit;default:return 0}}function w(r,e){return r.filter(t=>t.accountType===e).reduce((t,n)=>t+De(n),0)}function Re(r){let e=w(r,"revenue"),t=w(r,"expense");return{revenue:e,expense:t,netIncome:e-t}}function we(r){return{assets:w(r,"asset"),liabilities:w(r,"liability"),equity:w(r,"equity")}}function ne(r){return r.accountType==="revenue"?r.credit-r.debit:r.accountType==="expense"?r.debit-r.credit:0}function Fe(r){let e=r.filter(n=>n.accountType==="revenue").reduce((n,a)=>n+Math.max(0,ne(a)),0),t=r.filter(n=>n.accountType==="expense").reduce((n,a)=>n+Math.max(0,ne(a)),0);return{operatingInflow:e,operatingOutflow:t,netOperatingCashflow:e-t}}function Oe(r,e){let t=[],n=0;for(let a of e){if(a.accountType==="revenue"){let o=a.credit-a.debit;o>0&&(t.push({accountId:a.accountId,debit:o,credit:0,memo:"Close revenue account"}),n+=o)}if(a.accountType==="expense"){let o=a.debit-a.credit;o>0&&(t.push({accountId:a.accountId,debit:0,credit:o,memo:"Close expense account"}),n-=o)}}return n>0?t.push({accountId:r.retainedEarningsAccountId,debit:0,credit:n,memo:"Retained earnings from period close"}):n<0&&t.push({accountId:r.retainedEarningsAccountId,debit:Math.abs(n),credit:0,memo:"Retained earnings from period close"}),{id:r.journalId,tenantId:r.tenantId,branchId:r.branchId,financeDomainId:r.financeDomainId,ledgerProfileId:r.ledgerProfileId,occurredAt:r.occurredAt,reference:r.reference,lines:t}}function _e(r){return{version:"v1",generatedAt:r.generatedAt??new Date().toISOString(),payload:{trialBalance:r.trialBalance.map(e=>({...e})),incomeStatement:{...r.incomeStatement},balanceSheet:{...r.balanceSheet}}}}function Te(r){return r.accountType==="revenue"?r.credit-r.debit:r.accountType==="expense"?r.debit-r.credit:0}function re(r,e){return e===0?r===0?1:0:Number((r/e).toFixed(4))}function Le(r,e){let t=e.map(a=>{let s=((a.accountCodes?.length?r.filter(I=>a.accountCodes?.includes(I.accountCode)):null)??r.filter(I=>a.accountType?I.accountType===a.accountType:!1)).reduce((I,A)=>I+Te(A),0),u=s-a.plannedAmount;return{id:a.id,label:a.label,plannedAmount:a.plannedAmount,actualAmount:s,varianceAmount:u,achievementRatio:re(s,a.plannedAmount)}}),n=t.reduce((a,o)=>(a.plannedAmount+=o.plannedAmount,a.actualAmount+=o.actualAmount,a.varianceAmount+=o.varianceAmount,a),{plannedAmount:0,actualAmount:0,varianceAmount:0});return{rows:t,totals:{...n,achievementRatio:re(n.actualAmount,n.plannedAmount)}}}function ae(r,e){switch(e.type){case"finance.account.created":r.createAccount(e.payload);return;case"finance.period.opened":r.openFiscalPeriod(e.payload);return;case"finance.period.closed":r.closeFiscalPeriod(e.payload.periodId);return;case"finance.journal.drafted":r.createJournalDraft(e.payload);return;case"finance.journal.posted":r.postJournal(e.payload.journalId,e.payload.postedAt);return;case"finance.journal.reversed":r.reverseJournal(e.payload.journalId,e.payload.reversalId);return;default:throw new Error("FINANCE_EVENT_UNSUPPORTED")}}function Ne(r){let e=new D;for(let t of r)ae(e,t);return e}var oe=[{id:"coa-cash",code:"1101",name:"Kas",type:"asset"},{id:"coa-bank",code:"1102",name:"Bank",type:"asset"},{id:"coa-ar",code:"1201",name:"Piutang Usaha",type:"asset"},{id:"coa-ap",code:"2101",name:"Utang Usaha",type:"liability"},{id:"coa-retained",code:"3201",name:"Laba Ditahan",type:"equity"},{id:"coa-revenue",code:"4101",name:"Pendapatan Operasional",type:"revenue"},{id:"coa-expense",code:"5101",name:"Biaya Operasional",type:"expense"}];function xe(r="IDR"){return oe.map(e=>({id:e.id,code:e.code,name:e.name,type:e.type,currency:r,isActive:!0}))}var ie=[{id:"coop-coa-cash",code:"1101",name:"Kas",type:"asset"},{id:"coop-coa-bank",code:"1102",name:"Bank",type:"asset"},{id:"coop-coa-loan-ar",code:"1201",name:"Piutang Pinjaman Anggota",type:"asset"},{id:"coop-coa-other-ar",code:"1202",name:"Piutang Lain-lain",type:"asset"},{id:"coop-coa-prepaid",code:"1301",name:"Biaya Dibayar Dimuka",type:"asset"},{id:"coop-coa-fixed-asset",code:"1401",name:"Aset Tetap",type:"asset"},{id:"coop-coa-accum-depr",code:"1402",name:"Akumulasi Penyusutan",type:"asset"},{id:"coop-coa-simp-pokok",code:"2101",name:"Simpanan Pokok",type:"liability"},{id:"coop-coa-simp-wajib",code:"2102",name:"Simpanan Wajib",type:"liability"},{id:"coop-coa-simp-sukarela",code:"2103",name:"Simpanan Sukarela",type:"liability"},{id:"coop-coa-simp-berjangka",code:"2104",name:"Simpanan Berjangka",type:"liability"},{id:"coop-coa-ap",code:"2201",name:"Utang Usaha",type:"liability"},{id:"coop-coa-ext-loan",code:"2301",name:"Pinjaman Luar",type:"liability"},{id:"coop-coa-tax-payable",code:"2401",name:"Utang Pajak",type:"liability"},{id:"coop-coa-modal-awal",code:"3101",name:"Modal Awal",type:"equity"},{id:"coop-coa-cadangan-umum",code:"3201",name:"Dana Cadangan Umum",type:"equity"},{id:"coop-coa-cadangan-tujuan",code:"3202",name:"Dana Cadangan Tujuan",type:"equity"},{id:"coop-coa-shu-prior",code:"3301",name:"SHU Tahun Lalu",type:"equity"},{id:"coop-coa-shu-current",code:"3302",name:"SHU Berjalan",type:"equity"},{id:"coop-coa-shu-reserve",code:"3303",name:"Dana SHU Belum Dibagi",type:"equity"},{id:"coop-coa-jasa-pinjaman",code:"4101",name:"Pendapatan Jasa Pinjaman",type:"revenue"},{id:"coop-coa-provisi",code:"4102",name:"Pendapatan Provisi",type:"revenue"},{id:"coop-coa-rev-other",code:"4103",name:"Pendapatan Lain-lain",type:"revenue"},{id:"coop-coa-beban-bunga",code:"5101",name:"Beban Bunga Simpanan",type:"expense"},{id:"coop-coa-beban-ops",code:"5102",name:"Beban Operasional",type:"expense"},{id:"coop-coa-beban-gaji",code:"5103",name:"Beban Gaji dan Tunjangan",type:"expense"},{id:"coop-coa-beban-admin",code:"5104",name:"Beban Administrasi",type:"expense"},{id:"coop-coa-beban-depr",code:"5105",name:"Beban Penyusutan",type:"expense"},{id:"coop-coa-prov-kredit",code:"5106",name:"Cadangan Kerugian Piutang",type:"expense"}];function Je(r="IDR"){return ie.map(e=>({id:e.id,code:e.code,name:e.name,type:e.type,currency:r,isActive:!0}))}function Me(r){let e=new Set,t=new Set;for(let n of r){if(!n.id||!n.code||!n.name)return{ok:!1,reason:"COA_REQUIRED_FIELDS"};if(e.has(n.id))return{ok:!1,reason:"COA_DUPLICATE_ID"};if(t.has(n.code))return{ok:!1,reason:"COA_DUPLICATE_CODE"};e.add(n.id),t.add(n.code)}return{ok:!0}}
1
+ "use strict";var U=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var Ae=Object.getOwnPropertyNames;var be=Object.prototype.hasOwnProperty;var he=(n,e)=>{for(var t in e)U(n,t,{get:e[t],enumerable:!0})},Se=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of Ae(e))!be.call(n,a)&&a!==t&&U(n,a,{get:()=>e[a],enumerable:!(r=ye(e,a))||r.enumerable});return n};var Ce=n=>Se(U({},"__esModule",{value:!0}),n);var mn={};he(mn,{CANONICAL_COA_TEMPLATES:()=>fe,COOP_COA_TEMPLATES:()=>ge,OFINANCE_TABLES:()=>d,OffinanceCore:()=>T,OffinanceEnvelopeService:()=>x,OfinanceRuntimeCore:()=>B,OfinanceRuntimeCoreBuilder:()=>J,applyFinanceDomainEvent:()=>Ie,applyPendingMigrations:()=>N,buildBalanceSheet:()=>ze,buildBudgetVsRealization:()=>sn,buildCashflowBaseline:()=>We,buildClosingJournalDraft:()=>Xe,buildFinanceComplianceExportBundle:()=>ae,buildFinanceExportEnvelope:()=>an,buildFinanceOpenItemAging:()=>F,buildFinanceOperationalComplianceBundle:()=>on,buildFinanceTaxPostingLines:()=>$,buildIncomeStatement:()=>Ye,buildJournalFromCoopLoanDisbursement:()=>Y,buildJournalFromCoopLoanRepayment:()=>X,buildJournalFromCoopSavingDeposit:()=>z,buildJournalFromCoopSavingWithdrawal:()=>W,buildJournalFromCoopShuParticipationManualRecap:()=>Je,buildJournalFromPosSale:()=>G,buildJournalFromScopedCoopLoanDisbursement:()=>je,buildJournalFromScopedCoopLoanRepayment:()=>He,buildJournalFromScopedCoopSavingDeposit:()=>Ue,buildJournalFromScopedCoopSavingWithdrawal:()=>Ve,buildJournalFromScopedPosSale:()=>ke,createCanonicalCoA:()=>un,createCoopCoA:()=>pn,createDbAdapterOfinanceServices:()=>q,createFinanceProjectionSink:()=>$e,createOffinanceEnvelopeService:()=>Q,mapOffinanceErrorToEnvelope:()=>I,projectFinanceCashBankMovements:()=>w,projectFinanceOpenItems:()=>O,reconcileFinanceOpenItems:()=>D,replayFinanceDomainEvents:()=>dn,resolveCoopLoanDisbursementAccountMapping:()=>Z,resolveCoopLoanRepaymentAccountMapping:()=>ee,resolveCoopSavingDepositAccountMapping:()=>ne,resolveCoopSavingWithdrawalAccountMapping:()=>te,resolvePosSaleAccountMapping:()=>K,resolveScopedAccountMapping:()=>C,summarizeFinanceCashBankMovements:()=>_,toOffinanceFailureEnvelope:()=>H,toOffinanceSuccessEnvelope:()=>m,validateCoaIntegrity:()=>ln,validateJournalBalance:()=>R,validateOpenItemLineMetadata:()=>P});module.exports=Ce(mn);function R(n){if(!Array.isArray(n)||n.length===0)return{ok:!1,totalDebit:0,totalCredit:0,reason:"JOURNAL_LINES_EMPTY"};let e=0,t=0;for(let r of n){if(!r||!r.accountId)return{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_ACCOUNT_REQUIRED"};if(r.debit<0||r.credit<0)return{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_NEGATIVE_AMOUNT"};e+=r.debit,t+=r.credit}return Math.abs(e-t)>1e-6?{ok:!1,totalDebit:e,totalCredit:t,reason:"JOURNAL_NOT_BALANCED"}:{ok:!0,totalDebit:e,totalCredit:t}}var Ee=[{key:"current",label:"Current",maxDaysPastDue:0},{key:"1-30",label:"1-30 days",minDaysPastDue:1,maxDaysPastDue:30},{key:"31-60",label:"31-60 days",minDaysPastDue:31,maxDaysPastDue:60},{key:"61-90",label:"61-90 days",minDaysPastDue:61,maxDaysPastDue:90},{key:"90+",label:"90+ days",minDaysPastDue:91}];function ve(n,e,t){return n==="receivable"?e-t:t-e}function Re(n,e){return[n.tenantId??"",n.branchId??"",n.financeDomainId??"",n.ledgerProfileId??"",e.accountId,e.openItemType??"",e.openItemId??""].join("::")}function oe(n){return n<0?"overpaid":Math.abs(n)<1e-6?"settled":"open"}function Pe(n,e){if(!e)return 0;let t=Date.parse(n)-Date.parse(e);return!Number.isFinite(t)||t<=0?0:Math.floor(t/864e5)}function Oe(n,e){return e?!(e.tenantId&&n.tenantId!==e.tenantId||e.branchId&&n.branchId!==e.branchId||e.financeDomainId&&n.financeDomainId!==e.financeDomainId||e.ledgerProfileId&&n.ledgerProfileId!==e.ledgerProfileId||e.openItemType&&n.openItemType!==e.openItemType||e.counterpartyRef&&n.counterpartyRef!==e.counterpartyRef||!e.includeSettled&&n.status==="settled"):!0}function P(n){for(let e of n){let t=!!(e.openItemId||e.openItemType),r=!!(e.counterpartyRef||e.documentRef||e.dueAt);if(!(!t&&!r)){if(!e.openItemId)throw new Error("JOURNAL_OPEN_ITEM_ID_REQUIRED");if(!e.openItemType)throw new Error("JOURNAL_OPEN_ITEM_TYPE_REQUIRED");if(e.openItemType!=="receivable"&&e.openItemType!=="payable")throw new Error("JOURNAL_OPEN_ITEM_TYPE_INVALID");if(e.dueAt&&Number.isNaN(Date.parse(e.dueAt)))throw new Error("JOURNAL_OPEN_ITEM_DUE_AT_INVALID")}}}function O(n,e){let t=new Map;for(let r of n)if(r.status==="posted")for(let a of r.lines){if(!a.openItemId||!a.openItemType)continue;let o=Re(r,a),i=ve(a.openItemType,a.debit,a.credit),c=t.get(o);if(!c){let s={tenantId:r.tenantId,branchId:r.branchId,financeDomainId:r.financeDomainId,ledgerProfileId:r.ledgerProfileId,openItemId:a.openItemId,openItemType:a.openItemType,accountId:a.accountId,counterpartyRef:a.counterpartyRef,documentRef:a.documentRef,dueAt:a.dueAt,originatedAt:r.occurredAt,lastActivityAt:r.occurredAt,originalAmount:i>0?i:0,settledAmount:i<0?Math.abs(i):0,outstandingAmount:i,status:oe(i)};t.set(o,{item:s});continue}c.item.originatedAt=c.item.originatedAt<r.occurredAt?c.item.originatedAt:r.occurredAt,c.item.lastActivityAt=c.item.lastActivityAt>r.occurredAt?c.item.lastActivityAt:r.occurredAt,c.item.counterpartyRef=a.counterpartyRef??c.item.counterpartyRef,c.item.documentRef=a.documentRef??c.item.documentRef,c.item.dueAt=a.dueAt??c.item.dueAt,i>0?c.item.originalAmount+=i:i<0&&(c.item.settledAmount+=Math.abs(i)),c.item.outstandingAmount+=i,c.item.status=oe(c.item.outstandingAmount)}return Array.from(t.values()).map(({item:r})=>({...r})).filter(r=>Oe(r,e)).sort((r,a)=>r.originatedAt!==a.originatedAt?r.originatedAt.localeCompare(a.originatedAt):r.openItemId.localeCompare(a.openItemId))}function F(n,e){if(Number.isNaN(Date.parse(e.asOf)))throw new Error("FINANCE_OPEN_ITEM_AGING_AS_OF_INVALID");let t=(e.buckets?.length?e.buckets:Ee).map(a=>({...a,amount:0,itemCount:0})),r=0;for(let a of n){if(a.outstandingAmount<=0)continue;r+=a.outstandingAmount;let o=Pe(e.asOf,a.dueAt),i=t.find(c=>{let s=c.minDaysPastDue??Number.NEGATIVE_INFINITY,p=c.maxDaysPastDue??Number.POSITIVE_INFINITY;return o>=s&&o<=p});if(!i)throw new Error("FINANCE_OPEN_ITEM_AGING_BUCKET_UNRESOLVED");i.amount+=a.outstandingAmount,i.itemCount+=1}return{asOf:e.asOf,openItemType:e.openItemType,totalOutstanding:r,buckets:t}}function ie(n,e){return`${e??""}::${n}`}function Fe(n){if(!n.openItemId?.trim())throw new Error("FINANCE_RECONCILIATION_OPEN_ITEM_ID_REQUIRED");if(!Number.isFinite(n.observedAmount)||n.observedAmount<0)throw new Error("FINANCE_RECONCILIATION_OBSERVED_AMOUNT_INVALID");if(n.openItemType&&n.openItemType!=="receivable"&&n.openItemType!=="payable")throw new Error("FINANCE_RECONCILIATION_OPEN_ITEM_TYPE_INVALID")}function De(n,e){let t=new Map;for(let r of n){Fe(r);let a=r.openItemType??e,o=ie(r.openItemId,a),i=t.get(o);if(!i){t.set(o,{openItemId:r.openItemId,openItemType:a,observedAmount:r.observedAmount,counterpartyRef:r.counterpartyRef,documentRef:r.documentRef,references:r.reference?[r.reference]:[]});continue}i.observedAmount+=r.observedAmount,i.counterpartyRef=r.counterpartyRef??i.counterpartyRef,i.documentRef=r.documentRef??i.documentRef,r.reference&&i.references.push(r.reference)}return t}function we(n,e,t){let r=n.outstandingAmount,a=e?.observedAmount??0,o=a-r;if(!e)return{tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,openItemId:n.openItemId,openItemType:n.openItemType,accountId:n.accountId,counterpartyRef:n.counterpartyRef,documentRef:n.documentRef,dueAt:n.dueAt,expectedAmount:r,observedAmount:a,varianceAmount:o,status:"missing",reason:"FINANCE_RECONCILIATION_OBSERVATION_MISSING",observedReferences:[]};let i=e.counterpartyRef&&n.counterpartyRef&&e.counterpartyRef!==n.counterpartyRef||e.documentRef&&n.documentRef&&e.documentRef!==n.documentRef,c="matched",s;return i?(c="mismatch",s="FINANCE_RECONCILIATION_METADATA_MISMATCH"):Math.abs(o)<=t?c="matched":o<0?(c="under",s="FINANCE_RECONCILIATION_OBSERVED_UNDER"):o>0&&(c="over",s="FINANCE_RECONCILIATION_OBSERVED_OVER"),{tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,openItemId:n.openItemId,openItemType:n.openItemType,accountId:n.accountId,counterpartyRef:n.counterpartyRef,documentRef:n.documentRef,dueAt:n.dueAt,expectedAmount:r,observedAmount:a,varianceAmount:o,status:c,reason:s,observedReferences:[...e.references]}}function _e(n,e){return{tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,openItemId:n.openItemId,openItemType:n.openItemType??e.openItemType,counterpartyRef:n.counterpartyRef,documentRef:n.documentRef,expectedAmount:0,observedAmount:n.observedAmount,varianceAmount:n.observedAmount,status:"mismatch",reason:"FINANCE_RECONCILIATION_EXPECTED_ITEM_NOT_FOUND",observedReferences:[...n.references]}}function D(n,e){let t=e.toleranceAmount??0;if(!Number.isFinite(t)||t<0)throw new Error("FINANCE_RECONCILIATION_TOLERANCE_INVALID");let r=De(e.observations,e.openItemType),a=[];for(let s of n){let p=ie(s.openItemId,s.openItemType),f=r.get(p);a.push(we(s,f,t)),r.delete(p)}for(let s of r.values())a.push(_e(s,e));a.sort((s,p)=>(s.financeDomainId??"")!==(p.financeDomainId??"")?(s.financeDomainId??"").localeCompare(p.financeDomainId??""):(s.ledgerProfileId??"")!==(p.ledgerProfileId??"")?(s.ledgerProfileId??"").localeCompare(p.ledgerProfileId??""):s.openItemId.localeCompare(p.openItemId));let o=a.reduce((s,p)=>s+p.expectedAmount,0),i=a.reduce((s,p)=>s+p.observedAmount,0),c=a.reduce((s,p)=>s+p.varianceAmount,0);return{openItemType:e.openItemType,totalExpectedAmount:o,totalObservedAmount:i,totalVarianceAmount:c,rows:a}}function Te(n){if(!Array.isArray(n.trackedAccountIds)||n.trackedAccountIds.length===0)throw new Error("FINANCE_CASH_MOVEMENT_TRACKED_ACCOUNTS_REQUIRED");let e=new Set(n.trackedAccountIds.map(t=>t.trim()).filter(Boolean));if(e.size===0)throw new Error("FINANCE_CASH_MOVEMENT_TRACKED_ACCOUNTS_REQUIRED");return e}function Ne(n,e){return!(e.tenantId&&n.tenantId!==e.tenantId||e.branchId&&n.branchId!==e.branchId||e.financeDomainId&&n.financeDomainId!==e.financeDomainId||e.ledgerProfileId&&n.ledgerProfileId!==e.ledgerProfileId||e.occurredFrom&&n.occurredAt<e.occurredFrom||e.occurredTo&&n.occurredAt>e.occurredTo)}function w(n,e){let t=Te(e),r=[];for(let a of n){if(a.status!=="posted"||!Ne(a,e))continue;let o=a.lines.filter(l=>t.has(l.accountId)&&(l.debit>0||l.credit>0));if(o.length===0)continue;let i=Array.from(new Set(o.map(l=>l.accountId))).sort(),c=Array.from(new Set(a.lines.filter(l=>!t.has(l.accountId)&&(l.debit>0||l.credit>0)).map(l=>l.accountId))).sort(),s=o.some(l=>l.debit>0),p=o.some(l=>l.credit>0),f=i.length>1&&s&&p;for(let l of o)l.debit>0&&r.push({journalId:a.id,tenantId:a.tenantId,branchId:a.branchId,financeDomainId:a.financeDomainId,ledgerProfileId:a.ledgerProfileId,occurredAt:a.occurredAt,reference:a.reference,evidenceRef:a.evidenceRef,accountId:l.accountId,direction:f?"transfer_in":"in",amount:l.debit,counterpartAccountIds:c,trackedAccountIdsInJournal:i}),l.credit>0&&r.push({journalId:a.id,tenantId:a.tenantId,branchId:a.branchId,financeDomainId:a.financeDomainId,ledgerProfileId:a.ledgerProfileId,occurredAt:a.occurredAt,reference:a.reference,evidenceRef:a.evidenceRef,accountId:l.accountId,direction:f?"transfer_out":"out",amount:l.credit,counterpartAccountIds:c,trackedAccountIdsInJournal:i})}return r.sort((a,o)=>a.occurredAt!==o.occurredAt?a.occurredAt.localeCompare(o.occurredAt):a.journalId!==o.journalId?a.journalId.localeCompare(o.journalId):a.accountId.localeCompare(o.accountId))}function _(n){let e=0,t=0,r=0,a=0;for(let o of n)o.direction==="in"&&(e+=o.amount),o.direction==="out"&&(t+=o.amount),o.direction==="transfer_in"&&(r+=o.amount),o.direction==="transfer_out"&&(a+=o.amount);return{totalInflow:e,totalOutflow:t,totalTransferIn:r,totalTransferOut:a,netExternalMovement:e-t,entries:n.map(o=>({...o,counterpartAccountIds:[...o.counterpartAccountIds],trackedAccountIdsInJournal:[...o.trackedAccountIdsInJournal]}))}}var T=class{constructor(e){this.state={accounts:e?.accounts??new Map,periods:e?.periods??new Map,journals:e?.journals??new Map,balances:e?.balances??new Map,rapbPlans:e?.rapbPlans??new Map}}createAccount(e){if(!e.id||!e.code||!e.name)throw new Error("FINANCE_ACCOUNT_REQUIRED_FIELDS");if(this.state.accounts.has(e.id))throw new Error("FINANCE_ACCOUNT_ALREADY_EXISTS");if(Array.from(this.state.accounts.values()).some(r=>r.code===e.code))throw new Error("FINANCE_ACCOUNT_CODE_DUPLICATE");return this.state.accounts.set(e.id,{...e}),{...e}}listAccounts(){return Array.from(this.state.accounts.values()).map(e=>({...e})).sort((e,t)=>e.code.localeCompare(t.code))}openFiscalPeriod(e){if(!e.id||!e.tenantId||!e.code||!e.startDate||!e.endDate)throw new Error("FISCAL_PERIOD_REQUIRED_FIELDS");if(this.state.periods.has(e.id))throw new Error("FISCAL_PERIOD_ALREADY_EXISTS");if(Date.parse(e.startDate)>Date.parse(e.endDate))throw new Error("FISCAL_PERIOD_INVALID_RANGE");let t={...e,status:"open"};return this.state.periods.set(t.id,t),{...t}}closeFiscalPeriod(e){let t=this.state.periods.get(e);if(!t)throw new Error("FISCAL_PERIOD_NOT_FOUND");let r={...t,status:"closed"};return this.state.periods.set(e,r),{...r}}listFiscalPeriods(){return Array.from(this.state.periods.values()).map(e=>({...e})).sort((e,t)=>e.startDate.localeCompare(t.startDate))}createJournalDraft(e){if(!e.id||!e.tenantId||!e.occurredAt)throw new Error("JOURNAL_REQUIRED_FIELDS");if(this.state.journals.has(e.id))throw new Error("JOURNAL_ALREADY_EXISTS");this.assertJournalLinesKnownAccounts(e.lines),this.assertJournalPeriodOpen(e.occurredAt),P(e.lines);let t=R(e.lines);if(!t.ok)throw new Error(t.reason??"JOURNAL_INVALID");let r={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,evidenceRef:e.evidenceRef,lines:e.lines.map(a=>({...a})),status:"draft"};return this.state.journals.set(r.id,r),{...r,lines:r.lines.map(a=>({...a}))}}postJournal(e,t=new Date().toISOString()){let r=this.state.journals.get(e);if(!r)throw new Error("JOURNAL_NOT_FOUND");if(r.status==="posted"||r.status==="reversed")return{...r,lines:r.lines.map(o=>({...o}))};this.applyLinesToBalance(r.lines);let a={...r,status:"posted",postedAt:t};return this.state.journals.set(e,a),{...a,lines:a.lines.map(o=>({...o}))}}reverseJournal(e,t){let r=this.state.journals.get(e);if(!r)throw new Error("JOURNAL_NOT_FOUND");if(r.status!=="posted")throw new Error("JOURNAL_NOT_POSTED");if(this.state.journals.has(t))throw new Error("JOURNAL_ALREADY_EXISTS");let a=r.lines.map(i=>({accountId:i.accountId,debit:i.credit,credit:i.debit,memo:i.memo,openItemId:i.openItemId,openItemType:i.openItemType,counterpartyRef:i.counterpartyRef,documentRef:i.documentRef,dueAt:i.dueAt})),o=this.createJournalDraft({id:t,tenantId:r.tenantId,branchId:r.branchId,financeDomainId:r.financeDomainId,ledgerProfileId:r.ledgerProfileId,occurredAt:r.occurredAt,reference:`reversal:${r.id}`,evidenceRef:r.evidenceRef,lines:a});return this.postJournal(o.id)}getTrialBalance(){return this.getTrialBalanceByScope()}getTrialBalanceByScope(e){let t=this.computeScopedBalances(e);return this.listAccounts().map(a=>{let o=t.get(a.id)??{debit:0,credit:0};return{accountId:a.id,accountCode:a.code,accountName:a.name,accountType:a.type,debit:o.debit,credit:o.credit,net:o.debit-o.credit}})}listJournals(e){return Array.from(this.state.journals.values()).filter(t=>this.matchesScope(t,e)).map(t=>({...t,lines:t.lines.map(r=>({...r}))})).sort((t,r)=>t.occurredAt.localeCompare(r.occurredAt))}listOpenItems(e){return O(this.listJournals(e),e)}getOpenItemAging(e){return F(this.listOpenItems(e),e)}reconcileOpenItems(e){return D(this.listOpenItems(e),e)}listCashBankMovements(e){return w(this.listJournals(e),e)}summarizeCashBankMovements(e){return _(this.listCashBankMovements(e))}assertJournalLinesKnownAccounts(e){for(let t of e)if(!this.state.accounts.has(t.accountId))throw new Error("JOURNAL_ACCOUNT_NOT_FOUND")}assertJournalPeriodOpen(e){if(this.state.periods.size===0)return;let t=this.findPeriodByDate(e);if(!t)throw new Error("FISCAL_PERIOD_NOT_FOUND_FOR_DATE");if(t.status!=="open")throw new Error("FISCAL_PERIOD_CLOSED")}findPeriodByDate(e){let t=Date.parse(e);for(let r of this.state.periods.values()){let a=Date.parse(r.startDate),o=Date.parse(r.endDate);if(t>=a&&t<=o)return r}return null}applyLinesToBalance(e){for(let t of e){let r=this.state.balances.get(t.accountId)??{debit:0,credit:0};r.debit+=t.debit,r.credit+=t.credit,this.state.balances.set(t.accountId,r)}}computeScopedBalances(e){if(!e||!e.tenantId&&!e.branchId&&!e.financeDomainId&&!e.ledgerProfileId&&!e.occurredFrom&&!e.occurredTo)return this.state.balances;let t=new Map;for(let r of this.state.journals.values())if(r.status==="posted"&&this.matchesScope(r,e))for(let a of r.lines){let o=t.get(a.accountId)??{debit:0,credit:0};o.debit+=a.debit,o.credit+=a.credit,t.set(a.accountId,o)}return t}matchesScope(e,t){return t?!(t.tenantId&&e.tenantId!==t.tenantId||t.branchId&&e.branchId!==t.branchId||t.financeDomainId&&e.financeDomainId!==t.financeDomainId||t.ledgerProfileId&&e.ledgerProfileId!==t.ledgerProfileId||t.occurredFrom&&e.occurredAt<t.occurredFrom||t.occurredTo&&e.occurredAt>t.occurredTo):!0}createRapb(e){if(!e.id||!e.tenantId||!e.periodCode||!e.title)throw new Error("RAPB_REQUIRED_FIELDS");if(!e.lines||e.lines.length===0)throw new Error("RAPB_LINES_REQUIRED");if(this.state.rapbPlans.has(e.id))throw new Error("RAPB_ALREADY_EXISTS");if(e.lines.some(a=>a.budgetedDebit<0||a.budgetedCredit<0))throw new Error("RAPB_NEGATIVE_AMOUNT");let t=e.lines.map(a=>{let o=this.state.accounts.get(a.accountId);if(!o)throw new Error(`RAPB_ACCOUNT_NOT_FOUND:${a.accountId}`);let i=a.budgetedDebit-a.budgetedCredit;return{accountId:a.accountId,accountCode:o.code,accountName:o.name,accountType:o.type,budgetedDebit:a.budgetedDebit,budgetedCredit:a.budgetedCredit,budgetedNet:i}}),r={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,periodCode:e.periodCode,title:e.title,status:"draft",lines:t,notes:e.notes,createdAt:new Date().toISOString()};return this.state.rapbPlans.set(r.id,r),r}getRapb(e){return this.state.rapbPlans.get(e)??null}listRapb(e){let t=Array.from(this.state.rapbPlans.values());return e&&(e.tenantId&&(t=t.filter(r=>r.tenantId===e.tenantId)),e.periodCode&&(t=t.filter(r=>r.periodCode===e.periodCode)),e.branchId&&(t=t.filter(r=>r.branchId===e.branchId)),e.financeDomainId&&(t=t.filter(r=>r.financeDomainId===e.financeDomainId)),e.ledgerProfileId&&(t=t.filter(r=>r.ledgerProfileId===e.ledgerProfileId))),t}approveRapb(e,t){let r=this.state.rapbPlans.get(e);if(!r)throw new Error("RAPB_NOT_FOUND");let a=typeof t=="string"?t:t.approvedBy;if(r.status==="approved")throw new Error("RAPB_ALREADY_APPROVED");let o={...r,status:"approved",approvedAt:new Date().toISOString(),approvedBy:a};return this.state.rapbPlans.set(e,o),o}evaluateVariance(e){let t=this.state.rapbPlans.get(e);if(!t)throw new Error("RAPB_NOT_FOUND");let r=this.getTrialBalance(),a=new Map(r.map(u=>[u.accountId,u])),o=0,i=0,c=0,s=0,p=t.lines.map(u=>{let E=a.get(u.accountId),g=E?.debit??0,y=E?.credit??0,v=g-y;return u.accountType==="revenue"?(o+=u.budgetedCredit-u.budgetedDebit,i+=y-g):u.accountType==="expense"&&(c+=u.budgetedDebit-u.budgetedCredit,s+=g-y),{accountId:u.accountId,accountCode:u.accountCode,accountName:u.accountName,accountType:u.accountType,budgetedDebit:u.budgetedDebit,budgetedCredit:u.budgetedCredit,budgetedNet:u.budgetedNet,actualDebit:g,actualCredit:y,actualNet:v,varianceDebit:g-u.budgetedDebit,varianceCredit:y-u.budgetedCredit,varianceNet:v-u.budgetedNet}}),f=o-c,l=i-s;return{rapbId:e,periodCode:t.periodCode,evaluatedAt:new Date().toISOString(),lines:p,totalBudgetedRevenue:o,totalActualRevenue:i,totalBudgetedExpense:c,totalActualExpense:s,budgetedNetIncome:f,actualNetIncome:l,netVariance:l-f}}};var se=require("ofcore"),de=require("ofcore"),k=require("ofcore");var d={accounts:"ofinance_accounts",periods:"ofinance_periods",journals:"ofinance_journals",journalLines:"ofinance_journal_lines",rapbPlans:"ofinance_rapb_plans",rapbLines:"ofinance_rapb_lines",histories:"ofinance_histories"},Le=[{name:d.accounts,columns:[{name:"id",type:"string"},{name:"code",type:"string",isIndexed:!0},{name:"name",type:"string"},{name:"type",type:"string",isIndexed:!0},{name:"currency",type:"string"},{name:"isActive",type:"boolean",isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.periods,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"code",type:"string",isIndexed:!0},{name:"startDate",type:"string",isIndexed:!0},{name:"endDate",type:"string",isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.journals,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"occurredAt",type:"string",isIndexed:!0},{name:"reference",type:"string",isOptional:!0,isIndexed:!0},{name:"evidenceRef",type:"string",isOptional:!0,isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"postedAt",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.journalLines,columns:[{name:"id",type:"string"},{name:"journalId",type:"string",isIndexed:!0},{name:"accountId",type:"string",isIndexed:!0},{name:"debit",type:"number"},{name:"credit",type:"number"},{name:"memo",type:"string",isOptional:!0},{name:"openItemId",type:"string",isOptional:!0,isIndexed:!0},{name:"openItemType",type:"string",isOptional:!0,isIndexed:!0},{name:"counterpartyRef",type:"string",isOptional:!0,isIndexed:!0},{name:"documentRef",type:"string",isOptional:!0,isIndexed:!0},{name:"dueAt",type:"string",isOptional:!0,isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.rapbPlans,columns:[{name:"id",type:"string"},{name:"tenantId",type:"string",isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"periodCode",type:"string",isIndexed:!0},{name:"title",type:"string",isIndexed:!0},{name:"status",type:"string",isIndexed:!0},{name:"notes",type:"string",isOptional:!0},{name:"createdAt",type:"string",isIndexed:!0},{name:"approvedAt",type:"string",isOptional:!0,isIndexed:!0},{name:"approvedBy",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.rapbLines,columns:[{name:"id",type:"string"},{name:"rapbId",type:"string",isIndexed:!0},{name:"accountId",type:"string",isIndexed:!0},{name:"accountCode",type:"string",isIndexed:!0},{name:"accountName",type:"string"},{name:"accountType",type:"string",isIndexed:!0},{name:"budgetedDebit",type:"number"},{name:"budgetedCredit",type:"number"},{name:"budgetedNet",type:"number"},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:d.histories,columns:[{name:"id",type:"string"},{name:"tableName",type:"string",isIndexed:!0},{name:"recordId",type:"string",isIndexed:!0},{name:"action",type:"string",isIndexed:!0},{name:"changes",type:"json",isOptional:!0},{name:"timestamp",type:"string",isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"financeDomainId",type:"string",isOptional:!0,isIndexed:!0},{name:"ledgerProfileId",type:"string",isOptional:!0,isIndexed:!0}]}];function V(){return Le.map(n=>({...n,columns:n.columns.map(e=>({...e}))}))}var ce=[{toVersion:1,up:async n=>{let e=V();for(let t of e)try{await n.addTable(t)}catch{}}},{toVersion:2,up:async n=>{let e=V().filter(t=>t.name==="ofinance_rapb_plans"||t.name==="ofinance_rapb_lines");for(let t of e)try{await n.addTable(t)}catch{}}},{toVersion:3,up:async n=>{try{await n.addColumn("ofinance_journals",{name:"evidenceRef",type:"string",isOptional:!0,isIndexed:!0})}catch{}}},{toVersion:4,up:async n=>{let e=[{name:"openItemId",type:"string",isOptional:!0,isIndexed:!0},{name:"openItemType",type:"string",isOptional:!0,isIndexed:!0},{name:"counterpartyRef",type:"string",isOptional:!0,isIndexed:!0},{name:"documentRef",type:"string",isOptional:!0,isIndexed:!0},{name:"dueAt",type:"string",isOptional:!0,isIndexed:!0}];for(let t of e)try{await n.addColumn("ofinance_journal_lines",t)}catch{}}}];var xe={logInfo(){},logWarn(){},logError(){}};async function N(n,e=xe){e.logInfo("[offinance] starting database migration process");let t=[...ce].sort((o,i)=>o.toVersion-i.toVersion),r=t.length>0?t[t.length-1].toVersion:0,a=await n.getSchemaVersion();if((a==null||a<0)&&(a=0),a>=r){e.logInfo(`[offinance] database already up-to-date at v${a}`);return}for(let o of t)o.toVersion>a&&(e.logInfo(`[offinance] applying migration v${o.toVersion}`),await o.up(n),await n.setSchemaVersion(o.toVersion),a=o.toVersion);e.logInfo(`[offinance] migration completed at v${a}`)}function m(n,e){return{data:n,meta:{request_id:e??null,timestamp:new Date().toISOString()}}}function H(n,e,t={}){return{error:{code:n,message:e,details:t.details,retryable:t.retryable,correlationId:t.correlationId,timestamp:new Date().toISOString()},meta:{request_id:t.requestId??null,timestamp:new Date().toISOString()}}}function I(n,e="FINANCE_NOT_IMPLEMENTED",t="Unhandled offinance error."){return n instanceof Error?H(e,n.message||t):H(e,t)}var x=class{constructor(e){this.legacy=e;this.accountService={createAccount:async t=>{try{return m(await this.legacy.accountService.createAccount(t))}catch(r){return I(r)}},listAccounts:async()=>{try{return m(await this.legacy.accountService.listAccounts())}catch(t){return I(t)}}},this.journalService={createJournalDraft:async t=>{try{return m(await this.legacy.journalService.createJournalDraft(t))}catch(r){return I(r)}},postJournal:async(t,r)=>{try{return m(await this.legacy.journalService.postJournal(t,r))}catch(a){return I(a)}},reverseJournal:async(t,r)=>{try{return m(await this.legacy.journalService.reverseJournal(t,r))}catch(a){return I(a)}},listJournals:async t=>{try{return m(await this.legacy.journalService.listJournals(t))}catch(r){return I(r)}}},this.fiscalService={openFiscalPeriod:async t=>{try{return m(await this.legacy.fiscalService.openFiscalPeriod(t))}catch(r){return I(r)}},closeFiscalPeriod:async t=>{try{return m(await this.legacy.fiscalService.closeFiscalPeriod(t))}catch(r){return I(r)}},listFiscalPeriods:async()=>{try{return m(await this.legacy.fiscalService.listFiscalPeriods())}catch(t){return I(t)}},getTrialBalance:async()=>{try{return m(await this.legacy.fiscalService.getTrialBalance())}catch(t){return I(t)}},getTrialBalanceByScope:async t=>{try{return m(await this.legacy.fiscalService.getTrialBalanceByScope(t))}catch(r){return I(r)}}},this.rapbService={createRapb:async t=>{try{return m(await this.legacy.rapbService.createRapb(t))}catch(r){return I(r)}},getRapb:async t=>{try{return m(await this.legacy.rapbService.getRapb(t))}catch(r){return I(r)}},listRapb:async t=>{try{return m(await this.legacy.rapbService.listRapb(t))}catch(r){return I(r)}},approveRapb:async(t,r)=>{try{return m(await this.legacy.rapbService.approveRapb(t,r))}catch(a){return I(a)}},evaluateVariance:async t=>{try{return m(await this.legacy.rapbService.evaluateVariance(t))}catch(r){return I(r)}}},this.openItemService={listOpenItems:async t=>{try{return m(await this.legacy.openItemService.listOpenItems(t))}catch(r){return I(r)}},getOpenItemAging:async t=>{try{return m(await this.legacy.openItemService.getOpenItemAging(t))}catch(r){return I(r)}}},this.reconciliationService={reconcileOpenItems:async t=>{try{return m(await this.legacy.reconciliationService.reconcileOpenItems(t))}catch(r){return I(r)}}},this.cashMovementService={listCashBankMovements:async t=>{try{return m(await this.legacy.cashMovementService.listCashBankMovements(t))}catch(r){return I(r)}},summarizeCashBankMovements:async t=>{try{return m(await this.legacy.cashMovementService.summarizeCashBankMovements(t))}catch(r){return I(r)}}}}};function Q(n){return new x({accountService:n,journalService:n,fiscalService:n,rapbService:n,openItemService:n,reconciliationService:n,cashMovementService:n})}function b(n){return JSON.parse(JSON.stringify(n))}function A(){return new Date().toISOString()}function Me(n,e){return`${n}:${e}:${Date.now()}:${Math.random().toString(36).slice(2,8)}`}function Be(n,e){return!n||n.deleted?!1:e?!(e.tenantId&&n.tenantId!==e.tenantId||e.branchId&&n.branchId!==e.branchId||e.financeDomainId&&n.financeDomainId!==e.financeDomainId||e.ledgerProfileId&&n.ledgerProfileId!==e.ledgerProfileId||e.occurredFrom&&n.occurredAt&&n.occurredAt<e.occurredFrom||e.occurredTo&&n.occurredAt&&n.occurredAt>e.occurredTo):!0}var M=class{constructor(e){this.dbAdapter=e}async createAccount(e){if(!e.id||!e.code||!e.name)throw new Error("FINANCE_ACCOUNT_REQUIRED_FIELDS");let t=await this.dbAdapter.get(d.accounts,e.id);if(t&&!t.deleted)throw new Error("FINANCE_ACCOUNT_ALREADY_EXISTS");if((await this.dbAdapter.query(d.accounts,{filters:{and:[{field:"code",value:e.code},{field:"deleted",value:!1}]}})).some(i=>i.id!==e.id))throw new Error("FINANCE_ACCOUNT_CODE_DUPLICATE");let a=A(),o={...b(e),lastModified:a,deleted:!1};return t?await this.dbAdapter.update(d.accounts,e.id,o):await this.dbAdapter.create(d.accounts,o),await this.writeHistory("accounts",e.id,"UPSERT",o),b(e)}async listAccounts(){return(await this.dbAdapter.query(d.accounts,{filters:{field:"deleted",value:!1}})).map(({lastModified:t,deleted:r,...a})=>b(a)).sort((t,r)=>t.code.localeCompare(r.code))}async createJournalDraft(e){if(!e.id||!e.tenantId||!e.occurredAt)throw new Error("JOURNAL_REQUIRED_FIELDS");if(!e.ledgerProfileId)throw new Error("JOURNAL_REQUIRED_FIELDS");let t=await this.dbAdapter.get(d.journals,e.id);if(t&&!t.deleted)throw new Error("JOURNAL_ALREADY_EXISTS");await this.assertJournalLinesKnownAccounts(e.lines),await this.assertJournalPeriodOpen(e),P(e.lines);let r=R(e.lines);if(!r.ok)throw new Error(r.reason??"JOURNAL_INVALID");let a=A(),o={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,evidenceRef:e.evidenceRef,status:"draft",postedAt:void 0,lastModified:a,deleted:!1};await this.dbAdapter.create(d.journals,o);for(let i=0;i<e.lines.length;i+=1){let c=e.lines[i],s={id:`${e.id}:line:${i}`,journalId:e.id,accountId:c.accountId,debit:c.debit,credit:c.credit,memo:c.memo,openItemId:c.openItemId,openItemType:c.openItemType,counterpartyRef:c.counterpartyRef,documentRef:c.documentRef,dueAt:c.dueAt,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:a,deleted:!1};await this.dbAdapter.create(d.journalLines,s),await this.writeHistory("journal_lines",s.id,"UPSERT",s)}return await this.writeHistory("journals",e.id,"UPSERT",o),this.toJournalEntry(o,e.lines)}async postJournal(e,t=A()){let r=await this.requireJournal(e),a=await this.listJournalLines(e);if(r.status==="posted"||r.status==="reversed")return this.toJournalEntry(r,a);let o={...r,status:"posted",postedAt:t,lastModified:A()};return await this.dbAdapter.update(d.journals,e,o),await this.writeHistory("journals",e,"UPSERT",o),this.toJournalEntry(o,a)}async reverseJournal(e,t){let r=await this.requireJournal(e);if(r.status!=="posted")throw new Error("JOURNAL_NOT_POSTED");let a=await this.listJournalLines(e),o=await this.createJournalDraft({id:t,tenantId:r.tenantId,branchId:r.branchId,financeDomainId:r.financeDomainId,ledgerProfileId:r.ledgerProfileId,occurredAt:r.occurredAt,reference:`reversal:${r.id}`,evidenceRef:r.evidenceRef,lines:a.map(i=>({accountId:i.accountId,debit:i.credit,credit:i.debit,memo:i.memo,openItemId:i.openItemId,openItemType:i.openItemType,counterpartyRef:i.counterpartyRef,documentRef:i.documentRef,dueAt:i.dueAt}))});return this.postJournal(o.id)}async listJournals(e){let r=(await this.dbAdapter.query(d.journals,{filters:{field:"deleted",value:!1}})).filter(o=>Be(o,e)).sort((o,i)=>o.occurredAt.localeCompare(i.occurredAt)),a=[];for(let o of r){let i=await this.listJournalLines(o.id);a.push(this.toJournalEntry(o,i))}return a}async listOpenItems(e){return O(await this.listJournals(e),e)}async getOpenItemAging(e){return F(await this.listOpenItems(e),e)}async reconcileOpenItems(e){return D(await this.listOpenItems(e),e)}async listCashBankMovements(e){return w(await this.listJournals(e),e)}async summarizeCashBankMovements(e){return _(await this.listCashBankMovements(e))}async openFiscalPeriod(e){if(!e.id||!e.tenantId||!e.code||!e.startDate||!e.endDate)throw new Error("FISCAL_PERIOD_REQUIRED_FIELDS");if(Date.parse(e.startDate)>Date.parse(e.endDate))throw new Error("FISCAL_PERIOD_INVALID_RANGE");let t=await this.dbAdapter.get(d.periods,e.id);if(t&&!t.deleted)throw new Error("FISCAL_PERIOD_ALREADY_EXISTS");let r=A(),a={...b(e),status:"open",lastModified:r,deleted:!1};return t?await this.dbAdapter.update(d.periods,e.id,a):await this.dbAdapter.create(d.periods,a),await this.writeHistory("periods",e.id,"UPSERT",a),this.toPeriod(a)}async closeFiscalPeriod(e){let t=await this.dbAdapter.get(d.periods,e);if(!t||t.deleted)throw new Error("FISCAL_PERIOD_NOT_FOUND");let r={...t,status:"closed",lastModified:A()};return await this.dbAdapter.update(d.periods,e,r),await this.writeHistory("periods",e,"UPSERT",r),this.toPeriod(r)}async listFiscalPeriods(){return(await this.dbAdapter.query(d.periods,{filters:{field:"deleted",value:!1}})).map(t=>this.toPeriod(t)).sort((t,r)=>t.startDate.localeCompare(r.startDate))}async getTrialBalance(){return this.getTrialBalanceByScope()}async getTrialBalanceByScope(e){let t=await this.listAccounts(),a=(await this.listJournals(e)).filter(i=>i.status==="posted"),o=new Map;for(let i of a)for(let c of i.lines){let s=o.get(c.accountId)??{debit:0,credit:0};s.debit+=Number(c.debit||0),s.credit+=Number(c.credit||0),o.set(c.accountId,s)}return t.map(i=>{let c=o.get(i.id)??{debit:0,credit:0};return{accountId:i.id,accountCode:i.code,accountName:i.name,accountType:i.type,debit:c.debit,credit:c.credit,net:c.debit-c.credit}})}async createRapb(e){if(!e.id||!e.tenantId||!e.periodCode||!e.title)throw new Error("RAPB_REQUIRED_FIELDS");if(!e.lines||e.lines.length===0)throw new Error("RAPB_LINES_REQUIRED");if(e.lines.some(i=>i.budgetedDebit<0||i.budgetedCredit<0))throw new Error("RAPB_NEGATIVE_AMOUNT");let t=await this.dbAdapter.get(d.rapbPlans,e.id);if(t&&!t.deleted)throw new Error("RAPB_ALREADY_EXISTS");let r=A(),a=[];for(let i=0;i<e.lines.length;i+=1){let c=e.lines[i],s=await this.dbAdapter.get(d.accounts,c.accountId);if(!s||s.deleted)throw new Error(`RAPB_ACCOUNT_NOT_FOUND:${c.accountId}`);a.push({id:`${e.id}:line:${i}`,rapbId:e.id,accountId:c.accountId,accountCode:s.code,accountName:s.name,accountType:s.type,budgetedDebit:c.budgetedDebit,budgetedCredit:c.budgetedCredit,budgetedNet:c.budgetedDebit-c.budgetedCredit,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:r,deleted:!1})}let o={id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,periodCode:e.periodCode,title:e.title,status:"draft",notes:e.notes,createdAt:r,approvedAt:void 0,approvedBy:void 0,lastModified:r,deleted:!1};await this.dbAdapter.create(d.rapbPlans,o),await this.writeHistory("rapb_plans",e.id,"UPSERT",o);for(let i of a)await this.dbAdapter.create(d.rapbLines,i),await this.writeHistory("rapb_lines",i.id,"UPSERT",i);return this.toRapbPlan(o,a)}async getRapb(e){let t=await this.dbAdapter.get(d.rapbPlans,e);if(!t||t.deleted)return null;let r=await this.listRapbLines(e);return this.toRapbPlan(t,r)}async listRapb(e){let r=await this.dbAdapter.query(d.rapbPlans,{filters:{field:"deleted",value:!1}});e&&(e.tenantId&&(r=r.filter(o=>o.tenantId===e.tenantId)),e.periodCode&&(r=r.filter(o=>o.periodCode===e.periodCode)),e.branchId&&(r=r.filter(o=>o.branchId===e.branchId)),e.financeDomainId&&(r=r.filter(o=>o.financeDomainId===e.financeDomainId)),e.ledgerProfileId&&(r=r.filter(o=>o.ledgerProfileId===e.ledgerProfileId)));let a=[];for(let o of r.sort((i,c)=>i.createdAt.localeCompare(c.createdAt))){let i=await this.listRapbLines(o.id);a.push(this.toRapbPlan(o,i))}return a}async approveRapb(e,t){let r=await this.dbAdapter.get(d.rapbPlans,e);if(!r||r.deleted)throw new Error("RAPB_NOT_FOUND");if(r.status==="approved")throw new Error("RAPB_ALREADY_APPROVED");let a=typeof t=="string"?t:t.approvedBy,o={...r,status:"approved",approvedAt:A(),approvedBy:a,lastModified:A()};await this.dbAdapter.update(d.rapbPlans,e,o),await this.writeHistory("rapb_plans",e,"UPSERT",o);let i=await this.listRapbLines(e);return this.toRapbPlan(o,i)}async evaluateVariance(e){let t=await this.getRapb(e);if(!t)throw new Error("RAPB_NOT_FOUND");let r=await this.getTrialBalanceByScope({tenantId:t.tenantId,branchId:t.branchId,financeDomainId:t.financeDomainId,ledgerProfileId:t.ledgerProfileId}),a=new Map(r.map(u=>[u.accountId,u])),o=0,i=0,c=0,s=0,p=t.lines.map(u=>{let E=a.get(u.accountId),g=E?.debit??0,y=E?.credit??0,v=g-y;return u.accountType==="revenue"?(o+=u.budgetedCredit-u.budgetedDebit,i+=y-g):u.accountType==="expense"&&(c+=u.budgetedDebit-u.budgetedCredit,s+=g-y),{accountId:u.accountId,accountCode:u.accountCode,accountName:u.accountName,accountType:u.accountType,budgetedDebit:u.budgetedDebit,budgetedCredit:u.budgetedCredit,budgetedNet:u.budgetedNet,actualDebit:g,actualCredit:y,actualNet:v,varianceDebit:g-u.budgetedDebit,varianceCredit:y-u.budgetedCredit,varianceNet:v-u.budgetedNet}}),f=o-c,l=i-s;return{rapbId:e,periodCode:t.periodCode,evaluatedAt:A(),lines:p,totalBudgetedRevenue:o,totalActualRevenue:i,totalBudgetedExpense:c,totalActualExpense:s,budgetedNetIncome:f,actualNetIncome:l,netVariance:l-f}}async assertJournalLinesKnownAccounts(e){for(let t of e){let r=await this.dbAdapter.get(d.accounts,t.accountId);if(!r||r.deleted)throw new Error("JOURNAL_ACCOUNT_NOT_FOUND")}}async assertJournalPeriodOpen(e){let t=await this.dbAdapter.query(d.periods,{filters:{field:"deleted",value:!1}});if(t.length===0)return;let r=t.find(a=>!(a.tenantId!==e.tenantId||Date.parse(a.startDate)>Date.parse(e.occurredAt)||Date.parse(a.endDate)<Date.parse(e.occurredAt)||e.ledgerProfileId&&a.ledgerProfileId&&a.ledgerProfileId!==e.ledgerProfileId||e.financeDomainId&&a.financeDomainId&&a.financeDomainId!==e.financeDomainId));if(!r)throw new Error("FISCAL_PERIOD_NOT_FOUND_FOR_DATE");if(r.status!=="open")throw new Error("FISCAL_PERIOD_CLOSED")}async requireJournal(e){let t=await this.dbAdapter.get(d.journals,e);if(!t||t.deleted)throw new Error("JOURNAL_NOT_FOUND");return t}async listJournalLines(e){return(await this.dbAdapter.query(d.journalLines,{filters:{and:[{field:"journalId",value:e},{field:"deleted",value:!1}]}})).sort((r,a)=>r.id.localeCompare(a.id))}async listRapbLines(e){return(await this.dbAdapter.query(d.rapbLines,{filters:{and:[{field:"rapbId",value:e},{field:"deleted",value:!1}]}})).sort((r,a)=>r.id.localeCompare(a.id))}toJournalEntry(e,t){let{lastModified:r,deleted:a,...o}=e;return{...b(o),lines:t.map(i=>b(i))}}toPeriod(e){let{lastModified:t,deleted:r,...a}=e;return b(a)}toRapbPlan(e,t){let{lastModified:r,deleted:a,...o}=e;return{...b(o),lines:t.map(({id:i,rapbId:c,lastModified:s,deleted:p,...f})=>b(f))}}async writeHistory(e,t,r,a){let o=a,i={id:Me(e,t),tableName:e,recordId:t,action:r,changes:b(o),timestamp:A(),tenantId:typeof o.tenantId=="string"?o.tenantId:void 0,branchId:typeof o.branchId=="string"?o.branchId:void 0,financeDomainId:typeof o.financeDomainId=="string"?o.financeDomainId:void 0,ledgerProfileId:typeof o.ledgerProfileId=="string"?o.ledgerProfileId:void 0};await this.dbAdapter.create(d.histories,i)}};async function q(n){await N(n);let e=new M(n);return{financeService:Q({createAccount:e.createAccount.bind(e),listAccounts:e.listAccounts.bind(e),createJournalDraft:e.createJournalDraft.bind(e),postJournal:e.postJournal.bind(e),reverseJournal:e.reverseJournal.bind(e),listJournals:e.listJournals.bind(e),openFiscalPeriod:e.openFiscalPeriod.bind(e),closeFiscalPeriod:e.closeFiscalPeriod.bind(e),listFiscalPeriods:e.listFiscalPeriods.bind(e),getTrialBalance:e.getTrialBalance.bind(e),getTrialBalanceByScope:e.getTrialBalanceByScope.bind(e),createRapb:e.createRapb.bind(e),getRapb:e.getRapb.bind(e),listRapb:e.listRapb.bind(e),approveRapb:e.approveRapb.bind(e),evaluateVariance:e.evaluateVariance.bind(e),listOpenItems:e.listOpenItems.bind(e),getOpenItemAging:e.getOpenItemAging.bind(e),reconcileOpenItems:e.reconcileOpenItems.bind(e),listCashBankMovements:e.listCashBankMovements.bind(e),summarizeCashBankMovements:e.summarizeCashBankMovements.bind(e)})}}var B=class{constructor(e,t){this.runtime=e;this.runtimeStateStore=t;this.runtimeStore=(0,k.asReadonlyStore)(this.runtimeStateStore)}static builder(){return new J}get registry(){return this.runtime.registry}async start(e={}){this.runtimeStateStore.setState({phase:"starting",started:!1,lastError:null,lastTransitionAt:new Date().toISOString(),startCount:this.runtimeStateStore.getState().startCount,stopCount:this.runtimeStateStore.getState().stopCount});try{await this.runtime.start(e),this.domainServices=this.runtime.domainServices,this.runtimeStateStore.setState(t=>({...t,phase:"started",started:!0,startCount:t.startCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(t){throw this.runtimeStateStore.setState(r=>({...r,phase:"error",started:!1,lastError:t instanceof Error?t.message:String(t),lastTransitionAt:new Date().toISOString()})),t}}async stop(){this.runtimeStateStore.setState(e=>({...e,phase:"stopping",started:this.runtime.isStarted(),lastError:null,lastTransitionAt:new Date().toISOString()}));try{await this.runtime.stop(),this.runtimeStateStore.setState(e=>({...e,phase:"stopped",started:!1,stopCount:e.stopCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(e){throw this.runtimeStateStore.setState(t=>({...t,phase:"error",started:this.runtime.isStarted(),lastError:e instanceof Error?e.message:String(e),lastTransitionAt:new Date().toISOString()})),e}}isStarted(){return this.runtime.isStarted()}},J=class{constructor(){this.runtimeBuilder=se.CoreRuntime.builder();this.runtimeHooks={};this.runtimeBuilder.withDbAdapter(()=>new de.InMemoryDbAdapter)}withPlatformAdapter(e){return this.runtimeBuilder.withPlatformAdapter(e),this}withDbAdapter(e){return this.runtimeBuilder.withDbAdapter(e),this}withHttpAdapter(e){return this.runtimeBuilder.withHttpAdapter(e),this}withSocketAdapter(e){return this.runtimeBuilder.withSocketAdapter(e),this}withLoggerAdapter(e){return this.runtimeBuilder.withLoggerAdapter(e),this}withActivitySink(e){return this.runtimeBuilder.withActivitySink(e),this}withExtension(e,t){return this.runtimeBuilder.withExtension(e,t),this}withDomainServicesFactory(e){return this.domainServicesFactory=e,this}withRuntimeHooks(e){return this.runtimeHooks={...this.runtimeHooks,...e},this}build(){let e=(0,k.createStore)({phase:"idle",started:!1,startCount:0,stopCount:0,lastError:null,lastTransitionAt:new Date().toISOString()}),t={runMigrations:async a=>{let o=a.registry?.dbAdapter;if(!o)throw new Error("OFINANCE_DB_ADAPTER_REQUIRED");await N(o,a.registry?.loggerAdapter),this.runtimeHooks.runMigrations&&await this.runtimeHooks.runMigrations(a)},...this.runtimeHooks,createDomainServices:async a=>{if(this.domainServicesFactory)return this.domainServicesFactory();let o=a.registry?.dbAdapter;if(!o)throw new Error("OFINANCE_DB_ADAPTER_REQUIRED");return q(o)}};this.runtimeBuilder.withHooks(t);let r=this.runtimeBuilder.build();return new B(r,e)}};function $(n){return!Array.isArray(n.components)||n.components.length===0?[]:n.components.map(e=>{if(!e.accountId?.trim())throw new Error("FINANCE_TAX_ACCOUNT_REQUIRED");if(!Number.isFinite(e.amount)||e.amount<=0)throw new Error("FINANCE_TAX_AMOUNT_INVALID");if(e.direction!=="payable"&&e.direction!=="receivable")throw new Error("FINANCE_TAX_DIRECTION_INVALID");let t=`${n.memoPrefix??"Finance tax"} ${e.direction}`;return{accountId:e.accountId,debit:e.direction==="receivable"?e.amount:0,credit:e.direction==="payable"?e.amount:0,memo:e.memo??t}})}function h(n,e,t){return{id:n.journalId,tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,occurredAt:n.occurredAt,reference:t?`${n.reference??""}${t}`:n.reference,evidenceRef:n.evidenceRef,lines:e}}function S(n,e){if(!Number.isFinite(n)||n<=0)throw new Error(e)}function G(n,e){S(e.grossAmount,"POS_SALE_INVALID_GROSS_AMOUNT");let t=e.discountAmount??0,r=e.taxAmount??0;if(t<0||r<0)throw new Error("POS_SALE_NEGATIVE_COMPONENT");let a=e.grossAmount,o=a-t+r,i=[{accountId:e.paymentAccountId,debit:o,credit:0,memo:"POS sale payment"},{accountId:e.revenueAccountId,debit:0,credit:a,memo:"POS sale revenue"}];if(t>0){if(!e.discountAccountId)throw new Error("POS_SALE_DISCOUNT_ACCOUNT_REQUIRED");i.push({accountId:e.discountAccountId,debit:t,credit:0,memo:"POS sale discount"})}if(r>0){if(!e.taxPayableAccountId)throw new Error("POS_SALE_TAX_ACCOUNT_REQUIRED");i.push(...$({memoPrefix:"POS sale tax",components:[{accountId:e.taxPayableAccountId,amount:r,direction:"payable",memo:"POS sale tax payable"}]}))}return h(n,i)}function Y(n,e){return S(e.principalAmount,"COOP_LOAN_INVALID_PRINCIPAL"),h(n,[{accountId:e.receivableAccountId,debit:e.principalAmount,credit:0,memo:"Loan receivable principal"},{accountId:e.cashAccountId,debit:0,credit:e.principalAmount,memo:"Loan cash out"}])}function z(n,e){return S(e.amount,"COOP_SAVING_INVALID_AMOUNT"),h(n,[{accountId:e.cashAccountId,debit:e.amount,credit:0,memo:"Saving deposit cash in"},{accountId:e.savingLiabilityAccountId,debit:0,credit:e.amount,memo:"Saving liability increase"}])}function W(n,e){return S(e.amount,"COOP_SAVING_WITHDRAWAL_INVALID_AMOUNT"),h(n,[{accountId:e.savingLiabilityAccountId,debit:e.amount,credit:0,memo:"Saving liability decrease"},{accountId:e.cashAccountId,debit:0,credit:e.amount,memo:"Saving withdrawal cash out"}])}function X(n,e){S(e.principalAmount,"COOP_LOAN_REPAYMENT_INVALID_PRINCIPAL");let t=e.serviceAmount??0,r=e.penaltyAmount??0;if(t<0||r<0)throw new Error("COOP_LOAN_REPAYMENT_NEGATIVE_COMPONENT");if(t>0&&!e.serviceRevenueAccountId)throw new Error("COOP_LOAN_REPAYMENT_SERVICE_ACCOUNT_REQUIRED");if(r>0&&!e.penaltyRevenueAccountId)throw new Error("COOP_LOAN_REPAYMENT_PENALTY_ACCOUNT_REQUIRED");let a=e.principalAmount+t+r,o=[{accountId:e.cashAccountId,debit:a,credit:0,memo:"Loan repayment cash in"},{accountId:e.receivableAccountId,debit:0,credit:e.principalAmount,memo:"Loan receivable principal repayment"}];return t>0&&o.push({accountId:e.serviceRevenueAccountId,debit:0,credit:t,memo:"Loan service revenue"}),r>0&&o.push({accountId:e.penaltyRevenueAccountId,debit:0,credit:r,memo:"Loan penalty revenue"}),h(n,o)}function Je(n,e){if(S(e.amount,"COOP_SHU_PARTICIPATION_INVALID_AMOUNT"),!n.evidenceRef?.trim())throw new Error("COOP_SHU_PARTICIPATION_EVIDENCE_REQUIRED");return h(n,[{accountId:e.debitAccountId,debit:e.amount,credit:0,memo:e.memo??"Coop SHU participation manual recap debit"},{accountId:e.creditAccountId,debit:0,credit:e.amount,memo:e.memo??"Coop SHU participation manual recap credit"}])}function ue(n,e){return e?{...n,...e}:{...n}}function C(n){let e=n.tenantId?n.scopedMapping.byTenant?.[n.tenantId]:void 0,t=n.tenantId&&n.branchId?`${n.tenantId}:${n.branchId}`:"",r=t?n.scopedMapping.byBranch?.[t]:void 0;return ue(ue(n.scopedMapping.default,e),r)}function K(n){return C(n)}function Z(n){return C(n)}function ee(n){return C(n)}function ne(n){return C(n)}function te(n){return C(n)}function ke(n,e){let{scopedAccountMapping:t,...r}=e,a=K({tenantId:n.tenantId,branchId:n.branchId,scopedMapping:t});return G(n,{...r,...a})}function je(n,e){let{scopedAccountMapping:t,...r}=e,a=Z({tenantId:n.tenantId,branchId:n.branchId,scopedMapping:t});return Y(n,{...r,...a})}function Ue(n,e){let{scopedAccountMapping:t,...r}=e,a=ne({tenantId:n.tenantId,branchId:n.branchId,scopedMapping:t});return z(n,{...r,...a})}function Ve(n,e){let{scopedAccountMapping:t,...r}=e,a=te({tenantId:n.tenantId,branchId:n.branchId,scopedMapping:t});return W(n,{...r,...a})}function He(n,e){let{scopedAccountMapping:t,...r}=e,a=ee({tenantId:n.tenantId,branchId:n.branchId,scopedMapping:t});return X(n,{...r,...a})}function j(n){return!!(n&&typeof n=="object"&&n.error)}function re(n){return n.startsWith("ofinance_")?`offinance_${n.slice(9)}`:n}async function Qe(n,e,t){let r=await n.accountService.listAccounts();if(j(r))throw new Error(r.error.message||r.error.code||"FINANCE_ACCOUNT_LIST_FAILED");let a=new Set((r.data||[]).map(o=>o.id));for(let o of e){if(a.has(o.id))continue;let i=await n.accountService.createAccount(o);if(j(i))throw new Error(i.error.message||i.error.code||"FINANCE_ACCOUNT_CREATE_FAILED");await t?.({changeId:`offinance:account:${o.id}`,entity:"FinanceAccount",table:re(d.accounts),type:"CREATE",data:o})}}async function pe(n,e,t){return n.query(e,{filters:{and:t}})}async function qe(n,e,t){if(!t)return;let r=await pe(n,d.journals,[{field:"id",value:e.id}]),a=await pe(n,d.journalLines,[{field:"journalId",value:e.id}]);r.length===0&&(r=[{id:e.id,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,occurredAt:e.occurredAt,reference:e.reference,status:e.status,postedAt:e.postedAt,lastModified:e.postedAt||e.occurredAt,deleted:!1}]),a.length===0&&(a=e.lines.map((o,i)=>({id:`${e.id}:line:${i}`,journalId:e.id,accountId:o.accountId,debit:o.debit,credit:o.credit,memo:o.memo,openItemId:o.openItemId,openItemType:o.openItemType,counterpartyRef:o.counterpartyRef,documentRef:o.documentRef,dueAt:o.dueAt,tenantId:e.tenantId,branchId:e.branchId,financeDomainId:e.financeDomainId,ledgerProfileId:e.ledgerProfileId,lastModified:e.postedAt||e.occurredAt,deleted:!1})));for(let o of r)await t({changeId:`offinance:journal:${o.id}`,entity:"FinanceJournalEntry",table:re(d.journals),type:"CREATE",data:o});for(let o of a)await t({changeId:`offinance:journal-line:${o.id}`,entity:"FinanceJournalLine",table:re(d.journalLines),type:"CREATE",data:o})}function $e(n){return async e=>{let t=n.resolveFinanceServices();if(!t)throw new Error(n.missingServicesErrorCode||"FINANCE_SERVICES_UNAVAILABLE");let r=n.resolveLedgerProfileId().trim();if(!r)throw new Error(n.missingLedgerProfileErrorCode||"FINANCE_LEDGER_PROFILE_REQUIRED");let a=n.resolveSyncEnqueuer?.()??null;await Qe(t,n.requiredAccounts,a);let o=n.buildJournalDraft(e,r),i=await t.journalService.createJournalDraft(o);if(j(i)&&i.error.code!=="JOURNAL_ALREADY_EXISTS")throw new Error(i.error.message||i.error.code||"FINANCE_JOURNAL_CREATE_FAILED");let c=await t.journalService.postJournal(o.id,o.occurredAt);if(j(c))throw new Error(c.error.message||c.error.code||"FINANCE_JOURNAL_POST_FAILED");await qe(n.dbAdapter,c.data,a)}}function Ge(n){switch(n.accountType){case"asset":case"expense":return n.debit-n.credit;case"liability":case"equity":case"revenue":return n.credit-n.debit;default:return 0}}function L(n,e){return n.filter(t=>t.accountType===e).reduce((t,r)=>t+Ge(r),0)}function Ye(n){let e=L(n,"revenue"),t=L(n,"expense");return{revenue:e,expense:t,netIncome:e-t}}function ze(n){return{assets:L(n,"asset"),liabilities:L(n,"liability"),equity:L(n,"equity")}}function le(n){return n.accountType==="revenue"?n.credit-n.debit:n.accountType==="expense"?n.debit-n.credit:0}function We(n){let e=n.filter(r=>r.accountType==="revenue").reduce((r,a)=>r+Math.max(0,le(a)),0),t=n.filter(r=>r.accountType==="expense").reduce((r,a)=>r+Math.max(0,le(a)),0);return{operatingInflow:e,operatingOutflow:t,netOperatingCashflow:e-t}}function Xe(n,e){let t=[],r=0;for(let a of e){if(a.accountType==="revenue"){let o=a.credit-a.debit;o>0&&(t.push({accountId:a.accountId,debit:o,credit:0,memo:"Close revenue account"}),r+=o)}if(a.accountType==="expense"){let o=a.debit-a.credit;o>0&&(t.push({accountId:a.accountId,debit:0,credit:o,memo:"Close expense account"}),r-=o)}}return r>0?t.push({accountId:n.retainedEarningsAccountId,debit:0,credit:r,memo:"Retained earnings from period close"}):r<0&&t.push({accountId:n.retainedEarningsAccountId,debit:Math.abs(r),credit:0,memo:"Retained earnings from period close"}),{id:n.journalId,tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,occurredAt:n.occurredAt,reference:n.reference,lines:t}}function Ke(n){return Array.isArray(n)?n.length:n&&typeof n=="object"?1:n===null||typeof n>"u"?0:1}function Ze(n){return n==="json"?"application/json":"text/csv"}function en(n,e){if(n==="json")return`${JSON.stringify(e,null,2)}
2
+ `;if(typeof e!="string")throw new Error("FINANCE_COMPLIANCE_EXPORT_CSV_PAYLOAD_STRING_REQUIRED");return e}function nn(n){let e=2166136261;for(let t=0;t<n.length;t+=1)e^=n.charCodeAt(t),e=Math.imul(e,16777619);return`fnv1a32-${(e>>>0).toString(16).padStart(8,"0")}`}function tn(n){if(!n.key?.trim())throw new Error("FINANCE_COMPLIANCE_EXPORT_DATASET_KEY_REQUIRED");if(!n.fileName?.trim())throw new Error("FINANCE_COMPLIANCE_EXPORT_FILE_NAME_REQUIRED");if(n.format!=="json"&&n.format!=="csv")throw new Error("FINANCE_COMPLIANCE_EXPORT_FORMAT_INVALID")}function rn(n){return n??"custom"}function ae(n){if(!Array.isArray(n.datasets)||n.datasets.length===0)throw new Error("FINANCE_COMPLIANCE_EXPORT_DATASETS_REQUIRED");let e=new Set,t={},r=[];for(let o of n.datasets){if(tn(o),e.has(o.key))throw new Error("FINANCE_COMPLIANCE_EXPORT_DATASET_KEY_DUPLICATE");e.add(o.key);let i=en(o.format,o.payload);t[o.fileName]=i,r.push({key:o.key,fileName:o.fileName,format:o.format,semantic:rn(o.semantic),contentType:o.contentType??Ze(o.format),recordCount:Ke(o.payload),checksum:nn(i)})}return{contract:{contractVersion:"fcx-v1",tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,generatedAt:n.generatedAt??new Date().toISOString(),period:{from:n.period?.from??null,to:n.period?.to??null,label:n.period?.label??null},currency:{baseCurrencyCode:n.baseCurrencyCode??"IDR"},datasets:r,summary:{datasetCount:r.length,totalRecordCount:r.reduce((o,i)=>o+i.recordCount,0)}},files:t}}function an(n){return{version:"v1",generatedAt:n.generatedAt??new Date().toISOString(),payload:{trialBalance:n.trialBalance.map(e=>({...e})),incomeStatement:{...n.incomeStatement},balanceSheet:{...n.balanceSheet}}}}function on(n){let e=[{key:"trial-balance",fileName:"trial_balance.json",format:"json",semantic:"trial_balance",payload:n.trialBalance},{key:"income-statement",fileName:"income_statement.json",format:"json",semantic:"income_statement",payload:n.incomeStatement},{key:"balance-sheet",fileName:"balance_sheet.json",format:"json",semantic:"balance_sheet",payload:n.balanceSheet}];return typeof n.openItems<"u"&&e.push({key:"open-items",fileName:"open_items.json",format:"json",semantic:"open_items",payload:n.openItems}),typeof n.agingSummary<"u"&&e.push({key:"aging-summary",fileName:"aging_summary.json",format:"json",semantic:"aging_summary",payload:n.agingSummary}),typeof n.reconciliationSummary<"u"&&e.push({key:"reconciliation-summary",fileName:"reconciliation_summary.json",format:"json",semantic:"reconciliation",payload:n.reconciliationSummary}),typeof n.cashMovements<"u"&&e.push({key:"cash-movements",fileName:"cash_movements.json",format:"json",semantic:"cash_movements",payload:n.cashMovements}),ae({tenantId:n.tenantId,branchId:n.branchId,financeDomainId:n.financeDomainId,ledgerProfileId:n.ledgerProfileId,generatedAt:n.generatedAt,period:n.period,baseCurrencyCode:n.baseCurrencyCode,datasets:e})}function cn(n){return n.accountType==="revenue"?n.credit-n.debit:n.accountType==="expense"?n.debit-n.credit:0}function me(n,e){return e===0?n===0?1:0:Number((n/e).toFixed(4))}function sn(n,e){let t=e.map(a=>{let c=((a.accountCodes?.length?n.filter(p=>a.accountCodes?.includes(p.accountCode)):null)??n.filter(p=>a.accountType?p.accountType===a.accountType:!1)).reduce((p,f)=>p+cn(f),0),s=c-a.plannedAmount;return{id:a.id,label:a.label,plannedAmount:a.plannedAmount,actualAmount:c,varianceAmount:s,achievementRatio:me(c,a.plannedAmount)}}),r=t.reduce((a,o)=>(a.plannedAmount+=o.plannedAmount,a.actualAmount+=o.actualAmount,a.varianceAmount+=o.varianceAmount,a),{plannedAmount:0,actualAmount:0,varianceAmount:0});return{rows:t,totals:{...r,achievementRatio:me(r.actualAmount,r.plannedAmount)}}}function Ie(n,e){switch(e.type){case"finance.account.created":n.createAccount(e.payload);return;case"finance.period.opened":n.openFiscalPeriod(e.payload);return;case"finance.period.closed":n.closeFiscalPeriod(e.payload.periodId);return;case"finance.journal.drafted":n.createJournalDraft(e.payload);return;case"finance.journal.posted":n.postJournal(e.payload.journalId,e.payload.postedAt);return;case"finance.journal.reversed":n.reverseJournal(e.payload.journalId,e.payload.reversalId);return;default:throw new Error("FINANCE_EVENT_UNSUPPORTED")}}function dn(n){let e=new T;for(let t of n)Ie(e,t);return e}var fe=[{id:"coa-cash",code:"1101",name:"Kas",type:"asset"},{id:"coa-bank",code:"1102",name:"Bank",type:"asset"},{id:"coa-ar",code:"1201",name:"Piutang Usaha",type:"asset"},{id:"coa-ap",code:"2101",name:"Utang Usaha",type:"liability"},{id:"coa-retained",code:"3201",name:"Laba Ditahan",type:"equity"},{id:"coa-revenue",code:"4101",name:"Pendapatan Operasional",type:"revenue"},{id:"coa-expense",code:"5101",name:"Biaya Operasional",type:"expense"}];function un(n="IDR"){return fe.map(e=>({id:e.id,code:e.code,name:e.name,type:e.type,currency:n,isActive:!0}))}var ge=[{id:"coop-coa-cash",code:"1101",name:"Kas",type:"asset"},{id:"coop-coa-bank",code:"1102",name:"Bank",type:"asset"},{id:"coop-coa-loan-ar",code:"1201",name:"Piutang Pinjaman Anggota",type:"asset"},{id:"coop-coa-other-ar",code:"1202",name:"Piutang Lain-lain",type:"asset"},{id:"coop-coa-prepaid",code:"1301",name:"Biaya Dibayar Dimuka",type:"asset"},{id:"coop-coa-fixed-asset",code:"1401",name:"Aset Tetap",type:"asset"},{id:"coop-coa-accum-depr",code:"1402",name:"Akumulasi Penyusutan",type:"asset"},{id:"coop-coa-simp-pokok",code:"2101",name:"Simpanan Pokok",type:"liability"},{id:"coop-coa-simp-wajib",code:"2102",name:"Simpanan Wajib",type:"liability"},{id:"coop-coa-simp-sukarela",code:"2103",name:"Simpanan Sukarela",type:"liability"},{id:"coop-coa-simp-berjangka",code:"2104",name:"Simpanan Berjangka",type:"liability"},{id:"coop-coa-ap",code:"2201",name:"Utang Usaha",type:"liability"},{id:"coop-coa-ext-loan",code:"2301",name:"Pinjaman Luar",type:"liability"},{id:"coop-coa-tax-payable",code:"2401",name:"Utang Pajak",type:"liability"},{id:"coop-coa-modal-awal",code:"3101",name:"Modal Awal",type:"equity"},{id:"coop-coa-cadangan-umum",code:"3201",name:"Dana Cadangan Umum",type:"equity"},{id:"coop-coa-cadangan-tujuan",code:"3202",name:"Dana Cadangan Tujuan",type:"equity"},{id:"coop-coa-shu-prior",code:"3301",name:"SHU Tahun Lalu",type:"equity"},{id:"coop-coa-shu-current",code:"3302",name:"SHU Berjalan",type:"equity"},{id:"coop-coa-shu-reserve",code:"3303",name:"Dana SHU Belum Dibagi",type:"equity"},{id:"coop-coa-jasa-pinjaman",code:"4101",name:"Pendapatan Jasa Pinjaman",type:"revenue"},{id:"coop-coa-provisi",code:"4102",name:"Pendapatan Provisi",type:"revenue"},{id:"coop-coa-rev-other",code:"4103",name:"Pendapatan Lain-lain",type:"revenue"},{id:"coop-coa-beban-bunga",code:"5101",name:"Beban Bunga Simpanan",type:"expense"},{id:"coop-coa-beban-ops",code:"5102",name:"Beban Operasional",type:"expense"},{id:"coop-coa-beban-gaji",code:"5103",name:"Beban Gaji dan Tunjangan",type:"expense"},{id:"coop-coa-beban-admin",code:"5104",name:"Beban Administrasi",type:"expense"},{id:"coop-coa-beban-depr",code:"5105",name:"Beban Penyusutan",type:"expense"},{id:"coop-coa-prov-kredit",code:"5106",name:"Cadangan Kerugian Piutang",type:"expense"}];function pn(n="IDR"){return ge.map(e=>({id:e.id,code:e.code,name:e.name,type:e.type,currency:n,isActive:!0}))}function ln(n){let e=new Set,t=new Set;for(let r of n){if(!r.id||!r.code||!r.name)return{ok:!1,reason:"COA_REQUIRED_FIELDS"};if(e.has(r.id))return{ok:!1,reason:"COA_DUPLICATE_ID"};if(t.has(r.code))return{ok:!1,reason:"COA_DUPLICATE_CODE"};e.add(r.id),t.add(r.code)}return{ok:!0}}
2
3
  /*! For license information please see index.js.LEGAL.txt */
@@ -0,0 +1,4 @@
1
+ import type { FinanceJournalEntry } from '../contracts/JournalContract.js';
2
+ import type { FinanceCashBankMovementEntry, FinanceCashBankMovementScope, FinanceCashBankMovementSummary } from '../contracts/CashMovementContract.js';
3
+ export declare function projectFinanceCashBankMovements(journals: FinanceJournalEntry[], scope: FinanceCashBankMovementScope): FinanceCashBankMovementEntry[];
4
+ export declare function summarizeFinanceCashBankMovements(entries: FinanceCashBankMovementEntry[]): FinanceCashBankMovementSummary;
@@ -0,0 +1,11 @@
1
+ import type { FinanceComplianceExportBundle, FinanceComplianceExportDatasetInput, FinanceComplianceExportPeriod } from '../contracts/ComplianceExportContract.js';
2
+ export declare function buildFinanceComplianceExportBundle(params: {
3
+ tenantId?: string;
4
+ branchId?: string;
5
+ financeDomainId?: string;
6
+ ledgerProfileId?: string;
7
+ generatedAt?: string;
8
+ period?: Partial<FinanceComplianceExportPeriod>;
9
+ baseCurrencyCode?: string;
10
+ datasets: FinanceComplianceExportDatasetInput[];
11
+ }): FinanceComplianceExportBundle;
@@ -1,5 +1,6 @@
1
1
  import type { BalanceSheet, IncomeStatement } from './financialStatements.js';
2
2
  import type { TrialBalanceRow } from '../contracts/FiscalContract.js';
3
+ import { buildFinanceComplianceExportBundle } from './complianceExport.js';
3
4
  export interface FinanceExportEnvelope {
4
5
  version: 'v1';
5
6
  generatedAt: string;
@@ -15,3 +16,23 @@ export declare function buildFinanceExportEnvelope(params: {
15
16
  balanceSheet: BalanceSheet;
16
17
  generatedAt?: string;
17
18
  }): FinanceExportEnvelope;
19
+ export declare function buildFinanceOperationalComplianceBundle(params: {
20
+ tenantId?: string;
21
+ branchId?: string;
22
+ financeDomainId?: string;
23
+ ledgerProfileId?: string;
24
+ generatedAt?: string;
25
+ period?: {
26
+ from?: string | null;
27
+ to?: string | null;
28
+ label?: string | null;
29
+ };
30
+ baseCurrencyCode?: string;
31
+ trialBalance: TrialBalanceRow[];
32
+ incomeStatement: IncomeStatement;
33
+ balanceSheet: BalanceSheet;
34
+ openItems?: unknown[];
35
+ agingSummary?: unknown;
36
+ reconciliationSummary?: unknown;
37
+ cashMovements?: unknown[];
38
+ }): ReturnType<typeof buildFinanceComplianceExportBundle>;
@@ -0,0 +1,10 @@
1
+ import type { FinanceJournalEntry } from '../contracts/JournalContract.js';
2
+ import type { FinanceOpenItemAgingBucketResult, FinanceOpenItemAgingQuery, FinanceOpenItemPosition, FinanceOpenItemScope, FinanceOpenItemType } from '../contracts/OpenItemContract.js';
3
+ export declare function validateOpenItemLineMetadata(lines: FinanceJournalEntry['lines']): void;
4
+ export declare function projectFinanceOpenItems(journals: FinanceJournalEntry[], scope?: FinanceOpenItemScope): FinanceOpenItemPosition[];
5
+ export declare function buildFinanceOpenItemAging(items: FinanceOpenItemPosition[], query: FinanceOpenItemAgingQuery): {
6
+ asOf: string;
7
+ openItemType?: FinanceOpenItemType;
8
+ totalOutstanding: number;
9
+ buckets: FinanceOpenItemAgingBucketResult[];
10
+ };
@@ -0,0 +1,3 @@
1
+ import type { FinanceOpenItemReconciliationInput, FinanceOpenItemReconciliationSummary } from '../contracts/ReconciliationContract.js';
2
+ import type { FinanceOpenItemPosition } from '../contracts/OpenItemContract.js';
3
+ export declare function reconcileFinanceOpenItems(expectedItems: FinanceOpenItemPosition[], input: FinanceOpenItemReconciliationInput): FinanceOpenItemReconciliationSummary;
@@ -3,6 +3,9 @@ import type { FinanceAccount } from '../contracts/AccountContract.js';
3
3
  import type { CreateRapbInput, RapbPlan, RapbVariance } from '../contracts/BudgetContract.js';
4
4
  import type { FinanceLedgerScope, FiscalPeriod, TrialBalanceRow } from '../contracts/FiscalContract.js';
5
5
  import type { FinanceJournalEntry, JournalDraftInput } from '../contracts/JournalContract.js';
6
+ import type { FinanceOpenItemAgingQuery, FinanceOpenItemAgingSummary, FinanceOpenItemPosition, FinanceOpenItemScope } from '../contracts/OpenItemContract.js';
7
+ import type { FinanceOpenItemReconciliationInput, FinanceOpenItemReconciliationSummary } from '../contracts/ReconciliationContract.js';
8
+ import type { FinanceCashBankMovementEntry, FinanceCashBankMovementScope, FinanceCashBankMovementSummary } from '../contracts/CashMovementContract.js';
6
9
  export declare class DbAdapterOffinanceService {
7
10
  private readonly dbAdapter;
8
11
  constructor(dbAdapter: DbAdapter);
@@ -12,6 +15,11 @@ export declare class DbAdapterOffinanceService {
12
15
  postJournal(journalId: string, postedAt?: string): Promise<FinanceJournalEntry>;
13
16
  reverseJournal(journalId: string, reversalId: string): Promise<FinanceJournalEntry>;
14
17
  listJournals(scope?: FinanceLedgerScope): Promise<FinanceJournalEntry[]>;
18
+ listOpenItems(scope?: FinanceOpenItemScope): Promise<FinanceOpenItemPosition[]>;
19
+ getOpenItemAging(query: FinanceOpenItemAgingQuery): Promise<FinanceOpenItemAgingSummary>;
20
+ reconcileOpenItems(input: FinanceOpenItemReconciliationInput): Promise<FinanceOpenItemReconciliationSummary>;
21
+ listCashBankMovements(scope: FinanceCashBankMovementScope): Promise<FinanceCashBankMovementEntry[]>;
22
+ summarizeCashBankMovements(scope: FinanceCashBankMovementScope): Promise<FinanceCashBankMovementSummary>;
15
23
  openFiscalPeriod(period: FiscalPeriod): Promise<FiscalPeriod>;
16
24
  closeFiscalPeriod(periodId: string): Promise<FiscalPeriod>;
17
25
  listFiscalPeriods(): Promise<FiscalPeriod[]>;
@@ -2,6 +2,9 @@ import type { FinanceAccount, FinanceAccountServiceContractV2 } from '../contrac
2
2
  import type { RapbServiceContractV2 } from '../contracts/BudgetContract.js';
3
3
  import type { FinanceLedgerScope, FiscalPeriod, FiscalPeriodServiceContractV2 } from '../contracts/FiscalContract.js';
4
4
  import type { FinanceJournalServiceContractV2, JournalDraftInput } from '../contracts/JournalContract.js';
5
+ import type { FinanceOpenItemAgingQuery, FinanceOpenItemServiceContractV2, FinanceOpenItemScope } from '../contracts/OpenItemContract.js';
6
+ import type { FinanceOpenItemReconciliationInput, FinanceReconciliationServiceContractV2 } from '../contracts/ReconciliationContract.js';
7
+ import type { FinanceCashBankMovementScope, FinanceCashBankMovementServiceContractV2 } from '../contracts/CashMovementContract.js';
5
8
  export interface OffinanceLegacyServices {
6
9
  accountService: {
7
10
  createAccount(account: FinanceAccount): FinanceAccount | Promise<FinanceAccount>;
@@ -29,12 +32,26 @@ export interface OffinanceLegacyServices {
29
32
  }): any | Promise<any>;
30
33
  evaluateVariance(rapbId: string): any | Promise<any>;
31
34
  };
35
+ openItemService: {
36
+ listOpenItems(scope?: FinanceOpenItemScope): any[] | Promise<any[]>;
37
+ getOpenItemAging(query: FinanceOpenItemAgingQuery): any | Promise<any>;
38
+ };
39
+ reconciliationService: {
40
+ reconcileOpenItems(input: FinanceOpenItemReconciliationInput): any | Promise<any>;
41
+ };
42
+ cashMovementService: {
43
+ listCashBankMovements(scope: FinanceCashBankMovementScope): any[] | Promise<any[]>;
44
+ summarizeCashBankMovements(scope: FinanceCashBankMovementScope): any | Promise<any>;
45
+ };
32
46
  }
33
47
  export interface OffinanceEnvelopeServices {
34
48
  accountService: FinanceAccountServiceContractV2;
35
49
  journalService: FinanceJournalServiceContractV2;
36
50
  fiscalService: FiscalPeriodServiceContractV2;
37
51
  rapbService: RapbServiceContractV2;
52
+ openItemService: FinanceOpenItemServiceContractV2;
53
+ reconciliationService: FinanceReconciliationServiceContractV2;
54
+ cashMovementService: FinanceCashBankMovementServiceContractV2;
38
55
  }
39
56
  export declare class OffinanceEnvelopeService implements OffinanceEnvelopeServices {
40
57
  private readonly legacy;
@@ -42,6 +59,9 @@ export declare class OffinanceEnvelopeService implements OffinanceEnvelopeServic
42
59
  readonly journalService: FinanceJournalServiceContractV2;
43
60
  readonly fiscalService: FiscalPeriodServiceContractV2;
44
61
  readonly rapbService: RapbServiceContractV2;
62
+ readonly openItemService: FinanceOpenItemServiceContractV2;
63
+ readonly reconciliationService: FinanceReconciliationServiceContractV2;
64
+ readonly cashMovementService: FinanceCashBankMovementServiceContractV2;
45
65
  constructor(legacy: OffinanceLegacyServices);
46
66
  }
47
67
  export declare function createOffinanceEnvelopeService(legacyService: {
@@ -63,4 +83,9 @@ export declare function createOffinanceEnvelopeService(legacyService: {
63
83
  approvedBy: string;
64
84
  }): any | Promise<any>;
65
85
  evaluateVariance(rapbId: string): any | Promise<any>;
86
+ listOpenItems(scope?: FinanceOpenItemScope): any[] | Promise<any[]>;
87
+ getOpenItemAging(query: FinanceOpenItemAgingQuery): any | Promise<any>;
88
+ reconcileOpenItems(input: FinanceOpenItemReconciliationInput): any | Promise<any>;
89
+ listCashBankMovements(scope: FinanceCashBankMovementScope): any[] | Promise<any[]>;
90
+ summarizeCashBankMovements(scope: FinanceCashBankMovementScope): any | Promise<any>;
66
91
  }): OffinanceEnvelopeServices;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "offinance-shared-core",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.3",
4
4
  "private": false,
5
5
  "description": "Offline-first platform-agnostic db-agnostic finance shared core",
6
6
  "author": {