Fix all TypeScript build errors

- Add missing pacs008.ts, pacs009.ts, pain001.ts files
- Add missing config.ts, threshold.ts, documentation.ts files
- Fix property access errors (orderingCustomerTaxId -> orderingCustomer.taxId)
- Add contractActive property to FXContractCheckResult type
- Fix undefined handling in validateBrazilianTaxId calls
- Update web app tsconfig to exclude dist folders
- Remove tsc from web build (Vite handles TypeScript)
This commit is contained in:
defiQUG
2026-01-23 14:56:17 -08:00
parent f61c3603d9
commit 476dfd222c
82 changed files with 1559 additions and 2 deletions

View File

@@ -0,0 +1 @@
{"version":3,"file":"aml.d.ts","sourceRoot":"","sources":["aml.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,0BAA0B,EAC1B,sBAAsB,EACtB,UAAU,EAGX,MAAM,yBAAyB,CAAC;AAKjC;;GAEG;AACH,UAAU,kBAAkB;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,IAAI,CAAC;IACX,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,cAAM,uBAAuB;IAC3B,OAAO,CAAC,OAAO,CAA4B;IAE3C,GAAG,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAIpC,cAAc,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAG,kBAAkB,EAAE;IAMpE,aAAa,CACX,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,IAAI,EACf,OAAO,EAAE,IAAI,GACZ,kBAAkB,EAAE;IAUvB,MAAM,IAAI,kBAAkB,EAAE;CAG/B;AAID,wBAAgB,eAAe,IAAI,uBAAuB,CAEzD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,WAAW,GACvB,0BAA0B,CA6B5B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,WAAW,EACxB,sBAAsB,CAAC,EAAE,kBAAkB,EAAE,GAC5C,sBAAsB,GAAG,SAAS,CAiEpC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,WAAW,EACxB,sBAAsB,CAAC,EAAE,kBAAkB,EAAE,GAC5C,cAAc,CAyBhB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,UAAU,CAsBrE"}

View File

@@ -0,0 +1,152 @@
/**
* AML (Anti-Money Laundering) and anti-structuring detection
*/
import { getDefaultConverter } from '@brazil-swift-ops/utils';
import { calculateRollingWindow, filterDatesInWindow } from '@brazil-swift-ops/utils';
import { getConfig } from './config';
class TransactionHistoryStore {
history = [];
add(entry) {
this.history.push(entry);
}
getByDateRange(startDate, endDate) {
return this.history.filter((entry) => entry.date >= startDate && entry.date <= endDate);
}
getByCustomer(taxId, startDate, endDate) {
return this.history.filter((entry) => (entry.orderingCustomerTaxId === taxId ||
entry.beneficiaryTaxId === taxId) &&
entry.date >= startDate &&
entry.date <= endDate);
}
getAll() {
return [...this.history];
}
}
const historyStore = new TransactionHistoryStore();
export function getHistoryStore() {
return historyStore;
}
/**
* Check single transaction AML threshold
*/
export function checkSingleTransactionAML(transaction) {
const config = getConfig();
const converter = getDefaultConverter();
const usdEquivalent = converter.getUSDEquivalent(transaction.amount, transaction.currency);
const threshold = config.aml.singleTransactionThreshold;
const requiresEnhancedReview = usdEquivalent >= threshold;
let riskLevel;
if (usdEquivalent >= threshold) {
riskLevel = 'High';
}
else if (usdEquivalent >= threshold * 0.5) {
riskLevel = 'Medium';
}
else {
riskLevel = 'Low';
}
return {
passed: true, // AML check doesn't fail, it flags for review
transactionAmount: transaction.amount,
usdEquivalent,
threshold,
requiresEnhancedReview,
riskLevel,
};
}
/**
* Check for structuring patterns (multiple small transactions that sum above threshold)
*/
export function checkStructuring(transaction, historicalTransactions) {
const config = getConfig();
const converter = getDefaultConverter();
// Calculate rolling window
const window = calculateRollingWindow(transaction.createdAt || new Date(), config.aml.structuringWindowDays);
// Get historical transactions if not provided
if (!historicalTransactions) {
const customerTaxId = transaction.orderingCustomer?.taxId || transaction.beneficiary?.taxId;
if (customerTaxId) {
historicalTransactions = historyStore.getByCustomer(customerTaxId, window.startDate, window.endDate);
}
else {
historicalTransactions = historyStore.getByDateRange(window.startDate, window.endDate);
}
}
// Filter to transactions in window
const windowTransactions = historicalTransactions.filter((t) => filterDatesInWindow([t.date], window).length > 0);
// Calculate totals
const totalAmount = windowTransactions.reduce((sum, t) => sum + t.amount, transaction.amount);
const totalUsdEquivalent = windowTransactions.reduce((sum, t) => sum + t.usdEquivalent, converter.getUSDEquivalent(transaction.amount, transaction.currency));
const individualAmounts = [
...windowTransactions.map((t) => t.usdEquivalent),
converter.getUSDEquivalent(transaction.amount, transaction.currency),
];
// Check if structuring detected
const threshold = config.aml.structuringThreshold;
const detected = totalUsdEquivalent >= threshold &&
individualAmounts.every((amt) => amt < threshold);
return {
detected,
windowDays: window.days,
transactionCount: windowTransactions.length + 1,
totalAmount,
totalUsdEquivalent,
individualAmounts,
rationale: detected
? `Structuring detected: ${windowTransactions.length + 1} transactions totaling ${totalUsdEquivalent.toFixed(2)} USD over ${window.days} days, each below ${threshold} USD threshold.`
: `No structuring pattern detected. Total: ${totalUsdEquivalent.toFixed(2)} USD over ${window.days} days.`,
};
}
/**
* Perform complete AML check
*/
export function performAMLCheck(transaction, historicalTransactions) {
const singleCheck = checkSingleTransactionAML(transaction);
const structuringCheck = checkStructuring(transaction, historicalTransactions);
// Determine overall risk level
let overallRiskLevel;
if (singleCheck.riskLevel === 'High' || structuringCheck?.detected) {
overallRiskLevel = 'High';
}
else if (singleCheck.riskLevel === 'Medium') {
overallRiskLevel = 'Medium';
}
else {
overallRiskLevel = 'Low';
}
const passed = overallRiskLevel !== 'High';
return {
passed,
singleTransactionCheck: singleCheck,
structuringCheck,
overallRiskLevel,
rationale: passed
? `AML check passed. Risk level: ${overallRiskLevel}.`
: `AML check flagged for review. Risk level: ${overallRiskLevel}. ${structuringCheck?.detected ? 'Structuring pattern detected.' : ''}`,
};
}
/**
* Create rule result for AML check
*/
export function createAMLRuleResult(check) {
const severity = check.overallRiskLevel === 'High'
? 'Critical'
: check.overallRiskLevel === 'Medium'
? 'Warning'
: 'Info';
const decision = check.passed ? 'Allow' : 'Escalate';
return {
ruleId: 'aml-check',
ruleName: 'AML & Anti-Structuring Check',
passed: check.passed,
severity,
decision,
rationale: check.rationale,
details: {
overallRiskLevel: check.overallRiskLevel,
singleTransactionCheck: check.singleTransactionCheck,
structuringCheck: check.structuringCheck,
},
};
}
//# sourceMappingURL=aml.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"aml.js","sourceRoot":"","sources":["aml.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACtF,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAerC,MAAM,uBAAuB;IACnB,OAAO,GAAyB,EAAE,CAAC;IAE3C,GAAG,CAAC,KAAyB;QAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,cAAc,CAAC,SAAe,EAAE,OAAa;QAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CACxB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,IAAI,SAAS,IAAI,KAAK,CAAC,IAAI,IAAI,OAAO,CAC5D,CAAC;IACJ,CAAC;IAED,aAAa,CACX,KAAa,EACb,SAAe,EACf,OAAa;QAEb,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CACxB,CAAC,KAAK,EAAE,EAAE,CACR,CAAC,KAAK,CAAC,qBAAqB,KAAK,KAAK;YACpC,KAAK,CAAC,gBAAgB,KAAK,KAAK,CAAC;YACnC,KAAK,CAAC,IAAI,IAAI,SAAS;YACvB,KAAK,CAAC,IAAI,IAAI,OAAO,CACxB,CAAC;IACJ,CAAC;IAED,MAAM;QACJ,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,YAAY,GAAG,IAAI,uBAAuB,EAAE,CAAC;AAEnD,MAAM,UAAU,eAAe;IAC7B,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB,CACvC,WAAwB;IAExB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;IAExC,MAAM,aAAa,GAAG,SAAS,CAAC,gBAAgB,CAC9C,WAAW,CAAC,MAAM,EAClB,WAAW,CAAC,QAAQ,CACrB,CAAC;IAEF,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,0BAA0B,CAAC;IACxD,MAAM,sBAAsB,GAAG,aAAa,IAAI,SAAS,CAAC;IAE1D,IAAI,SAAoC,CAAC;IACzC,IAAI,aAAa,IAAI,SAAS,EAAE,CAAC;QAC/B,SAAS,GAAG,MAAM,CAAC;IACrB,CAAC;SAAM,IAAI,aAAa,IAAI,SAAS,GAAG,GAAG,EAAE,CAAC;QAC5C,SAAS,GAAG,QAAQ,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,KAAK,CAAC;IACpB,CAAC;IAED,OAAO;QACL,MAAM,EAAE,IAAI,EAAE,8CAA8C;QAC5D,iBAAiB,EAAE,WAAW,CAAC,MAAM;QACrC,aAAa;QACb,SAAS;QACT,sBAAsB;QACtB,SAAS;KACV,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,WAAwB,EACxB,sBAA6C;IAE7C,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;IAExC,2BAA2B;IAC3B,MAAM,MAAM,GAAG,sBAAsB,CACnC,WAAW,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,EACnC,MAAM,CAAC,GAAG,CAAC,qBAAqB,CACjC,CAAC;IAEF,8CAA8C;IAC9C,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC5B,MAAM,aAAa,GACjB,WAAW,CAAC,gBAAgB,EAAE,KAAK,IAAI,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC;QACxE,IAAI,aAAa,EAAE,CAAC;YAClB,sBAAsB,GAAG,YAAY,CAAC,aAAa,CACjD,aAAa,EACb,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,OAAO,CACf,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,sBAAsB,GAAG,YAAY,CAAC,cAAc,CAClD,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,OAAO,CACf,CAAC;QACJ,CAAC;IACH,CAAC;IAED,mCAAmC;IACnC,MAAM,kBAAkB,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAC7D,mBAAmB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CACjD,CAAC;IAEF,mBAAmB;IACnB,MAAM,WAAW,GAAG,kBAAkB,CAAC,MAAM,CAC3C,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,EAC1B,WAAW,CAAC,MAAM,CACnB,CAAC;IACF,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,MAAM,CAClD,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,aAAa,EACjC,SAAS,CAAC,gBAAgB,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CACrE,CAAC;IAEF,MAAM,iBAAiB,GAAG;QACxB,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QACjD,SAAS,CAAC,gBAAgB,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC;KACrE,CAAC;IAEF,gCAAgC;IAChC,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAClD,MAAM,QAAQ,GACZ,kBAAkB,IAAI,SAAS;QAC/B,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;IAEpD,OAAO;QACL,QAAQ;QACR,UAAU,EAAE,MAAM,CAAC,IAAI;QACvB,gBAAgB,EAAE,kBAAkB,CAAC,MAAM,GAAG,CAAC;QAC/C,WAAW;QACX,kBAAkB;QAClB,iBAAiB;QACjB,SAAS,EAAE,QAAQ;YACjB,CAAC,CAAC,yBAAyB,kBAAkB,CAAC,MAAM,GAAG,CAAC,0BAA0B,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,MAAM,CAAC,IAAI,qBAAqB,SAAS,iBAAiB;YACtL,CAAC,CAAC,2CAA2C,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,MAAM,CAAC,IAAI,QAAQ;KAC7G,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,WAAwB,EACxB,sBAA6C;IAE7C,MAAM,WAAW,GAAG,yBAAyB,CAAC,WAAW,CAAC,CAAC;IAC3D,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,WAAW,EAAE,sBAAsB,CAAC,CAAC;IAE/E,+BAA+B;IAC/B,IAAI,gBAA2C,CAAC;IAChD,IAAI,WAAW,CAAC,SAAS,KAAK,MAAM,IAAI,gBAAgB,EAAE,QAAQ,EAAE,CAAC;QACnE,gBAAgB,GAAG,MAAM,CAAC;IAC5B,CAAC;SAAM,IAAI,WAAW,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC9C,gBAAgB,GAAG,QAAQ,CAAC;IAC9B,CAAC;SAAM,CAAC;QACN,gBAAgB,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED,MAAM,MAAM,GAAG,gBAAgB,KAAK,MAAM,CAAC;IAE3C,OAAO;QACL,MAAM;QACN,sBAAsB,EAAE,WAAW;QACnC,gBAAgB;QAChB,gBAAgB;QAChB,SAAS,EAAE,MAAM;YACf,CAAC,CAAC,iCAAiC,gBAAgB,GAAG;YACtD,CAAC,CAAC,6CAA6C,gBAAgB,KAAK,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,EAAE,EAAE;KAC1I,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAqB;IACvD,MAAM,QAAQ,GACZ,KAAK,CAAC,gBAAgB,KAAK,MAAM;QAC/B,CAAC,CAAC,UAAU;QACZ,CAAC,CAAC,KAAK,CAAC,gBAAgB,KAAK,QAAQ;YACrC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,MAAM,CAAC;IACb,MAAM,QAAQ,GAAiB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IAEnE,OAAO;QACL,MAAM,EAAE,WAAW;QACnB,QAAQ,EAAE,8BAA8B;QACxC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ;QACR,QAAQ;QACR,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EAAE;YACP,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;YACxC,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;YACpD,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;SACzC;KACF,CAAC;AACJ,CAAC"}

View File

@@ -121,7 +121,7 @@ export function checkStructuring(
// Get historical transactions if not provided
if (!historicalTransactions) {
const customerTaxId =
transaction.orderingCustomerTaxId || transaction.beneficiary?.taxId;
transaction.orderingCustomer?.taxId || transaction.beneficiary?.taxId;
if (customerTaxId) {
historicalTransactions = historyStore.getByCustomer(
customerTaxId,

23
packages/rules-engine/src/config.d.ts vendored Normal file
View File

@@ -0,0 +1,23 @@
export interface RulesConfig {
threshold: {
usdReportingThreshold: number;
};
iof: {
inboundRate: number;
outboundRate: number;
rateVersion: string;
effectiveDate: Date;
};
aml: {
singleTransactionThreshold: number;
structuringWindowDays: number;
structuringThreshold: number;
};
ruleSetVersion: string;
effectiveDate: Date;
}
export declare const DEFAULT_CONFIG: RulesConfig;
export declare function getConfig(): RulesConfig;
export declare function setConfig(config: RulesConfig): void;
export declare function resetConfig(): void;
//# sourceMappingURL=config.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE;QACT,qBAAqB,EAAE,MAAM,CAAC;KAC/B,CAAC;IACF,GAAG,EAAE;QACH,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,IAAI,CAAC;KACrB,CAAC;IACF,GAAG,EAAE;QACH,0BAA0B,EAAE,MAAM,CAAC;QACnC,qBAAqB,EAAE,MAAM,CAAC;QAC9B,oBAAoB,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,EAAE,WAiB5B,CAAC;AAIF,wBAAgB,SAAS,IAAI,WAAW,CAEvC;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAEnD;AAED,wBAAgB,WAAW,IAAI,IAAI,CAElC"}

View File

@@ -0,0 +1,29 @@
export const DEFAULT_CONFIG = {
threshold: {
usdReportingThreshold: 10000,
},
iof: {
inboundRate: 0.0038,
outboundRate: 0.0350,
rateVersion: '1.0.0',
effectiveDate: new Date('2024-01-01'),
},
aml: {
singleTransactionThreshold: 10000,
structuringWindowDays: 30,
structuringThreshold: 10000,
},
ruleSetVersion: '1.0.0',
effectiveDate: new Date('2024-01-01'),
};
let currentConfig = DEFAULT_CONFIG;
export function getConfig() {
return currentConfig;
}
export function setConfig(config) {
currentConfig = config;
}
export function resetConfig() {
currentConfig = DEFAULT_CONFIG;
}
//# sourceMappingURL=config.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"config.js","sourceRoot":"","sources":["config.ts"],"names":[],"mappings":"AAmBA,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,SAAS,EAAE;QACT,qBAAqB,EAAE,KAAK;KAC7B;IACD,GAAG,EAAE;QACH,WAAW,EAAE,MAAM;QACnB,YAAY,EAAE,MAAM;QACpB,WAAW,EAAE,OAAO;QACpB,aAAa,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC;KACtC;IACD,GAAG,EAAE;QACH,0BAA0B,EAAE,KAAK;QACjC,qBAAqB,EAAE,EAAE;QACzB,oBAAoB,EAAE,KAAK;KAC5B;IACD,cAAc,EAAE,OAAO;IACvB,aAAa,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC;CACtC,CAAC;AAEF,IAAI,aAAa,GAAgB,cAAc,CAAC;AAEhD,MAAM,UAAU,SAAS;IACvB,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAmB;IAC3C,aAAa,GAAG,MAAM,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,aAAa,GAAG,cAAc,CAAC;AACjC,CAAC"}

View File

@@ -0,0 +1,51 @@
export interface RulesConfig {
threshold: {
usdReportingThreshold: number;
};
iof: {
inboundRate: number;
outboundRate: number;
rateVersion: string;
effectiveDate: Date;
};
aml: {
singleTransactionThreshold: number;
structuringWindowDays: number;
structuringThreshold: number;
};
ruleSetVersion: string;
effectiveDate: Date;
}
export const DEFAULT_CONFIG: RulesConfig = {
threshold: {
usdReportingThreshold: 10000,
},
iof: {
inboundRate: 0.0038,
outboundRate: 0.0350,
rateVersion: '1.0.0',
effectiveDate: new Date('2024-01-01'),
},
aml: {
singleTransactionThreshold: 10000,
structuringWindowDays: 30,
structuringThreshold: 10000,
},
ruleSetVersion: '1.0.0',
effectiveDate: new Date('2024-01-01'),
};
let currentConfig: RulesConfig = DEFAULT_CONFIG;
export function getConfig(): RulesConfig {
return currentConfig;
}
export function setConfig(config: RulesConfig): void {
currentConfig = config;
}
export function resetConfig(): void {
currentConfig = DEFAULT_CONFIG;
}

View File

@@ -0,0 +1,4 @@
import type { Transaction, DocumentationCheckResult, RuleResult } from '@brazil-swift-ops/types';
export declare function validateDocumentation(transaction: Transaction): DocumentationCheckResult;
export declare function createDocumentationRuleResult(check: DocumentationCheckResult): RuleResult;
//# sourceMappingURL=documentation.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"documentation.d.ts","sourceRoot":"","sources":["documentation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,wBAAwB,EACxB,UAAU,EAGX,MAAM,yBAAyB,CAAC;AAGjC,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,WAAW,GACvB,wBAAwB,CAkE1B;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,wBAAwB,GAC9B,UAAU,CAsBZ"}

View File

@@ -0,0 +1,82 @@
import { validateBrazilianTaxId } from '@brazil-swift-ops/utils';
export function validateDocumentation(transaction) {
const missingFields = [];
const hasOrderingCustomerName = !!transaction.orderingCustomer?.name;
if (!hasOrderingCustomerName) {
missingFields.push('orderingCustomer.name');
}
const hasOrderingCustomerAddress = !!transaction.orderingCustomer?.address || !!transaction.orderingCustomer?.city;
if (!hasOrderingCustomerAddress) {
missingFields.push('orderingCustomer.address');
}
const hasOrderingCustomerTaxId = !!transaction.orderingCustomer?.taxId;
if (hasOrderingCustomerTaxId && transaction.orderingCustomer.taxId) {
const taxIdValidation = validateBrazilianTaxId(transaction.orderingCustomer.taxId);
if (!taxIdValidation.valid) {
missingFields.push('orderingCustomer.taxId (invalid format)');
}
}
else {
missingFields.push('orderingCustomer.taxId');
}
const hasBeneficiaryName = !!transaction.beneficiary?.name;
if (!hasBeneficiaryName) {
missingFields.push('beneficiary.name');
}
const hasBeneficiaryAccount = !!transaction.beneficiary?.accountNumber || !!transaction.beneficiary?.iban;
if (!hasBeneficiaryAccount) {
missingFields.push('beneficiary.accountNumber or beneficiary.iban');
}
const hasBeneficiaryTaxId = !!transaction.beneficiary?.taxId;
if (hasBeneficiaryTaxId && transaction.beneficiary.taxId) {
const taxIdValidation = validateBrazilianTaxId(transaction.beneficiary.taxId);
if (!taxIdValidation.valid) {
missingFields.push('beneficiary.taxId (invalid format)');
}
}
else {
missingFields.push('beneficiary.taxId');
}
const hasPurposeOfPayment = !!transaction.purposeOfPayment && transaction.purposeOfPayment.trim().length > 0;
if (!hasPurposeOfPayment) {
missingFields.push('purposeOfPayment');
}
const passed = missingFields.length === 0;
return {
passed,
hasOrderingCustomerName,
hasOrderingCustomerAddress,
hasOrderingCustomerTaxId,
hasBeneficiaryName,
hasBeneficiaryAccount,
hasBeneficiaryTaxId,
hasPurposeOfPayment,
missingFields,
rationale: passed
? 'All required documentation fields are present and valid.'
: `Missing or invalid required fields: ${missingFields.join(', ')}`,
};
}
export function createDocumentationRuleResult(check) {
const severity = check.passed ? 'Info' : 'Critical';
const decision = check.passed ? 'Allow' : 'Hold';
return {
ruleId: 'documentation-check',
ruleName: 'Documentation Validation',
passed: check.passed,
severity,
decision,
rationale: check.rationale,
details: {
missingFields: check.missingFields,
hasOrderingCustomerName: check.hasOrderingCustomerName,
hasOrderingCustomerAddress: check.hasOrderingCustomerAddress,
hasOrderingCustomerTaxId: check.hasOrderingCustomerTaxId,
hasBeneficiaryName: check.hasBeneficiaryName,
hasBeneficiaryAccount: check.hasBeneficiaryAccount,
hasBeneficiaryTaxId: check.hasBeneficiaryTaxId,
hasPurposeOfPayment: check.hasPurposeOfPayment,
},
};
}
//# sourceMappingURL=documentation.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"documentation.js","sourceRoot":"","sources":["documentation.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,104 @@
import type {
Transaction,
DocumentationCheckResult,
RuleResult,
RuleSeverity,
RuleDecision,
} from '@brazil-swift-ops/types';
import { validateBrazilianTaxId } from '@brazil-swift-ops/utils';
export function validateDocumentation(
transaction: Transaction
): DocumentationCheckResult {
const missingFields: string[] = [];
const hasOrderingCustomerName = !!transaction.orderingCustomer?.name;
if (!hasOrderingCustomerName) {
missingFields.push('orderingCustomer.name');
}
const hasOrderingCustomerAddress =
!!transaction.orderingCustomer?.address || !!transaction.orderingCustomer?.city;
if (!hasOrderingCustomerAddress) {
missingFields.push('orderingCustomer.address');
}
const hasOrderingCustomerTaxId = !!transaction.orderingCustomer?.taxId;
if (hasOrderingCustomerTaxId && transaction.orderingCustomer.taxId) {
const taxIdValidation = validateBrazilianTaxId(transaction.orderingCustomer.taxId);
if (!taxIdValidation.valid) {
missingFields.push('orderingCustomer.taxId (invalid format)');
}
} else {
missingFields.push('orderingCustomer.taxId');
}
const hasBeneficiaryName = !!transaction.beneficiary?.name;
if (!hasBeneficiaryName) {
missingFields.push('beneficiary.name');
}
const hasBeneficiaryAccount =
!!transaction.beneficiary?.accountNumber || !!transaction.beneficiary?.iban;
if (!hasBeneficiaryAccount) {
missingFields.push('beneficiary.accountNumber or beneficiary.iban');
}
const hasBeneficiaryTaxId = !!transaction.beneficiary?.taxId;
if (hasBeneficiaryTaxId && transaction.beneficiary.taxId) {
const taxIdValidation = validateBrazilianTaxId(transaction.beneficiary.taxId);
if (!taxIdValidation.valid) {
missingFields.push('beneficiary.taxId (invalid format)');
}
} else {
missingFields.push('beneficiary.taxId');
}
const hasPurposeOfPayment = !!transaction.purposeOfPayment && transaction.purposeOfPayment.trim().length > 0;
if (!hasPurposeOfPayment) {
missingFields.push('purposeOfPayment');
}
const passed = missingFields.length === 0;
return {
passed,
hasOrderingCustomerName,
hasOrderingCustomerAddress,
hasOrderingCustomerTaxId,
hasBeneficiaryName,
hasBeneficiaryAccount,
hasBeneficiaryTaxId,
hasPurposeOfPayment,
missingFields,
rationale: passed
? 'All required documentation fields are present and valid.'
: `Missing or invalid required fields: ${missingFields.join(', ')}`,
};
}
export function createDocumentationRuleResult(
check: DocumentationCheckResult
): RuleResult {
const severity: RuleSeverity = check.passed ? 'Info' : 'Critical';
const decision: RuleDecision = check.passed ? 'Allow' : 'Hold';
return {
ruleId: 'documentation-check',
ruleName: 'Documentation Validation',
passed: check.passed,
severity,
decision,
rationale: check.rationale,
details: {
missingFields: check.missingFields,
hasOrderingCustomerName: check.hasOrderingCustomerName,
hasOrderingCustomerAddress: check.hasOrderingCustomerAddress,
hasOrderingCustomerTaxId: check.hasOrderingCustomerTaxId,
hasBeneficiaryName: check.hasBeneficiaryName,
hasBeneficiaryAccount: check.hasBeneficiaryAccount,
hasBeneficiaryTaxId: check.hasBeneficiaryTaxId,
hasPurposeOfPayment: check.hasPurposeOfPayment,
},
};
}

View File

@@ -0,0 +1 @@
{"version":3,"file":"fx-contract.d.ts","sourceRoot":"","sources":["fx-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,qBAAqB,EACrB,UAAU,EAGX,MAAM,yBAAyB,CAAC;AAGjC,cAAM,eAAe;IACnB,OAAO,CAAC,SAAS,CAAsC;IAEvD,GAAG,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;IAI/B,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI/C,MAAM,IAAI,UAAU,EAAE;IAItB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;CAWpE;AAID,wBAAgB,gBAAgB,IAAI,eAAe,CAElD;AAED,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,EACxB,QAAQ,CAAC,EAAE,UAAU,GACpB,qBAAqB,CAmFvB;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,qBAAqB,GAC3B,UAAU,CAsBZ"}

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC;AACtB,cAAc,gBAAgB,CAAC"}

View File

@@ -0,0 +1,13 @@
/**
* @brazil-swift-ops/rules-engine
*
* Brazil regulatory rules engine for cross-border payments
*/
export * from './config';
export * from './threshold';
export * from './documentation';
export * from './fx-contract';
export * from './iof';
export * from './aml';
export * from './orchestrator';
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC;AACtB,cAAc,gBAAgB,CAAC"}

View File

@@ -0,0 +1 @@
{"version":3,"file":"iof.d.ts","sourceRoot":"","sources":["iof.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,oBAAoB,EACpB,UAAU,EACX,MAAM,yBAAyB,CAAC;AAIjC,wBAAgB,YAAY,CAAC,WAAW,EAAE,WAAW,GAAG,oBAAoB,CAuC3E;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,oBAAoB,GAChC,UAAU,CAoBZ"}

View File

@@ -0,0 +1,55 @@
import Decimal from 'decimal.js';
import { getDefaultConverter } from '@brazil-swift-ops/utils';
import { getConfig } from './config';
export function calculateIOF(transaction) {
const config = getConfig();
const converter = getDefaultConverter();
const brlAmount = converter.convert(transaction.amount, transaction.currency, 'BRL');
const iofRate = transaction.direction === 'inbound'
? config.iof.inboundRate
: config.iof.outboundRate;
const brlDecimal = new Decimal(brlAmount);
const rateDecimal = new Decimal(iofRate);
const iofDecimal = brlDecimal.mul(rateDecimal);
const iofAmount = iofDecimal.toNumber();
let netAmount;
if (transaction.direction === 'inbound') {
netAmount = brlAmount - iofAmount;
}
else {
netAmount = brlAmount + iofAmount;
}
return {
direction: transaction.direction,
transactionAmount: transaction.amount,
currency: transaction.currency,
brlAmount,
iofRate,
iofAmount,
netAmount,
effectiveDate: config.iof.effectiveDate,
rateVersion: config.iof.rateVersion,
};
}
export function createIOFRuleResult(calculation) {
return {
ruleId: 'iof-calculation',
ruleName: 'IOF Tax Calculation',
passed: true,
severity: 'Info',
decision: 'Allow',
rationale: `IOF calculated: ${calculation.iofAmount.toFixed(2)} BRL (${(calculation.iofRate * 100).toFixed(2)}% rate) for ${calculation.direction} transaction. Net amount: ${calculation.netAmount.toFixed(2)} BRL.`,
details: {
direction: calculation.direction,
transactionAmount: calculation.transactionAmount,
currency: calculation.currency,
brlAmount: calculation.brlAmount,
iofRate: calculation.iofRate,
iofAmount: calculation.iofAmount,
netAmount: calculation.netAmount,
effectiveDate: calculation.effectiveDate,
rateVersion: calculation.rateVersion,
},
};
}
//# sourceMappingURL=iof.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"iof.js","sourceRoot":"","sources":["iof.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,YAAY,CAAC;AAMjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,MAAM,UAAU,YAAY,CAAC,WAAwB;IACnD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;IAExC,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CACjC,WAAW,CAAC,MAAM,EAClB,WAAW,CAAC,QAAQ,EACpB,KAAK,CACN,CAAC;IAEF,MAAM,OAAO,GACX,WAAW,CAAC,SAAS,KAAK,SAAS;QACjC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW;QACxB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;IAE9B,MAAM,UAAU,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAE/C,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC;IAExC,IAAI,SAAiB,CAAC;IACtB,IAAI,WAAW,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACxC,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IACpC,CAAC;IAED,OAAO;QACL,SAAS,EAAE,WAAW,CAAC,SAAS;QAChC,iBAAiB,EAAE,WAAW,CAAC,MAAM;QACrC,QAAQ,EAAE,WAAW,CAAC,QAAQ;QAC9B,SAAS;QACT,OAAO;QACP,SAAS;QACT,SAAS;QACT,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa;QACvC,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW;KACpC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,WAAiC;IAEjC,OAAO;QACL,MAAM,EAAE,iBAAiB;QACzB,QAAQ,EAAE,qBAAqB;QAC/B,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,MAAM;QAChB,QAAQ,EAAE,OAAO;QACjB,SAAS,EAAE,mBAAmB,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,WAAW,CAAC,SAAS,6BAA6B,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;QACrN,OAAO,EAAE;YACP,SAAS,EAAE,WAAW,CAAC,SAAS;YAChC,iBAAiB,EAAE,WAAW,CAAC,iBAAiB;YAChD,QAAQ,EAAE,WAAW,CAAC,QAAQ;YAC9B,SAAS,EAAE,WAAW,CAAC,SAAS;YAChC,OAAO,EAAE,WAAW,CAAC,OAAO;YAC5B,SAAS,EAAE,WAAW,CAAC,SAAS;YAChC,SAAS,EAAE,WAAW,CAAC,SAAS;YAChC,aAAa,EAAE,WAAW,CAAC,aAAa;YACxC,WAAW,EAAE,WAAW,CAAC,WAAW;SACrC;KACF,CAAC;AACJ,CAAC"}

View File

@@ -0,0 +1 @@
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["orchestrator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,sBAAsB,EAGvB,MAAM,yBAAyB,CAAC;AAmBjC;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,WAAW,GACvB,sBAAsB,CAoDxB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,WAAW,EAAE,GAC1B,sBAAsB,EAAE,CAE1B"}

View File

@@ -0,0 +1,68 @@
/**
* Rules engine orchestrator - coordinates all regulatory rule evaluations
*/
import { getConfig } from './config';
import { evaluateThreshold, createThresholdRuleResult } from './threshold';
import { validateDocumentation, createDocumentationRuleResult, } from './documentation';
import { validateFXContract, createFXContractRuleResult, getContractStore, } from './fx-contract';
import { calculateIOF, createIOFRuleResult } from './iof';
import { performAMLCheck, createAMLRuleResult, } from './aml';
/**
* Evaluate all Brazil regulatory rules for a transaction
*/
export function evaluateTransaction(transaction) {
const config = getConfig();
const timestamp = new Date();
// Run all rule checks
const thresholdCheck = evaluateThreshold(transaction);
const documentationCheck = validateDocumentation(transaction);
const fxContract = getContractStore().get(transaction.fxContractId || '');
const fxContractCheck = validateFXContract(transaction, fxContract);
const iofCalculation = calculateIOF(transaction);
const amlCheck = performAMLCheck(transaction);
// Create rule results
const rules = [
createThresholdRuleResult(thresholdCheck),
createDocumentationRuleResult(documentationCheck),
createFXContractRuleResult(fxContractCheck),
createIOFRuleResult(iofCalculation),
createAMLRuleResult(amlCheck),
];
// Determine overall decision and severity
const criticalRules = rules.filter((r) => r.severity === 'Critical' && !r.passed);
const warningRules = rules.filter((r) => r.severity === 'Warning' && !r.passed);
let overallDecision;
let overallSeverity;
if (criticalRules.length > 0) {
overallDecision = 'Hold';
overallSeverity = 'Critical';
}
else if (warningRules.length > 0) {
overallDecision = 'Escalate';
overallSeverity = 'Warning';
}
else {
overallDecision = 'Allow';
overallSeverity = 'Info';
}
return {
transactionId: transaction.id,
timestamp,
ruleSetVersion: config.ruleSetVersion,
overallDecision,
overallSeverity,
rules,
thresholdCheck,
documentationCheck,
fxContractCheck,
iofCalculation,
amlCheck,
};
}
/**
* Evaluate a batch of transactions
*/
export function evaluateBatch(transactions) {
return transactions.map((txn) => evaluateTransaction(txn));
}
//# sourceMappingURL=orchestrator.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["orchestrator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EACL,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,EAClB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAC1D,OAAO,EACL,eAAe,EACf,mBAAmB,GAEpB,MAAM,OAAO,CAAC;AAEf;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,WAAwB;IAExB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;IAE7B,sBAAsB;IACtB,MAAM,cAAc,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,WAAW,CAAC,CAAC;IAC9D,MAAM,UAAU,GAAG,gBAAgB,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAC1E,MAAM,eAAe,GAAG,kBAAkB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACpE,MAAM,cAAc,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAE9C,sBAAsB;IACtB,MAAM,KAAK,GAAG;QACZ,yBAAyB,CAAC,cAAc,CAAC;QACzC,6BAA6B,CAAC,kBAAkB,CAAC;QACjD,0BAA0B,CAAC,eAAe,CAAC;QAC3C,mBAAmB,CAAC,cAAc,CAAC;QACnC,mBAAmB,CAAC,QAAQ,CAAC;KAC9B,CAAC;IAEF,0CAA0C;IAC1C,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAClF,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAEhF,IAAI,eAA6B,CAAC;IAClC,IAAI,eAA6B,CAAC;IAElC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,eAAe,GAAG,MAAM,CAAC;QACzB,eAAe,GAAG,UAAU,CAAC;IAC/B,CAAC;SAAM,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,eAAe,GAAG,UAAU,CAAC;QAC7B,eAAe,GAAG,SAAS,CAAC;IAC9B,CAAC;SAAM,CAAC;QACN,eAAe,GAAG,OAAO,CAAC;QAC1B,eAAe,GAAG,MAAM,CAAC;IAC3B,CAAC;IAED,OAAO;QACL,aAAa,EAAE,WAAW,CAAC,EAAE;QAC7B,SAAS;QACT,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,eAAe;QACf,eAAe;QACf,KAAK;QACL,cAAc;QACd,kBAAkB;QAClB,eAAe;QACf,cAAc;QACd,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,YAA2B;IAE3B,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7D,CAAC"}

View File

@@ -0,0 +1,4 @@
import type { Transaction, ThresholdCheckResult, RuleResult } from '@brazil-swift-ops/types';
export declare function evaluateThreshold(transaction: Transaction): ThresholdCheckResult;
export declare function createThresholdRuleResult(check: ThresholdCheckResult): RuleResult;
//# sourceMappingURL=threshold.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"threshold.d.ts","sourceRoot":"","sources":["threshold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,oBAAoB,EACpB,UAAU,EAGX,MAAM,yBAAyB,CAAC;AAIjC,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,WAAW,GACvB,oBAAoB,CAuBtB;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,oBAAoB,GAC1B,UAAU,CAmBZ"}

View File

@@ -0,0 +1,40 @@
import { getDefaultConverter } from '@brazil-swift-ops/utils';
import { getConfig } from './config';
export function evaluateThreshold(transaction) {
const config = getConfig();
const converter = getDefaultConverter();
const usdEquivalent = converter.getUSDEquivalent(transaction.amount, transaction.currency);
const threshold = config.threshold.usdReportingThreshold;
const requiresReporting = usdEquivalent >= threshold;
return {
passed: true,
transactionAmount: transaction.amount,
currency: transaction.currency,
usdEquivalent,
threshold,
requiresReporting,
rationale: requiresReporting
? `Transaction amount (${transaction.amount} ${transaction.currency} = ${usdEquivalent.toFixed(2)} USD) exceeds reporting threshold of ${threshold} USD. Reporting to Banco Central required.`
: `Transaction amount (${transaction.amount} ${transaction.currency} = ${usdEquivalent.toFixed(2)} USD) is below reporting threshold of ${threshold} USD.`,
};
}
export function createThresholdRuleResult(check) {
const severity = check.requiresReporting ? 'Warning' : 'Info';
const decision = check.requiresReporting ? 'Hold' : 'Allow';
return {
ruleId: 'threshold-check',
ruleName: 'USD Equivalent Threshold Check',
passed: true,
severity,
decision,
rationale: check.rationale,
details: {
transactionAmount: check.transactionAmount,
currency: check.currency,
usdEquivalent: check.usdEquivalent,
threshold: check.threshold,
requiresReporting: check.requiresReporting,
},
};
}
//# sourceMappingURL=threshold.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"threshold.js","sourceRoot":"","sources":["threshold.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,MAAM,UAAU,iBAAiB,CAC/B,WAAwB;IAExB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;IAExC,MAAM,aAAa,GAAG,SAAS,CAAC,gBAAgB,CAC9C,WAAW,CAAC,MAAM,EAClB,WAAW,CAAC,QAAQ,CACrB,CAAC;IAEF,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,qBAAqB,CAAC;IACzD,MAAM,iBAAiB,GAAG,aAAa,IAAI,SAAS,CAAC;IAErD,OAAO;QACL,MAAM,EAAE,IAAI;QACZ,iBAAiB,EAAE,WAAW,CAAC,MAAM;QACrC,QAAQ,EAAE,WAAW,CAAC,QAAQ;QAC9B,aAAa;QACb,SAAS;QACT,iBAAiB;QACjB,SAAS,EAAE,iBAAiB;YAC1B,CAAC,CAAC,uBAAuB,WAAW,CAAC,MAAM,IAAI,WAAW,CAAC,QAAQ,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,wCAAwC,SAAS,4CAA4C;YAC9L,CAAC,CAAC,uBAAuB,WAAW,CAAC,MAAM,IAAI,WAAW,CAAC,QAAQ,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,yCAAyC,SAAS,OAAO;KAC7J,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,KAA2B;IAE3B,MAAM,QAAQ,GAAiB,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5E,MAAM,QAAQ,GAAiB,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAE1E,OAAO;QACL,MAAM,EAAE,iBAAiB;QACzB,QAAQ,EAAE,gCAAgC;QAC1C,MAAM,EAAE,IAAI;QACZ,QAAQ;QACR,QAAQ;QACR,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EAAE;YACP,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;YAC1C,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;SAC3C;KACF,CAAC;AACJ,CAAC"}

View File

@@ -0,0 +1,59 @@
import type {
Transaction,
ThresholdCheckResult,
RuleResult,
RuleSeverity,
RuleDecision,
} from '@brazil-swift-ops/types';
import { getDefaultConverter } from '@brazil-swift-ops/utils';
import { getConfig } from './config';
export function evaluateThreshold(
transaction: Transaction
): ThresholdCheckResult {
const config = getConfig();
const converter = getDefaultConverter();
const usdEquivalent = converter.getUSDEquivalent(
transaction.amount,
transaction.currency
);
const threshold = config.threshold.usdReportingThreshold;
const requiresReporting = usdEquivalent >= threshold;
return {
passed: true,
transactionAmount: transaction.amount,
currency: transaction.currency,
usdEquivalent,
threshold,
requiresReporting,
rationale: requiresReporting
? `Transaction amount (${transaction.amount} ${transaction.currency} = ${usdEquivalent.toFixed(2)} USD) exceeds reporting threshold of ${threshold} USD. Reporting to Banco Central required.`
: `Transaction amount (${transaction.amount} ${transaction.currency} = ${usdEquivalent.toFixed(2)} USD) is below reporting threshold of ${threshold} USD.`,
};
}
export function createThresholdRuleResult(
check: ThresholdCheckResult
): RuleResult {
const severity: RuleSeverity = check.requiresReporting ? 'Warning' : 'Info';
const decision: RuleDecision = check.requiresReporting ? 'Hold' : 'Allow';
return {
ruleId: 'threshold-check',
ruleName: 'USD Equivalent Threshold Check',
passed: true,
severity,
decision,
rationale: check.rationale,
details: {
transactionAmount: check.transactionAmount,
currency: check.currency,
usdEquivalent: check.usdEquivalent,
threshold: check.threshold,
requiresReporting: check.requiresReporting,
},
};
}

View File

@@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"composite": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"],
"references": [
{
"path": "../types"
},
{
"path": "../utils"
}
]
}