@accounter/server 0.0.8-alpha-20251102200443-d7162b8ce1dfc629b8b454df17dcec9ed005a052 → 0.0.8-alpha-20251102213150-c9d936f545d5351df0dc5326c2623266f1ad1f46
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.
- package/CHANGELOG.md +47 -7
- package/dist/green-invoice-graphql/src/mesh-artifacts/index.d.ts +1 -1
- package/dist/server/src/__generated__/types.d.ts +77 -0
- package/dist/server/src/__generated__/types.js.map +1 -1
- package/dist/server/src/modules/charges-matcher/__generated__/types.d.ts +68 -0
- package/dist/server/src/modules/charges-matcher/__generated__/types.js +7 -0
- package/dist/server/src/modules/charges-matcher/__generated__/types.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/amount-confidence.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/amount-confidence.test.js +218 -0
- package/dist/server/src/modules/charges-matcher/__tests__/amount-confidence.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/auto-match-integration.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/auto-match-integration.test.js +645 -0
- package/dist/server/src/modules/charges-matcher/__tests__/auto-match-integration.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/auto-match.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/auto-match.test.js +530 -0
- package/dist/server/src/modules/charges-matcher/__tests__/auto-match.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/business-confidence.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/business-confidence.test.js +143 -0
- package/dist/server/src/modules/charges-matcher/__tests__/business-confidence.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/candidate-filter.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/candidate-filter.test.js +186 -0
- package/dist/server/src/modules/charges-matcher/__tests__/candidate-filter.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/charge-validator.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/charge-validator.test.js +301 -0
- package/dist/server/src/modules/charges-matcher/__tests__/charge-validator.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/currency-confidence.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/currency-confidence.test.js +127 -0
- package/dist/server/src/modules/charges-matcher/__tests__/currency-confidence.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/date-confidence.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/date-confidence.test.js +246 -0
- package/dist/server/src/modules/charges-matcher/__tests__/date-confidence.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/document-aggregator.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/document-aggregator.test.js +475 -0
- package/dist/server/src/modules/charges-matcher/__tests__/document-aggregator.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/document-amount.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/document-amount.test.js +287 -0
- package/dist/server/src/modules/charges-matcher/__tests__/document-amount.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/document-business.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/document-business.test.js +151 -0
- package/dist/server/src/modules/charges-matcher/__tests__/document-business.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/match-scorer.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/match-scorer.test.js +550 -0
- package/dist/server/src/modules/charges-matcher/__tests__/match-scorer.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/overall-confidence.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/overall-confidence.test.js +410 -0
- package/dist/server/src/modules/charges-matcher/__tests__/overall-confidence.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/single-match-integration.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/single-match-integration.test.js +504 -0
- package/dist/server/src/modules/charges-matcher/__tests__/single-match-integration.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/single-match.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/single-match.test.js +483 -0
- package/dist/server/src/modules/charges-matcher/__tests__/single-match.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/test-helpers.d.ts +46 -0
- package/dist/server/src/modules/charges-matcher/__tests__/test-helpers.js +143 -0
- package/dist/server/src/modules/charges-matcher/__tests__/test-helpers.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/test-infrastructure.spec.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/test-infrastructure.spec.js +137 -0
- package/dist/server/src/modules/charges-matcher/__tests__/test-infrastructure.spec.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/transaction-aggregator.test.d.ts +1 -0
- package/dist/server/src/modules/charges-matcher/__tests__/transaction-aggregator.test.js +415 -0
- package/dist/server/src/modules/charges-matcher/__tests__/transaction-aggregator.test.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/helpers/amount-confidence.helper.d.ts +7 -0
- package/dist/server/src/modules/charges-matcher/helpers/amount-confidence.helper.js +70 -0
- package/dist/server/src/modules/charges-matcher/helpers/amount-confidence.helper.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/helpers/business-confidence.helper.d.ts +7 -0
- package/dist/server/src/modules/charges-matcher/helpers/business-confidence.helper.js +19 -0
- package/dist/server/src/modules/charges-matcher/helpers/business-confidence.helper.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/helpers/candidate-filter.helper.d.ts +24 -0
- package/dist/server/src/modules/charges-matcher/helpers/candidate-filter.helper.js +45 -0
- package/dist/server/src/modules/charges-matcher/helpers/candidate-filter.helper.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/helpers/charge-validator.helper.d.ts +33 -0
- package/dist/server/src/modules/charges-matcher/helpers/charge-validator.helper.js +65 -0
- package/dist/server/src/modules/charges-matcher/helpers/charge-validator.helper.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/helpers/currency-confidence.helper.d.ts +7 -0
- package/dist/server/src/modules/charges-matcher/helpers/currency-confidence.helper.js +18 -0
- package/dist/server/src/modules/charges-matcher/helpers/currency-confidence.helper.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/helpers/date-confidence.helper.d.ts +7 -0
- package/dist/server/src/modules/charges-matcher/helpers/date-confidence.helper.js +35 -0
- package/dist/server/src/modules/charges-matcher/helpers/date-confidence.helper.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/helpers/document-amount.helper.d.ts +49 -0
- package/dist/server/src/modules/charges-matcher/helpers/document-amount.helper.js +58 -0
- package/dist/server/src/modules/charges-matcher/helpers/document-amount.helper.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/helpers/document-business.helper.d.ts +13 -0
- package/dist/server/src/modules/charges-matcher/helpers/document-business.helper.js +37 -0
- package/dist/server/src/modules/charges-matcher/helpers/document-business.helper.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/helpers/overall-confidence.helper.d.ts +42 -0
- package/dist/server/src/modules/charges-matcher/helpers/overall-confidence.helper.js +77 -0
- package/dist/server/src/modules/charges-matcher/helpers/overall-confidence.helper.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/index.d.ts +3 -0
- package/dist/server/src/modules/charges-matcher/index.js +15 -0
- package/dist/server/src/modules/charges-matcher/index.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/providers/auto-match.provider.d.ts +48 -0
- package/dist/server/src/modules/charges-matcher/providers/auto-match.provider.js +133 -0
- package/dist/server/src/modules/charges-matcher/providers/auto-match.provider.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/providers/charges-matcher.provider.d.ts +38 -0
- package/dist/server/src/modules/charges-matcher/providers/charges-matcher.provider.js +248 -0
- package/dist/server/src/modules/charges-matcher/providers/charges-matcher.provider.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/providers/document-aggregator.d.ts +61 -0
- package/dist/server/src/modules/charges-matcher/providers/document-aggregator.js +153 -0
- package/dist/server/src/modules/charges-matcher/providers/document-aggregator.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/providers/match-scorer.provider.d.ts +25 -0
- package/dist/server/src/modules/charges-matcher/providers/match-scorer.provider.js +114 -0
- package/dist/server/src/modules/charges-matcher/providers/match-scorer.provider.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/providers/single-match.provider.d.ts +39 -0
- package/dist/server/src/modules/charges-matcher/providers/single-match.provider.js +189 -0
- package/dist/server/src/modules/charges-matcher/providers/single-match.provider.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/providers/transaction-aggregator.d.ts +54 -0
- package/dist/server/src/modules/charges-matcher/providers/transaction-aggregator.js +93 -0
- package/dist/server/src/modules/charges-matcher/providers/transaction-aggregator.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/resolvers/auto-match-charges.resolver.d.ts +2 -0
- package/dist/server/src/modules/charges-matcher/resolvers/auto-match-charges.resolver.js +22 -0
- package/dist/server/src/modules/charges-matcher/resolvers/auto-match-charges.resolver.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/resolvers/find-charge-matches.resolver.d.ts +2 -0
- package/dist/server/src/modules/charges-matcher/resolvers/find-charge-matches.resolver.js +24 -0
- package/dist/server/src/modules/charges-matcher/resolvers/find-charge-matches.resolver.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/resolvers/index.d.ts +2 -0
- package/dist/server/src/modules/charges-matcher/resolvers/index.js +11 -0
- package/dist/server/src/modules/charges-matcher/resolvers/index.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/typeDefs/charges-matcher.graphql.d.ts +2 -0
- package/dist/server/src/modules/charges-matcher/typeDefs/charges-matcher.graphql.js +47 -0
- package/dist/server/src/modules/charges-matcher/typeDefs/charges-matcher.graphql.js.map +1 -0
- package/dist/server/src/modules/charges-matcher/types.d.ts +179 -0
- package/dist/server/src/modules/charges-matcher/types.js +14 -0
- package/dist/server/src/modules/charges-matcher/types.js.map +1 -0
- package/dist/server/src/modules/documents/resolvers/document-suggestions.resolver.js +2 -2
- package/dist/server/src/modules/documents/resolvers/document-suggestions.resolver.js.map +1 -1
- package/dist/server/src/modules-app.js +2 -0
- package/dist/server/src/modules-app.js.map +1 -1
- package/dist/server/src/shared/types/index.d.ts +1 -1
- package/package.json +4 -4
- package/src/__generated__/types.ts +87 -0
- package/src/modules/charges-matcher/README.md +279 -0
- package/src/modules/charges-matcher/__generated__/types.ts +71 -0
- package/src/modules/charges-matcher/__tests__/amount-confidence.test.ts +260 -0
- package/src/modules/charges-matcher/__tests__/auto-match-integration.test.ts +714 -0
- package/src/modules/charges-matcher/__tests__/auto-match.test.ts +621 -0
- package/src/modules/charges-matcher/__tests__/business-confidence.test.ts +177 -0
- package/src/modules/charges-matcher/__tests__/candidate-filter.test.ts +238 -0
- package/src/modules/charges-matcher/__tests__/charge-validator.test.ts +374 -0
- package/src/modules/charges-matcher/__tests__/currency-confidence.test.ts +164 -0
- package/src/modules/charges-matcher/__tests__/date-confidence.test.ts +291 -0
- package/src/modules/charges-matcher/__tests__/document-aggregator.test.ts +614 -0
- package/src/modules/charges-matcher/__tests__/document-amount.test.ts +352 -0
- package/src/modules/charges-matcher/__tests__/document-business.test.ts +192 -0
- package/src/modules/charges-matcher/__tests__/match-scorer.test.ts +659 -0
- package/src/modules/charges-matcher/__tests__/overall-confidence.test.ts +502 -0
- package/src/modules/charges-matcher/__tests__/single-match-integration.test.ts +556 -0
- package/src/modules/charges-matcher/__tests__/single-match.test.ts +608 -0
- package/src/modules/charges-matcher/__tests__/test-helpers.ts +174 -0
- package/src/modules/charges-matcher/__tests__/test-infrastructure.spec.ts +177 -0
- package/src/modules/charges-matcher/__tests__/transaction-aggregator.test.ts +547 -0
- package/src/modules/charges-matcher/documentation/README.md +331 -0
- package/src/modules/charges-matcher/documentation/SPEC.md +1503 -0
- package/src/modules/charges-matcher/documentation/TODO.md +799 -0
- package/src/modules/charges-matcher/helpers/amount-confidence.helper.ts +88 -0
- package/src/modules/charges-matcher/helpers/business-confidence.helper.ts +23 -0
- package/src/modules/charges-matcher/helpers/candidate-filter.helper.ts +56 -0
- package/src/modules/charges-matcher/helpers/charge-validator.helper.ts +100 -0
- package/src/modules/charges-matcher/helpers/currency-confidence.helper.ts +22 -0
- package/src/modules/charges-matcher/helpers/date-confidence.helper.ts +41 -0
- package/src/modules/charges-matcher/helpers/document-amount.helper.ts +77 -0
- package/src/modules/charges-matcher/helpers/document-business.helper.ts +54 -0
- package/src/modules/charges-matcher/helpers/overall-confidence.helper.ts +90 -0
- package/src/modules/charges-matcher/index.ts +17 -0
- package/src/modules/charges-matcher/providers/auto-match.provider.ts +176 -0
- package/src/modules/charges-matcher/providers/charges-matcher.provider.ts +322 -0
- package/src/modules/charges-matcher/providers/document-aggregator.ts +211 -0
- package/src/modules/charges-matcher/providers/match-scorer.provider.ts +154 -0
- package/src/modules/charges-matcher/providers/single-match.provider.ts +252 -0
- package/src/modules/charges-matcher/providers/transaction-aggregator.ts +131 -0
- package/src/modules/charges-matcher/resolvers/auto-match-charges.resolver.ts +23 -0
- package/src/modules/charges-matcher/resolvers/find-charge-matches.resolver.ts +25 -0
- package/src/modules/charges-matcher/resolvers/index.ts +12 -0
- package/src/modules/charges-matcher/typeDefs/charges-matcher.graphql.ts +47 -0
- package/src/modules/charges-matcher/types.ts +200 -0
- package/src/modules/documents/resolvers/document-suggestions.resolver.ts +2 -2
- package/src/modules-app.ts +2 -0
- package/src/shared/types/index.ts +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-aggregator.js","sourceRoot":"","sources":["../../../../../../src/modules/charges-matcher/providers/document-aggregator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { document_type } from '../../documents/types.js';
|
|
2
|
+
import type { AggregatedTransaction, DocumentCharge, MatchScore, TransactionCharge } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Select appropriate transaction date based on document type
|
|
5
|
+
* Per specification:
|
|
6
|
+
* - INVOICE/CREDIT_INVOICE: Use event_date
|
|
7
|
+
* - RECEIPT/INVOICE_RECEIPT: Use debit_date (debit_timestamp or debit_date)
|
|
8
|
+
* - OTHER/PROFORMA/UNPROCESSED: Calculate both and use better score
|
|
9
|
+
*
|
|
10
|
+
* @param transaction - Aggregated transaction data
|
|
11
|
+
* @param documentType - Document type being matched
|
|
12
|
+
* @returns The date to use for matching
|
|
13
|
+
*/
|
|
14
|
+
export declare function selectTransactionDate(transaction: AggregatedTransaction, documentType: document_type): Date;
|
|
15
|
+
/**
|
|
16
|
+
* Score a potential match between transaction charge and document charge
|
|
17
|
+
* Aggregates data from both charges and calculates confidence score
|
|
18
|
+
*
|
|
19
|
+
* @param txCharge - Transaction charge to match
|
|
20
|
+
* @param docCharge - Document charge candidate
|
|
21
|
+
* @param userId - Current user UUID for business extraction
|
|
22
|
+
* @returns Match score with confidence and component breakdown
|
|
23
|
+
* @throws Error if aggregation fails (mixed currencies, multiple businesses, etc.)
|
|
24
|
+
*/
|
|
25
|
+
export declare function scoreMatch(txCharge: TransactionCharge, docCharge: DocumentCharge, userId: string): MatchScore;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { calculateAmountConfidence } from '../helpers/amount-confidence.helper.js';
|
|
2
|
+
import { calculateBusinessConfidence } from '../helpers/business-confidence.helper.js';
|
|
3
|
+
import { calculateCurrencyConfidence } from '../helpers/currency-confidence.helper.js';
|
|
4
|
+
import { calculateDateConfidence } from '../helpers/date-confidence.helper.js';
|
|
5
|
+
import { calculateOverallConfidence } from '../helpers/overall-confidence.helper.js';
|
|
6
|
+
import { aggregateDocuments } from './document-aggregator.js';
|
|
7
|
+
import { aggregateTransactions } from './transaction-aggregator.js';
|
|
8
|
+
/**
|
|
9
|
+
* Select appropriate transaction date based on document type
|
|
10
|
+
* Per specification:
|
|
11
|
+
* - INVOICE/CREDIT_INVOICE: Use event_date
|
|
12
|
+
* - RECEIPT/INVOICE_RECEIPT: Use debit_date (debit_timestamp or debit_date)
|
|
13
|
+
* - OTHER/PROFORMA/UNPROCESSED: Calculate both and use better score
|
|
14
|
+
*
|
|
15
|
+
* @param transaction - Aggregated transaction data
|
|
16
|
+
* @param documentType - Document type being matched
|
|
17
|
+
* @returns The date to use for matching
|
|
18
|
+
*/
|
|
19
|
+
export function selectTransactionDate(transaction, documentType) {
|
|
20
|
+
switch (documentType) {
|
|
21
|
+
case 'INVOICE':
|
|
22
|
+
case 'CREDIT_INVOICE':
|
|
23
|
+
case 'RECEIPT':
|
|
24
|
+
case 'INVOICE_RECEIPT':
|
|
25
|
+
// For invoices, use event_date
|
|
26
|
+
return transaction.date;
|
|
27
|
+
case 'OTHER':
|
|
28
|
+
case 'PROFORMA':
|
|
29
|
+
case 'UNPROCESSED':
|
|
30
|
+
// For flexible types, use event_date as default
|
|
31
|
+
// (caller should calculate both and use better score)
|
|
32
|
+
return transaction.date;
|
|
33
|
+
default:
|
|
34
|
+
// Fallback to event_date for unknown types
|
|
35
|
+
return transaction.date;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Score a potential match between transaction charge and document charge
|
|
40
|
+
* Aggregates data from both charges and calculates confidence score
|
|
41
|
+
*
|
|
42
|
+
* @param txCharge - Transaction charge to match
|
|
43
|
+
* @param docCharge - Document charge candidate
|
|
44
|
+
* @param userId - Current user UUID for business extraction
|
|
45
|
+
* @returns Match score with confidence and component breakdown
|
|
46
|
+
* @throws Error if aggregation fails (mixed currencies, multiple businesses, etc.)
|
|
47
|
+
*/
|
|
48
|
+
export function scoreMatch(txCharge, docCharge, userId) {
|
|
49
|
+
// Aggregate transaction data
|
|
50
|
+
const aggregatedTransaction = aggregateTransactions(txCharge.transactions);
|
|
51
|
+
// Aggregate document data (includes business extraction and amount normalization)
|
|
52
|
+
const aggregatedDocument = aggregateDocuments(docCharge.documents, userId);
|
|
53
|
+
// // For flexible document types, try both dates and use the better score
|
|
54
|
+
// if (
|
|
55
|
+
// aggregatedDocument.type === 'OTHER' ||
|
|
56
|
+
// aggregatedDocument.type === 'PROFORMA' ||
|
|
57
|
+
// aggregatedDocument.type === 'UNPROCESSED'
|
|
58
|
+
// ) {
|
|
59
|
+
// // Calculate score with event_date
|
|
60
|
+
// const scoreWithEventDate = calculateScoreWithDate(
|
|
61
|
+
// aggregatedTransaction,
|
|
62
|
+
// aggregatedDocument,
|
|
63
|
+
// aggregatedTransaction.date,
|
|
64
|
+
// docCharge.chargeId,
|
|
65
|
+
// );
|
|
66
|
+
// // Calculate score with debit_date (if available)
|
|
67
|
+
// if (aggregatedTransaction.debitDate) {
|
|
68
|
+
// const scoreWithDebitDate = calculateScoreWithDate(
|
|
69
|
+
// aggregatedTransaction,
|
|
70
|
+
// aggregatedDocument,
|
|
71
|
+
// aggregatedTransaction.debitDate,
|
|
72
|
+
// docCharge.chargeId,
|
|
73
|
+
// );
|
|
74
|
+
// // Return the better score
|
|
75
|
+
// return scoreWithEventDate.confidenceScore > scoreWithDebitDate.confidenceScore
|
|
76
|
+
// ? scoreWithEventDate
|
|
77
|
+
// : scoreWithDebitDate;
|
|
78
|
+
// }
|
|
79
|
+
// return scoreWithEventDate;
|
|
80
|
+
// }
|
|
81
|
+
// For specific document types, use the appropriate date
|
|
82
|
+
const transactionDate = selectTransactionDate(aggregatedTransaction, aggregatedDocument.type);
|
|
83
|
+
return calculateScoreWithDate(aggregatedTransaction, aggregatedDocument, transactionDate, docCharge.chargeId);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Helper function to calculate match score with a specific transaction date
|
|
87
|
+
* @param transaction - Aggregated transaction
|
|
88
|
+
* @param document - Aggregated document
|
|
89
|
+
* @param transactionDate - Date to use from transaction
|
|
90
|
+
* @param chargeId - Document charge ID
|
|
91
|
+
* @returns Match score
|
|
92
|
+
*/
|
|
93
|
+
function calculateScoreWithDate(transaction, document, transactionDate, chargeId) {
|
|
94
|
+
// Calculate individual confidence scores
|
|
95
|
+
const amountScore = calculateAmountConfidence(transaction.amount, document.amount);
|
|
96
|
+
const currencyScore = calculateCurrencyConfidence(transaction.currency, document.currency);
|
|
97
|
+
const businessScore = calculateBusinessConfidence(transaction.businessId, document.businessId);
|
|
98
|
+
const dateScore = calculateDateConfidence(transactionDate, document.date);
|
|
99
|
+
// Create components object
|
|
100
|
+
const components = {
|
|
101
|
+
amount: amountScore,
|
|
102
|
+
currency: currencyScore,
|
|
103
|
+
business: businessScore,
|
|
104
|
+
date: dateScore,
|
|
105
|
+
};
|
|
106
|
+
// Calculate overall confidence
|
|
107
|
+
const confidenceScore = calculateOverallConfidence(components);
|
|
108
|
+
return {
|
|
109
|
+
chargeId,
|
|
110
|
+
confidenceScore,
|
|
111
|
+
components,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=match-scorer.provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match-scorer.provider.js","sourceRoot":"","sources":["../../../../../../src/modules/charges-matcher/providers/match-scorer.provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single-Match Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements the core single-match logic for finding potential charge matches.
|
|
5
|
+
* This is a pure function implementation without database dependencies.
|
|
6
|
+
*/
|
|
7
|
+
import type { DocumentCharge, TransactionCharge } from '../types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Match result with score and metadata
|
|
10
|
+
*/
|
|
11
|
+
export interface MatchResult {
|
|
12
|
+
chargeId: string;
|
|
13
|
+
confidenceScore: number;
|
|
14
|
+
components: {
|
|
15
|
+
amount: number;
|
|
16
|
+
currency: number;
|
|
17
|
+
business: number;
|
|
18
|
+
date: number;
|
|
19
|
+
};
|
|
20
|
+
dateProximity?: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Options for findMatches function
|
|
24
|
+
*/
|
|
25
|
+
export interface FindMatchesOptions {
|
|
26
|
+
maxMatches?: number;
|
|
27
|
+
dateWindowMonths?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Find top matches for an unmatched charge
|
|
31
|
+
*
|
|
32
|
+
* @param sourceCharge - The unmatched charge (transactions OR documents)
|
|
33
|
+
* @param candidateCharges - All potential match candidates
|
|
34
|
+
* @param userId - Current user ID
|
|
35
|
+
* @param options - Optional configuration (maxMatches, dateWindowMonths)
|
|
36
|
+
* @returns Top matches sorted by confidence
|
|
37
|
+
* @throws Error if source charge is matched or has validation issues
|
|
38
|
+
*/
|
|
39
|
+
export declare function findMatches(sourceCharge: TransactionCharge | DocumentCharge, candidateCharges: Array<TransactionCharge | DocumentCharge>, userId: string, options?: FindMatchesOptions): MatchResult[];
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single-Match Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements the core single-match logic for finding potential charge matches.
|
|
5
|
+
* This is a pure function implementation without database dependencies.
|
|
6
|
+
*/
|
|
7
|
+
import { isWithinDateWindow } from '../helpers/candidate-filter.helper.js';
|
|
8
|
+
import { aggregateDocuments } from './document-aggregator.js';
|
|
9
|
+
import { scoreMatch } from './match-scorer.provider.js';
|
|
10
|
+
import { aggregateTransactions } from './transaction-aggregator.js';
|
|
11
|
+
/**
|
|
12
|
+
* Type guard: check if charge is TransactionCharge
|
|
13
|
+
*/
|
|
14
|
+
function isTransactionCharge(charge) {
|
|
15
|
+
return 'transactions' in charge && charge.transactions.length > 0;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Type guard: check if charge is DocumentCharge
|
|
19
|
+
*/
|
|
20
|
+
function isDocumentCharge(charge) {
|
|
21
|
+
return 'documents' in charge && charge.documents.length > 0;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Validate that source charge is unmatched (has only one type)
|
|
25
|
+
*/
|
|
26
|
+
function validateUnmatchedCharge(charge) {
|
|
27
|
+
const hasTx = 'transactions' in charge && charge.transactions && charge.transactions.length > 0;
|
|
28
|
+
const hasDocs = 'documents' in charge && charge.documents && charge.documents.length > 0;
|
|
29
|
+
if (hasTx && hasDocs) {
|
|
30
|
+
throw new Error(`Source charge ${charge.chargeId} is already matched (contains both transactions and documents)`);
|
|
31
|
+
}
|
|
32
|
+
if (!hasTx && !hasDocs) {
|
|
33
|
+
throw new Error(`Source charge ${charge.chargeId} has no transactions or documents`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Validate that source charge can be aggregated successfully
|
|
38
|
+
*/
|
|
39
|
+
function validateSourceAggregation(charge, userId) {
|
|
40
|
+
try {
|
|
41
|
+
if (isTransactionCharge(charge)) {
|
|
42
|
+
aggregateTransactions(charge.transactions);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
aggregateDocuments(charge.documents, userId);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
throw new Error(`Source charge ${charge.chargeId} failed validation: ${error instanceof Error ? error.message : String(error)}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Calculate date proximity between transaction and document charges
|
|
54
|
+
* Used for tie-breaking when confidence scores are equal
|
|
55
|
+
*
|
|
56
|
+
* @param txCharge - Transaction charge
|
|
57
|
+
* @param docCharge - Document charge
|
|
58
|
+
* @returns Number of days between earliest transaction date and latest document date
|
|
59
|
+
*/
|
|
60
|
+
function calculateDateProximity(txCharge, docCharge) {
|
|
61
|
+
// Get earliest transaction event_date
|
|
62
|
+
const earliestTxDate = txCharge.transactions.reduce((earliest, tx) => {
|
|
63
|
+
return tx.event_date < earliest ? tx.event_date : earliest;
|
|
64
|
+
}, txCharge.transactions[0].event_date);
|
|
65
|
+
// Get latest document date
|
|
66
|
+
const latestDocDate = docCharge.documents.reduce((latest, doc) => {
|
|
67
|
+
if (!doc.date)
|
|
68
|
+
return latest;
|
|
69
|
+
return doc.date > latest ? doc.date : latest;
|
|
70
|
+
}, docCharge.documents[0].date);
|
|
71
|
+
// Calculate day difference
|
|
72
|
+
const diffMs = Math.abs(earliestTxDate.getTime() - latestDocDate.getTime());
|
|
73
|
+
return Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Find top matches for an unmatched charge
|
|
77
|
+
*
|
|
78
|
+
* @param sourceCharge - The unmatched charge (transactions OR documents)
|
|
79
|
+
* @param candidateCharges - All potential match candidates
|
|
80
|
+
* @param userId - Current user ID
|
|
81
|
+
* @param options - Optional configuration (maxMatches, dateWindowMonths)
|
|
82
|
+
* @returns Top matches sorted by confidence
|
|
83
|
+
* @throws Error if source charge is matched or has validation issues
|
|
84
|
+
*/
|
|
85
|
+
export function findMatches(sourceCharge, candidateCharges, userId, options) {
|
|
86
|
+
const maxMatches = options?.maxMatches ?? 5;
|
|
87
|
+
const dateWindowMonths = options?.dateWindowMonths ?? 12;
|
|
88
|
+
// Step 1: Validate source charge is unmatched
|
|
89
|
+
validateUnmatchedCharge(sourceCharge);
|
|
90
|
+
// Step 2: Validate source charge aggregation
|
|
91
|
+
validateSourceAggregation(sourceCharge, userId);
|
|
92
|
+
// Step 3: Determine source type and filter candidates by complementary type
|
|
93
|
+
const isSourceTransaction = isTransactionCharge(sourceCharge);
|
|
94
|
+
const complementaryCandidates = candidateCharges.filter(candidate => {
|
|
95
|
+
if (isSourceTransaction) {
|
|
96
|
+
return isDocumentCharge(candidate);
|
|
97
|
+
}
|
|
98
|
+
return isTransactionCharge(candidate);
|
|
99
|
+
});
|
|
100
|
+
// Step 4: Get source date for window filtering
|
|
101
|
+
let sourceDate;
|
|
102
|
+
if (isSourceTransaction) {
|
|
103
|
+
// Use earliest event_date from transactions
|
|
104
|
+
sourceDate = sourceCharge.transactions.reduce((earliest, tx) => {
|
|
105
|
+
return tx.event_date < earliest ? tx.event_date : earliest;
|
|
106
|
+
}, sourceCharge.transactions[0].event_date);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Use latest date from documents
|
|
110
|
+
sourceDate = sourceCharge.documents.reduce((latest, doc) => {
|
|
111
|
+
if (!doc.date)
|
|
112
|
+
return latest;
|
|
113
|
+
return doc.date > latest ? doc.date : latest;
|
|
114
|
+
}, sourceCharge.documents[0].date);
|
|
115
|
+
}
|
|
116
|
+
// Step 5: Filter candidates by date window
|
|
117
|
+
const windowFilteredCandidates = complementaryCandidates.filter(candidate => {
|
|
118
|
+
let candidateDate;
|
|
119
|
+
if (isTransactionCharge(candidate)) {
|
|
120
|
+
candidateDate = candidate.transactions.reduce((earliest, tx) => {
|
|
121
|
+
return tx.event_date < earliest ? tx.event_date : earliest;
|
|
122
|
+
}, candidate.transactions[0].event_date);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
candidateDate = candidate.documents.reduce((latest, doc) => {
|
|
126
|
+
if (!doc.date)
|
|
127
|
+
return latest;
|
|
128
|
+
return doc.date > latest ? doc.date : latest;
|
|
129
|
+
}, candidate.documents[0].date);
|
|
130
|
+
}
|
|
131
|
+
return isWithinDateWindow(sourceDate, candidateDate, dateWindowMonths);
|
|
132
|
+
});
|
|
133
|
+
// Step 6: Filter candidates using candidate filter logic
|
|
134
|
+
// Note: Additional filtering (is_fee, null checks) is handled by aggregators
|
|
135
|
+
// which will throw errors for invalid data
|
|
136
|
+
// Step 7: Exclude candidates with same chargeId
|
|
137
|
+
const sameChargeCandidate = windowFilteredCandidates.find(c => c.chargeId === sourceCharge.chargeId);
|
|
138
|
+
if (sameChargeCandidate) {
|
|
139
|
+
throw new Error(`Candidate charge ${sameChargeCandidate.chargeId} has the same ID as source charge`);
|
|
140
|
+
}
|
|
141
|
+
// Step 8: Score all remaining candidates
|
|
142
|
+
const scoredCandidates = [];
|
|
143
|
+
for (const candidate of windowFilteredCandidates) {
|
|
144
|
+
try {
|
|
145
|
+
let matchScore;
|
|
146
|
+
let txCharge;
|
|
147
|
+
let docCharge;
|
|
148
|
+
if (isSourceTransaction) {
|
|
149
|
+
txCharge = sourceCharge;
|
|
150
|
+
docCharge = candidate;
|
|
151
|
+
matchScore = scoreMatch(txCharge, docCharge, userId);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
txCharge = candidate;
|
|
155
|
+
docCharge = sourceCharge;
|
|
156
|
+
matchScore = scoreMatch(txCharge, docCharge, userId);
|
|
157
|
+
}
|
|
158
|
+
// Calculate date proximity for tie-breaking
|
|
159
|
+
const dateProximity = calculateDateProximity(txCharge, docCharge);
|
|
160
|
+
scoredCandidates.push({
|
|
161
|
+
chargeId: candidate.chargeId,
|
|
162
|
+
confidenceScore: matchScore.confidenceScore,
|
|
163
|
+
components: matchScore.components,
|
|
164
|
+
dateProximity,
|
|
165
|
+
_txCharge: txCharge,
|
|
166
|
+
_docCharge: docCharge,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// Skip candidates that fail scoring (e.g., mixed currencies, invalid data)
|
|
171
|
+
// This is expected behavior - not all candidates will be scoreable
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Step 9: Sort by confidence descending, then by date proximity ascending (tie-breaker)
|
|
176
|
+
scoredCandidates.sort((a, b) => {
|
|
177
|
+
// Primary: confidence score (descending)
|
|
178
|
+
if (a.confidenceScore !== b.confidenceScore) {
|
|
179
|
+
return b.confidenceScore - a.confidenceScore;
|
|
180
|
+
}
|
|
181
|
+
// Tie-breaker: date proximity (ascending - closer dates win)
|
|
182
|
+
return (a.dateProximity ?? Infinity) - (b.dateProximity ?? Infinity);
|
|
183
|
+
});
|
|
184
|
+
// Step 10: Return top N matches
|
|
185
|
+
const topMatches = scoredCandidates.slice(0, maxMatches);
|
|
186
|
+
// Clean up temporary fields
|
|
187
|
+
return topMatches.map(({ _txCharge, _docCharge, ...match }) => match);
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=single-match.provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"single-match.provider.js","sourceRoot":"","sources":["../../../../../../src/modules/charges-matcher/providers/single-match.provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transaction Aggregator
|
|
3
|
+
*
|
|
4
|
+
* Aggregates multiple transactions from a single charge into a unified representation
|
|
5
|
+
* for matching purposes. Handles fee exclusion, currency validation, business ID
|
|
6
|
+
* validation, amount summation, date selection, and description concatenation.
|
|
7
|
+
*/
|
|
8
|
+
import type { currency } from '../../documents/types';
|
|
9
|
+
import type { AggregatedTransaction } from '../types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Minimal transaction interface for aggregation
|
|
12
|
+
* Based on database schema from accounter_schema.transactions
|
|
13
|
+
*/
|
|
14
|
+
export interface Transaction {
|
|
15
|
+
id: string;
|
|
16
|
+
charge_id: string;
|
|
17
|
+
amount: string;
|
|
18
|
+
currency: currency;
|
|
19
|
+
business_id: string | null;
|
|
20
|
+
event_date: Date;
|
|
21
|
+
debit_date: Date | null;
|
|
22
|
+
debit_timestamp: Date | null;
|
|
23
|
+
source_description: string | null;
|
|
24
|
+
is_fee: boolean | null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Aggregate multiple transactions into a single representation
|
|
28
|
+
*
|
|
29
|
+
* Per specification (section 4.2):
|
|
30
|
+
* 1. Exclude transactions where is_fee = true
|
|
31
|
+
* 2. If multiple currencies exist: throw error
|
|
32
|
+
* 3. If multiple non-null business IDs exist: throw error
|
|
33
|
+
* 4. Amount: sum of all amounts
|
|
34
|
+
* 5. Currency: the common currency
|
|
35
|
+
* 6. Business ID: the single non-null business ID (or null if all null)
|
|
36
|
+
* 7. Date: earliest event_date
|
|
37
|
+
* 8. Description: concatenate all source_description values with line breaks
|
|
38
|
+
*
|
|
39
|
+
* @param transactions - Array of transactions from a charge
|
|
40
|
+
* @returns Aggregated transaction data
|
|
41
|
+
*
|
|
42
|
+
* @throws {Error} If transactions array is empty
|
|
43
|
+
* @throws {Error} If no non-fee transactions exist after filtering
|
|
44
|
+
* @throws {Error} If multiple different currencies exist
|
|
45
|
+
* @throws {Error} If multiple different non-null business IDs exist
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* const aggregated = aggregateTransactions([
|
|
49
|
+
* { amount: 100, currency: 'USD', business_id: 'b1', event_date: new Date('2024-01-15'), ... },
|
|
50
|
+
* { amount: 50, currency: 'USD', business_id: 'b1', event_date: new Date('2024-01-20'), ... }
|
|
51
|
+
* ]);
|
|
52
|
+
* // Returns: { amount: 150, currency: 'USD', businessId: 'b1', date: Date('2024-01-15'), ... }
|
|
53
|
+
*/
|
|
54
|
+
export declare function aggregateTransactions(transactions: Transaction[]): AggregatedTransaction;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transaction Aggregator
|
|
3
|
+
*
|
|
4
|
+
* Aggregates multiple transactions from a single charge into a unified representation
|
|
5
|
+
* for matching purposes. Handles fee exclusion, currency validation, business ID
|
|
6
|
+
* validation, amount summation, date selection, and description concatenation.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Aggregate multiple transactions into a single representation
|
|
10
|
+
*
|
|
11
|
+
* Per specification (section 4.2):
|
|
12
|
+
* 1. Exclude transactions where is_fee = true
|
|
13
|
+
* 2. If multiple currencies exist: throw error
|
|
14
|
+
* 3. If multiple non-null business IDs exist: throw error
|
|
15
|
+
* 4. Amount: sum of all amounts
|
|
16
|
+
* 5. Currency: the common currency
|
|
17
|
+
* 6. Business ID: the single non-null business ID (or null if all null)
|
|
18
|
+
* 7. Date: earliest event_date
|
|
19
|
+
* 8. Description: concatenate all source_description values with line breaks
|
|
20
|
+
*
|
|
21
|
+
* @param transactions - Array of transactions from a charge
|
|
22
|
+
* @returns Aggregated transaction data
|
|
23
|
+
*
|
|
24
|
+
* @throws {Error} If transactions array is empty
|
|
25
|
+
* @throws {Error} If no non-fee transactions exist after filtering
|
|
26
|
+
* @throws {Error} If multiple different currencies exist
|
|
27
|
+
* @throws {Error} If multiple different non-null business IDs exist
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const aggregated = aggregateTransactions([
|
|
31
|
+
* { amount: 100, currency: 'USD', business_id: 'b1', event_date: new Date('2024-01-15'), ... },
|
|
32
|
+
* { amount: 50, currency: 'USD', business_id: 'b1', event_date: new Date('2024-01-20'), ... }
|
|
33
|
+
* ]);
|
|
34
|
+
* // Returns: { amount: 150, currency: 'USD', businessId: 'b1', date: Date('2024-01-15'), ... }
|
|
35
|
+
*/
|
|
36
|
+
export function aggregateTransactions(transactions) {
|
|
37
|
+
// Validate non-empty input
|
|
38
|
+
if (!transactions || transactions.length === 0) {
|
|
39
|
+
throw new Error('Cannot aggregate transactions: array is empty');
|
|
40
|
+
}
|
|
41
|
+
// Filter out fee transactions
|
|
42
|
+
const nonFeeTransactions = transactions.filter(t => t.is_fee !== true);
|
|
43
|
+
// Validate we have transactions after filtering
|
|
44
|
+
if (nonFeeTransactions.length === 0) {
|
|
45
|
+
throw new Error('Cannot aggregate transactions: all transactions are marked as fees');
|
|
46
|
+
}
|
|
47
|
+
// Validate single currency
|
|
48
|
+
const currencies = new Set(nonFeeTransactions.map(t => t.currency));
|
|
49
|
+
if (currencies.size > 1) {
|
|
50
|
+
throw new Error(`Cannot aggregate transactions: multiple currencies found (${Array.from(currencies).join(', ')})`);
|
|
51
|
+
}
|
|
52
|
+
// Validate single non-null business ID
|
|
53
|
+
const businessIds = nonFeeTransactions
|
|
54
|
+
.map(t => t.business_id)
|
|
55
|
+
.filter((id) => id !== null && id !== undefined);
|
|
56
|
+
const uniqueBusinessIds = new Set(businessIds);
|
|
57
|
+
if (uniqueBusinessIds.size > 1) {
|
|
58
|
+
throw new Error(`Cannot aggregate transactions: multiple business IDs found (${Array.from(uniqueBusinessIds).join(', ')})`);
|
|
59
|
+
}
|
|
60
|
+
// Sum amounts
|
|
61
|
+
const totalAmount = nonFeeTransactions.reduce((sum, t) => sum + Number(t.amount), 0);
|
|
62
|
+
// Get common currency (safe since we validated single currency)
|
|
63
|
+
const currency = nonFeeTransactions[0].currency;
|
|
64
|
+
// Get business ID (single non-null or null if all null)
|
|
65
|
+
const businessId = uniqueBusinessIds.size === 1 ? Array.from(uniqueBusinessIds)[0] : null;
|
|
66
|
+
// Get earliest event_date
|
|
67
|
+
const earliestDate = nonFeeTransactions.reduce((earliest, t) => {
|
|
68
|
+
return t.event_date < earliest ? t.event_date : earliest;
|
|
69
|
+
}, nonFeeTransactions[0].event_date);
|
|
70
|
+
// Get earliest debit_date
|
|
71
|
+
const earliestDebitDate = nonFeeTransactions.reduce((earliest, t) => {
|
|
72
|
+
const debitDate = t.debit_timestamp ?? t.debit_date;
|
|
73
|
+
if (debitDate === null)
|
|
74
|
+
return earliest;
|
|
75
|
+
if (earliest === null)
|
|
76
|
+
return debitDate;
|
|
77
|
+
return debitDate < earliest ? debitDate : earliest;
|
|
78
|
+
}, null);
|
|
79
|
+
// Concatenate descriptions with line breaks, filtering out nulls
|
|
80
|
+
const descriptions = nonFeeTransactions
|
|
81
|
+
.map(t => t.source_description)
|
|
82
|
+
.filter((desc) => desc !== null && desc !== undefined && desc.trim() !== '');
|
|
83
|
+
const description = descriptions.length > 0 ? descriptions.join('\n') : '';
|
|
84
|
+
return {
|
|
85
|
+
amount: totalAmount,
|
|
86
|
+
currency,
|
|
87
|
+
businessId,
|
|
88
|
+
date: earliestDate,
|
|
89
|
+
description,
|
|
90
|
+
debitDate: earliestDebitDate,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=transaction-aggregator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transaction-aggregator.js","sourceRoot":"","sources":["../../../../../../src/modules/charges-matcher/providers/transaction-aggregator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { GraphQLError } from 'graphql';
|
|
2
|
+
import { ChargesMatcherProvider } from '../providers/charges-matcher.provider.js';
|
|
3
|
+
export const autoMatchChargesResolver = {
|
|
4
|
+
Mutation: {
|
|
5
|
+
autoMatchCharges: async (_, __, context) => {
|
|
6
|
+
try {
|
|
7
|
+
const result = await context.injector.get(ChargesMatcherProvider).autoMatchCharges(context);
|
|
8
|
+
return result;
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
if (e instanceof GraphQLError) {
|
|
12
|
+
throw e;
|
|
13
|
+
}
|
|
14
|
+
const message = e?.message ??
|
|
15
|
+
e?.errors.map(e => e.message).toString() ??
|
|
16
|
+
'Unknown error';
|
|
17
|
+
throw new GraphQLError(message);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=auto-match-charges.resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-match-charges.resolver.js","sourceRoot":"","sources":["../../../../../../src/modules/charges-matcher/resolvers/auto-match-charges.resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAGlF,MAAM,CAAC,MAAM,wBAAwB,GAAmC;IACtE,QAAQ,EAAE;QACR,gBAAgB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE;YACzC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBAC5F,OAAO,MAAM,CAAC;YAChB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,YAAY,YAAY,EAAE,CAAC;oBAC9B,MAAM,CAAC,CAAC;gBACV,CAAC;gBACD,MAAM,OAAO,GACV,CAAW,EAAE,OAAO;oBACpB,CAAyB,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE;oBACjE,eAAe,CAAC;gBAClB,MAAM,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { GraphQLError } from 'graphql';
|
|
2
|
+
import { ChargesMatcherProvider } from '../providers/charges-matcher.provider.js';
|
|
3
|
+
export const findChargeMatchesResolver = {
|
|
4
|
+
Query: {
|
|
5
|
+
findChargeMatches: async (_, { chargeId }, context) => {
|
|
6
|
+
try {
|
|
7
|
+
const result = await context.injector
|
|
8
|
+
.get(ChargesMatcherProvider)
|
|
9
|
+
.findMatchesForCharge(chargeId, context);
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
12
|
+
catch (e) {
|
|
13
|
+
if (e instanceof GraphQLError) {
|
|
14
|
+
throw e;
|
|
15
|
+
}
|
|
16
|
+
const message = e?.message ??
|
|
17
|
+
e?.errors.map(e => e.message).toString() ??
|
|
18
|
+
'Unknown error';
|
|
19
|
+
throw new GraphQLError(message);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=find-charge-matches.resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-charge-matches.resolver.js","sourceRoot":"","sources":["../../../../../../src/modules/charges-matcher/resolvers/find-charge-matches.resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAGlF,MAAM,CAAC,MAAM,yBAAyB,GAAmC;IACvE,KAAK,EAAE;QACL,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE;YACpD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ;qBAClC,GAAG,CAAC,sBAAsB,CAAC;qBAC3B,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAC3C,OAAO,MAAM,CAAC;YAChB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,YAAY,YAAY,EAAE,CAAC;oBAC9B,MAAM,CAAC,CAAC;gBACV,CAAC;gBACD,MAAM,OAAO,GACV,CAAW,EAAE,OAAO;oBACpB,CAAyB,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE;oBACjE,eAAe,CAAC;gBAClB,MAAM,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { autoMatchChargesResolver } from './auto-match-charges.resolver.js';
|
|
2
|
+
import { findChargeMatchesResolver } from './find-charge-matches.resolver.js';
|
|
3
|
+
export const chargesMatcherResolvers = {
|
|
4
|
+
Query: {
|
|
5
|
+
...findChargeMatchesResolver.Query,
|
|
6
|
+
},
|
|
7
|
+
Mutation: {
|
|
8
|
+
...autoMatchChargesResolver.Mutation,
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../src/modules/charges-matcher/resolvers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAE9E,MAAM,CAAC,MAAM,uBAAuB,GAAmC;IACrE,KAAK,EAAE;QACL,GAAG,yBAAyB,CAAC,KAAK;KACnC;IACD,QAAQ,EAAE;QACR,GAAG,wBAAwB,CAAC,QAAQ;KACrC;CACF,CAAC"}
|