@riocrypto/common-server 1.0.2879 → 1.0.2881
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/build/helpers/get-processor.js +10 -6
- package/build/helpers/payin-destinations.d.ts +11 -0
- package/build/helpers/payin-destinations.js +31 -3
- package/build/helpers/resolve-processor.d.ts +1 -1
- package/build/helpers/resolve-processor.js +23 -17
- package/build/index.d.ts +2 -0
- package/build/index.js +2 -0
- package/build/models/alfin-payin-notification.d.ts +2 -0
- package/build/models/alfin-payin-notification.js +17 -0
- package/build/models/alfin-payin-origin.d.ts +39 -0
- package/build/models/alfin-payin-origin.js +65 -0
- package/build/models/alfin-statement-credit.d.ts +55 -0
- package/build/models/alfin-statement-credit.js +91 -0
- package/package.json +2 -2
|
@@ -31,8 +31,11 @@ const getProcessor = ({ country, fiat, side, isBinanceRFQ, routingConfig, disabl
|
|
|
31
31
|
];
|
|
32
32
|
// Applied only inside the branches that genuinely have more than one rail, so
|
|
33
33
|
// a stray rule cannot hijack structural routing (COP, USD in the US or Mexico)
|
|
34
|
-
// or bypass the country checks below.
|
|
35
|
-
//
|
|
34
|
+
// or bypass the country checks below. Answers even when no rule is configured,
|
|
35
|
+
// because the corridor default is only safe to use once the rails the customer
|
|
36
|
+
// has switched off are out of the running. Undefined is left for the one case
|
|
37
|
+
// that genuinely belongs to structural routing: a custom Rio bank account whose
|
|
38
|
+
// rail we do not know.
|
|
36
39
|
const trySplit = () => {
|
|
37
40
|
const routed = (0, resolve_processor_1.resolveProcessor)({
|
|
38
41
|
country,
|
|
@@ -62,10 +65,11 @@ const getProcessor = ({ country, fiat, side, isBinanceRFQ, routingConfig, disabl
|
|
|
62
65
|
}
|
|
63
66
|
return undefined;
|
|
64
67
|
};
|
|
65
|
-
// The rail
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
// corridor that gets this far has to
|
|
68
|
+
// The rail a corridor with nothing to decide runs on, from the one table the
|
|
69
|
+
// routing editor reads as well, so the page can name it. Reached by corridors
|
|
70
|
+
// with a single rail, and by the unknown-rail custom account case. Throwing on
|
|
71
|
+
// a missing entry keeps the two honest: a corridor that gets this far has to
|
|
72
|
+
// have a default.
|
|
69
73
|
const structural = () => {
|
|
70
74
|
const fallback = (0, common_1.getDefaultProcessor)(country, fiat, purpose, excludedProcessors);
|
|
71
75
|
if (!fallback) {
|
|
@@ -13,6 +13,17 @@ export interface PayinBankDetails {
|
|
|
13
13
|
NIT?: string;
|
|
14
14
|
}
|
|
15
15
|
export declare const PER_USER_PAYIN_PROCESSORS: Processor[];
|
|
16
|
+
export declare const normalizeCci: (cci: string) => string;
|
|
17
|
+
/**
|
|
18
|
+
* Whether a CCI is one of Rio's own Peru accounts.
|
|
19
|
+
*
|
|
20
|
+
* Rio funds Alfin from its Interbank accounts, so those transfers appear on the
|
|
21
|
+
* Alfin statement as ordinary interbank credits carrying Rio's own account as
|
|
22
|
+
* the payer. Anything reading the statement to attribute customer payments has
|
|
23
|
+
* to exclude them, or a treasury top-up would be credited to whichever customer
|
|
24
|
+
* order happened to be awaiting the same amount.
|
|
25
|
+
*/
|
|
26
|
+
export declare const isRioOwnPeruAccountCci: (cci?: string) => boolean;
|
|
16
27
|
export declare const getPayinBankDetails: ({ mongoose, processor, fiat, country, user, }: {
|
|
17
28
|
mongoose: Mongoose;
|
|
18
29
|
processor: Processor;
|
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.getPayinDestinations = exports.getPayinBankDetails = exports.PER_USER_PAYIN_PROCESSORS = void 0;
|
|
12
|
+
exports.getPayinDestinations = exports.getPayinBankDetails = exports.isRioOwnPeruAccountCci = exports.normalizeCci = exports.PER_USER_PAYIN_PROCESSORS = void 0;
|
|
13
13
|
const common_1 = require("@riocrypto/common");
|
|
14
14
|
const rio_bank_account_1 = require("../models/rio-bank-account");
|
|
15
15
|
const STP_deposit_CLABE_1 = require("../models/STP-deposit-CLABE");
|
|
@@ -40,6 +40,34 @@ const ALFIN_ACCOUNT_NUMBER_BY_FIAT = {
|
|
|
40
40
|
[common_1.Fiat.PEN]: "01818233900001",
|
|
41
41
|
[common_1.Fiat.USD]: "01818233900002",
|
|
42
42
|
};
|
|
43
|
+
const INTERBANK_PERU_CCI_BY_FIAT = {
|
|
44
|
+
[common_1.Fiat.PEN]: "003-200-003004741070-36",
|
|
45
|
+
[common_1.Fiat.USD]: "003-200-003004741088-38",
|
|
46
|
+
};
|
|
47
|
+
// Digits-only form of a Peruvian CCI. Banks present them either grouped with
|
|
48
|
+
// dashes or bare, and Alfin reports the bare form inside a statement line's
|
|
49
|
+
// referencia, so both have to reduce to the same string to be comparable.
|
|
50
|
+
const normalizeCci = (cci) => cci.replace(/\D/g, "");
|
|
51
|
+
exports.normalizeCci = normalizeCci;
|
|
52
|
+
const RIO_PERU_OWN_CCIS = Object.values(INTERBANK_PERU_CCI_BY_FIAT)
|
|
53
|
+
.filter((cci) => Boolean(cci))
|
|
54
|
+
.map(exports.normalizeCci);
|
|
55
|
+
/**
|
|
56
|
+
* Whether a CCI is one of Rio's own Peru accounts.
|
|
57
|
+
*
|
|
58
|
+
* Rio funds Alfin from its Interbank accounts, so those transfers appear on the
|
|
59
|
+
* Alfin statement as ordinary interbank credits carrying Rio's own account as
|
|
60
|
+
* the payer. Anything reading the statement to attribute customer payments has
|
|
61
|
+
* to exclude them, or a treasury top-up would be credited to whichever customer
|
|
62
|
+
* order happened to be awaiting the same amount.
|
|
63
|
+
*/
|
|
64
|
+
const isRioOwnPeruAccountCci = (cci) => {
|
|
65
|
+
if (!cci) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
return RIO_PERU_OWN_CCIS.includes((0, exports.normalizeCci)(cci));
|
|
69
|
+
};
|
|
70
|
+
exports.isRioOwnPeruAccountCci = isRioOwnPeruAccountCci;
|
|
43
71
|
// Shared house accounts. Kept here rather than in the order-payment path so the
|
|
44
72
|
// customer-facing whitelisting list and the payment instructions on an order can
|
|
45
73
|
// never drift apart.
|
|
@@ -78,7 +106,7 @@ const getStaticPayinBankDetails = (processor, fiat) => {
|
|
|
78
106
|
companyName: PERU_COMPANY_NAME,
|
|
79
107
|
companyAddress: PERU_COMPANY_ADDRESS,
|
|
80
108
|
accountNumber: "200-3004741070",
|
|
81
|
-
CCI:
|
|
109
|
+
CCI: INTERBANK_PERU_CCI_BY_FIAT[common_1.Fiat.PEN],
|
|
82
110
|
RUC: PERU_RUC,
|
|
83
111
|
};
|
|
84
112
|
}
|
|
@@ -88,7 +116,7 @@ const getStaticPayinBankDetails = (processor, fiat) => {
|
|
|
88
116
|
companyName: PERU_COMPANY_NAME,
|
|
89
117
|
companyAddress: PERU_COMPANY_ADDRESS,
|
|
90
118
|
accountNumber: "200-3004741088",
|
|
91
|
-
CCI:
|
|
119
|
+
CCI: INTERBANK_PERU_CCI_BY_FIAT[common_1.Fiat.USD],
|
|
92
120
|
RUC: PERU_RUC,
|
|
93
121
|
};
|
|
94
122
|
}
|
|
@@ -13,6 +13,6 @@ export interface ResolveProcessorParams {
|
|
|
13
13
|
}
|
|
14
14
|
export interface ResolveProcessorResult {
|
|
15
15
|
processor?: Processor;
|
|
16
|
-
reason: "customRioBankAccount" | "customRioBankAccountWithoutRail" | "split" | "onlyCandidate" | "enabledRailWithoutShare" | "
|
|
16
|
+
reason: "customRioBankAccount" | "customRioBankAccountWithoutRail" | "split" | "onlyCandidate" | "enabledRailWithoutShare" | "noEligibleCandidate" | "noEnabledCandidate";
|
|
17
17
|
}
|
|
18
18
|
export declare const resolveProcessor: ({ country, fiat, purpose, routingConfig, excludedProcessors, disabledProcessors, customRioBankAccount, randomSeed, }: ResolveProcessorParams) => ResolveProcessorResult;
|
|
@@ -23,11 +23,11 @@ const pickByShare = (candidates, position) => {
|
|
|
23
23
|
// from the configured split.
|
|
24
24
|
//
|
|
25
25
|
// A percentage divides volume between the rails that are actually available to
|
|
26
|
-
// the customer; it is not a switch. A rail left at zero,
|
|
27
|
-
//
|
|
28
|
-
// enabled, which is why the candidate set comes from
|
|
29
|
-
// from the rule. Switching a rail off is the only way to
|
|
30
|
-
// it.
|
|
26
|
+
// the customer; it is not a switch. A rail left at zero, left out of the rule, or
|
|
27
|
+
// belonging to a corridor with no rule at all still takes their orders when it is
|
|
28
|
+
// the only one they have left enabled, which is why the candidate set comes from
|
|
29
|
+
// the corridor rather than from the rule. Switching a rail off is the only way to
|
|
30
|
+
// keep an order away from it.
|
|
31
31
|
//
|
|
32
32
|
// Does no IO of its own - the routing config and the user's readiness are passed
|
|
33
33
|
// in - and the only nondeterminism is the per-order roll, which a caller can
|
|
@@ -73,10 +73,12 @@ const resolveProcessor = ({ country, fiat, purpose, routingConfig, excludedProce
|
|
|
73
73
|
}
|
|
74
74
|
return { processor, reason: "customRioBankAccount" };
|
|
75
75
|
}
|
|
76
|
+
// An absent rule is read as every rail at zero rather than as a reason to stop.
|
|
77
|
+
// Bailing out here would hand the decision to the structural default, which
|
|
78
|
+
// knows nothing about which rails the customer accepts, and every corridor is
|
|
79
|
+
// ruleless until an admin first saves one - as is any corridor whose shares
|
|
80
|
+
// were all cleared, since the settings page stores that as no rule at all.
|
|
76
81
|
const rule = getRule(routingConfig, country, fiat, purpose);
|
|
77
|
-
if (!rule) {
|
|
78
|
-
return { reason: "noRuleConfigured" };
|
|
79
|
-
}
|
|
80
82
|
// Starts from the corridor's rails rather than from the rails the rule names,
|
|
81
83
|
// because a percentage decides how volume is divided between the rails a
|
|
82
84
|
// customer can use - it is not what makes a rail usable. Also drops any share
|
|
@@ -91,16 +93,20 @@ const resolveProcessor = ({ country, fiat, purpose, routingConfig, excludedProce
|
|
|
91
93
|
return { reason: "noEnabledCandidate" };
|
|
92
94
|
}
|
|
93
95
|
const shares = candidates
|
|
94
|
-
.map((processor) =>
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
.map((processor) => {
|
|
97
|
+
var _a;
|
|
98
|
+
return ({
|
|
99
|
+
processor,
|
|
100
|
+
percentage: Number((_a = rule === null || rule === void 0 ? void 0 : rule.percentages) === null || _a === void 0 ? void 0 : _a[processor]) || 0,
|
|
101
|
+
});
|
|
102
|
+
})
|
|
98
103
|
.filter((candidate) => candidate.percentage > 0);
|
|
99
|
-
// None of the rails this customer can use carries a share
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
+
// None of the rails this customer can use carries a share - or no rule is
|
|
105
|
+
// configured at all - so there is no split to draw from. Refusing the order
|
|
106
|
+
// would read a zero as "never use this rail", when all it says is where volume
|
|
107
|
+
// goes while there is somewhere else to send it. Prefers the corridor default
|
|
108
|
+
// and otherwise the corridor's own order, so the rail a customer in this
|
|
109
|
+
// position gets is predictable rather than rolled.
|
|
104
110
|
if (!shares.length) {
|
|
105
111
|
const fallback = (0, common_1.getDefaultProcessor)(country, fiat, purpose, excludedProcessors);
|
|
106
112
|
return {
|
package/build/index.d.ts
CHANGED
|
@@ -95,6 +95,8 @@ export * from "./models/alfin-virtual-cci";
|
|
|
95
95
|
export * from "./models/alfin-settings";
|
|
96
96
|
export * from "./models/alfin-withdrawal";
|
|
97
97
|
export * from "./models/alfin-payin-notification";
|
|
98
|
+
export * from "./models/alfin-payin-origin";
|
|
99
|
+
export * from "./models/alfin-statement-credit";
|
|
98
100
|
export * from "./models/alfin-webhook-token";
|
|
99
101
|
export * from "./models/dashboard-push-notification-subscription";
|
|
100
102
|
export * from "./models/webauthn-credential";
|
package/build/index.js
CHANGED
|
@@ -111,6 +111,8 @@ __exportStar(require("./models/alfin-virtual-cci"), exports);
|
|
|
111
111
|
__exportStar(require("./models/alfin-settings"), exports);
|
|
112
112
|
__exportStar(require("./models/alfin-withdrawal"), exports);
|
|
113
113
|
__exportStar(require("./models/alfin-payin-notification"), exports);
|
|
114
|
+
__exportStar(require("./models/alfin-payin-origin"), exports);
|
|
115
|
+
__exportStar(require("./models/alfin-statement-credit"), exports);
|
|
114
116
|
__exportStar(require("./models/alfin-webhook-token"), exports);
|
|
115
117
|
__exportStar(require("./models/dashboard-push-notification-subscription"), exports);
|
|
116
118
|
__exportStar(require("./models/webauthn-credential"), exports);
|
|
@@ -19,6 +19,8 @@ interface AlfinPayinNotificationDoc extends Document {
|
|
|
19
19
|
amount: number;
|
|
20
20
|
processedAt: Date;
|
|
21
21
|
payload: Record<string, any>;
|
|
22
|
+
processingCompletedAt?: Date | null;
|
|
23
|
+
reconciledStatementCreditKey?: string;
|
|
22
24
|
}
|
|
23
25
|
interface AlfinPayinNotificationModel extends Model<AlfinPayinNotificationDoc> {
|
|
24
26
|
build(attrs: AlfinPayinNotificationAttrs): HydratedDocument<AlfinPayinNotificationDoc>;
|
|
@@ -37,6 +37,17 @@ const buildAlfinPayinNotification = (mongoose) => {
|
|
|
37
37
|
payload: {
|
|
38
38
|
type: mongoose.Schema.Types.Mixed,
|
|
39
39
|
},
|
|
40
|
+
// Defaulted so every new notification carries the field explicitly, which
|
|
41
|
+
// is what separates one that has not finished from one written before this
|
|
42
|
+
// existed. A query that cannot tell those apart either credits a payin
|
|
43
|
+
// twice or not at all.
|
|
44
|
+
processingCompletedAt: {
|
|
45
|
+
type: mongoose.Schema.Types.Date,
|
|
46
|
+
default: null,
|
|
47
|
+
},
|
|
48
|
+
reconciledStatementCreditKey: {
|
|
49
|
+
type: String,
|
|
50
|
+
},
|
|
40
51
|
}, {
|
|
41
52
|
toJSON: {
|
|
42
53
|
transform(doc, ret) {
|
|
@@ -46,6 +57,12 @@ const buildAlfinPayinNotification = (mongoose) => {
|
|
|
46
57
|
},
|
|
47
58
|
},
|
|
48
59
|
});
|
|
60
|
+
// Supports the claim lookup, which searches unclaimed notifications by
|
|
61
|
+
// currency and amount within a few days of a statement line.
|
|
62
|
+
AlfinPayinNotificationSchema.index({ fiat: 1, amount: 1, processedAt: 1 });
|
|
63
|
+
// One statement line can only ever be the same money as one notification.
|
|
64
|
+
// Sparse so the unclaimed majority are not indexed as duplicate nulls.
|
|
65
|
+
AlfinPayinNotificationSchema.index({ reconciledStatementCreditKey: 1 }, { unique: true, sparse: true });
|
|
49
66
|
AlfinPayinNotificationSchema.statics.build = (attrs) => {
|
|
50
67
|
return new AlfinPayinNotification(attrs);
|
|
51
68
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Mongoose, Model, Document, HydratedDocument } from "mongoose";
|
|
2
|
+
type AlfinPayinOriginSource = "payinWebhook" | "payinVerification";
|
|
3
|
+
interface AlfinPayinOriginAttrs {
|
|
4
|
+
CCI: string;
|
|
5
|
+
userId: string;
|
|
6
|
+
source: AlfinPayinOriginSource;
|
|
7
|
+
accountHolderName?: string;
|
|
8
|
+
firstSeenAt: Date;
|
|
9
|
+
lastSeenAt: Date;
|
|
10
|
+
}
|
|
11
|
+
interface AlfinPayinOriginDoc extends Document {
|
|
12
|
+
CCI: string;
|
|
13
|
+
userId: string;
|
|
14
|
+
source: AlfinPayinOriginSource;
|
|
15
|
+
accountHolderName?: string;
|
|
16
|
+
firstSeenAt: Date;
|
|
17
|
+
lastSeenAt: Date;
|
|
18
|
+
}
|
|
19
|
+
interface AlfinPayinOriginModel extends Model<AlfinPayinOriginDoc> {
|
|
20
|
+
build(attrs: AlfinPayinOriginAttrs): HydratedDocument<AlfinPayinOriginDoc>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Accounts customers have paid us from at Alfin, learned as they pay.
|
|
24
|
+
*
|
|
25
|
+
* A payment that lands on a user's virtual CCI identifies its owner outright, so
|
|
26
|
+
* nothing here is needed to process it. It exists for payments that cannot use a
|
|
27
|
+
* virtual CCI at all - anything over the CCE immediate-transfer ceiling, which
|
|
28
|
+
* the CCIV rejects - because those land on the principal account, raise no
|
|
29
|
+
* notification, and are only visible as an account-statement credit. The
|
|
30
|
+
* statement carries the payer's CCI, so a customer's first small payment through
|
|
31
|
+
* their CCIV is what teaches us where their large ones will come from.
|
|
32
|
+
*
|
|
33
|
+
* One document per account/user pair rather than one per account: a shared
|
|
34
|
+
* corporate account can legitimately belong to more than one user, and a
|
|
35
|
+
* statement credit from an account claimed by two users cannot be attributed to
|
|
36
|
+
* either, which the matcher detects by finding more than one document.
|
|
37
|
+
*/
|
|
38
|
+
declare const buildAlfinPayinOrigin: (mongoose: Mongoose) => AlfinPayinOriginModel;
|
|
39
|
+
export { buildAlfinPayinOrigin, AlfinPayinOriginDoc, AlfinPayinOriginAttrs, AlfinPayinOriginSource, };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildAlfinPayinOrigin = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Accounts customers have paid us from at Alfin, learned as they pay.
|
|
6
|
+
*
|
|
7
|
+
* A payment that lands on a user's virtual CCI identifies its owner outright, so
|
|
8
|
+
* nothing here is needed to process it. It exists for payments that cannot use a
|
|
9
|
+
* virtual CCI at all - anything over the CCE immediate-transfer ceiling, which
|
|
10
|
+
* the CCIV rejects - because those land on the principal account, raise no
|
|
11
|
+
* notification, and are only visible as an account-statement credit. The
|
|
12
|
+
* statement carries the payer's CCI, so a customer's first small payment through
|
|
13
|
+
* their CCIV is what teaches us where their large ones will come from.
|
|
14
|
+
*
|
|
15
|
+
* One document per account/user pair rather than one per account: a shared
|
|
16
|
+
* corporate account can legitimately belong to more than one user, and a
|
|
17
|
+
* statement credit from an account claimed by two users cannot be attributed to
|
|
18
|
+
* either, which the matcher detects by finding more than one document.
|
|
19
|
+
*/
|
|
20
|
+
const buildAlfinPayinOrigin = (mongoose) => {
|
|
21
|
+
if (mongoose.models.AlfinPayinOrigin) {
|
|
22
|
+
return mongoose.model("AlfinPayinOrigin");
|
|
23
|
+
}
|
|
24
|
+
const AlfinPayinOriginSchema = new mongoose.Schema({
|
|
25
|
+
CCI: {
|
|
26
|
+
type: String,
|
|
27
|
+
required: true,
|
|
28
|
+
},
|
|
29
|
+
userId: {
|
|
30
|
+
type: String,
|
|
31
|
+
required: true,
|
|
32
|
+
index: true,
|
|
33
|
+
},
|
|
34
|
+
source: {
|
|
35
|
+
type: String,
|
|
36
|
+
required: true,
|
|
37
|
+
},
|
|
38
|
+
accountHolderName: {
|
|
39
|
+
type: String,
|
|
40
|
+
},
|
|
41
|
+
firstSeenAt: {
|
|
42
|
+
type: mongoose.Schema.Types.Date,
|
|
43
|
+
required: true,
|
|
44
|
+
},
|
|
45
|
+
lastSeenAt: {
|
|
46
|
+
type: mongoose.Schema.Types.Date,
|
|
47
|
+
required: true,
|
|
48
|
+
},
|
|
49
|
+
}, {
|
|
50
|
+
toJSON: {
|
|
51
|
+
transform(doc, ret) {
|
|
52
|
+
ret.id = ret._id.valueOf();
|
|
53
|
+
delete ret._id;
|
|
54
|
+
delete ret.__v;
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
AlfinPayinOriginSchema.index({ CCI: 1, userId: 1 }, { unique: true });
|
|
59
|
+
AlfinPayinOriginSchema.statics.build = (attrs) => {
|
|
60
|
+
return new AlfinPayinOrigin(attrs);
|
|
61
|
+
};
|
|
62
|
+
const AlfinPayinOrigin = mongoose.model("AlfinPayinOrigin", AlfinPayinOriginSchema);
|
|
63
|
+
return AlfinPayinOrigin;
|
|
64
|
+
};
|
|
65
|
+
exports.buildAlfinPayinOrigin = buildAlfinPayinOrigin;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Fiat } from "@riocrypto/common";
|
|
2
|
+
import { Mongoose, Model, Document, HydratedDocument } from "mongoose";
|
|
3
|
+
type AlfinStatementCreditStatus = "matched" | "attributedToWebhook" | "ignored" | "awaitingApproval" | "unmatched";
|
|
4
|
+
interface AlfinStatementCreditAttrs {
|
|
5
|
+
uniqueCompositeKey: string;
|
|
6
|
+
movimientoUId: string;
|
|
7
|
+
ordinal?: number;
|
|
8
|
+
fiat: Fiat;
|
|
9
|
+
amount: number;
|
|
10
|
+
postedAt: Date;
|
|
11
|
+
concepto?: string;
|
|
12
|
+
referencia?: string;
|
|
13
|
+
originCCI?: string;
|
|
14
|
+
originName?: string;
|
|
15
|
+
status: AlfinStatementCreditStatus;
|
|
16
|
+
reason?: string;
|
|
17
|
+
userId?: string;
|
|
18
|
+
orderId?: string;
|
|
19
|
+
bulkBankPaymentId?: string;
|
|
20
|
+
evaluatedAt: Date;
|
|
21
|
+
}
|
|
22
|
+
interface AlfinStatementCreditDoc extends Document {
|
|
23
|
+
uniqueCompositeKey: string;
|
|
24
|
+
movimientoUId: string;
|
|
25
|
+
ordinal?: number;
|
|
26
|
+
fiat: Fiat;
|
|
27
|
+
amount: number;
|
|
28
|
+
postedAt: Date;
|
|
29
|
+
concepto?: string;
|
|
30
|
+
referencia?: string;
|
|
31
|
+
originCCI?: string;
|
|
32
|
+
originName?: string;
|
|
33
|
+
status: AlfinStatementCreditStatus;
|
|
34
|
+
reason?: string;
|
|
35
|
+
userId?: string;
|
|
36
|
+
orderId?: string;
|
|
37
|
+
bulkBankPaymentId?: string;
|
|
38
|
+
evaluatedAt: Date;
|
|
39
|
+
}
|
|
40
|
+
interface AlfinStatementCreditModel extends Model<AlfinStatementCreditDoc> {
|
|
41
|
+
build(attrs: AlfinStatementCreditAttrs): HydratedDocument<AlfinStatementCreditDoc>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* One record per account-statement credit we have evaluated for payment
|
|
45
|
+
* matching, and the decision we reached.
|
|
46
|
+
*
|
|
47
|
+
* The statement is re-read on every poll over a 30-day window, so this is what
|
|
48
|
+
* stops a credit from being attributed twice: the key is inserted before any
|
|
49
|
+
* matching happens, and a duplicate-key error means another run already owns
|
|
50
|
+
* this line. It doubles as the audit trail for why a credit was or was not
|
|
51
|
+
* attributed, which is the only record of that reasoning - the credit itself
|
|
52
|
+
* arrives with no notification behind it.
|
|
53
|
+
*/
|
|
54
|
+
declare const buildAlfinStatementCredit: (mongoose: Mongoose) => AlfinStatementCreditModel;
|
|
55
|
+
export { buildAlfinStatementCredit, AlfinStatementCreditDoc, AlfinStatementCreditAttrs, AlfinStatementCreditStatus, };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildAlfinStatementCredit = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* One record per account-statement credit we have evaluated for payment
|
|
6
|
+
* matching, and the decision we reached.
|
|
7
|
+
*
|
|
8
|
+
* The statement is re-read on every poll over a 30-day window, so this is what
|
|
9
|
+
* stops a credit from being attributed twice: the key is inserted before any
|
|
10
|
+
* matching happens, and a duplicate-key error means another run already owns
|
|
11
|
+
* this line. It doubles as the audit trail for why a credit was or was not
|
|
12
|
+
* attributed, which is the only record of that reasoning - the credit itself
|
|
13
|
+
* arrives with no notification behind it.
|
|
14
|
+
*/
|
|
15
|
+
const buildAlfinStatementCredit = (mongoose) => {
|
|
16
|
+
if (mongoose.models.AlfinStatementCredit) {
|
|
17
|
+
return mongoose.model("AlfinStatementCredit");
|
|
18
|
+
}
|
|
19
|
+
const AlfinStatementCreditSchema = new mongoose.Schema({
|
|
20
|
+
uniqueCompositeKey: {
|
|
21
|
+
type: String,
|
|
22
|
+
required: true,
|
|
23
|
+
unique: true,
|
|
24
|
+
},
|
|
25
|
+
movimientoUId: {
|
|
26
|
+
type: String,
|
|
27
|
+
required: true,
|
|
28
|
+
},
|
|
29
|
+
ordinal: {
|
|
30
|
+
type: Number,
|
|
31
|
+
},
|
|
32
|
+
fiat: {
|
|
33
|
+
type: String,
|
|
34
|
+
required: true,
|
|
35
|
+
},
|
|
36
|
+
amount: {
|
|
37
|
+
type: Number,
|
|
38
|
+
required: true,
|
|
39
|
+
},
|
|
40
|
+
postedAt: {
|
|
41
|
+
type: mongoose.Schema.Types.Date,
|
|
42
|
+
required: true,
|
|
43
|
+
},
|
|
44
|
+
concepto: {
|
|
45
|
+
type: String,
|
|
46
|
+
},
|
|
47
|
+
referencia: {
|
|
48
|
+
type: String,
|
|
49
|
+
},
|
|
50
|
+
originCCI: {
|
|
51
|
+
type: String,
|
|
52
|
+
},
|
|
53
|
+
originName: {
|
|
54
|
+
type: String,
|
|
55
|
+
},
|
|
56
|
+
status: {
|
|
57
|
+
type: String,
|
|
58
|
+
required: true,
|
|
59
|
+
},
|
|
60
|
+
reason: {
|
|
61
|
+
type: String,
|
|
62
|
+
},
|
|
63
|
+
userId: {
|
|
64
|
+
type: String,
|
|
65
|
+
},
|
|
66
|
+
orderId: {
|
|
67
|
+
type: String,
|
|
68
|
+
},
|
|
69
|
+
bulkBankPaymentId: {
|
|
70
|
+
type: String,
|
|
71
|
+
},
|
|
72
|
+
evaluatedAt: {
|
|
73
|
+
type: mongoose.Schema.Types.Date,
|
|
74
|
+
required: true,
|
|
75
|
+
},
|
|
76
|
+
}, {
|
|
77
|
+
toJSON: {
|
|
78
|
+
transform(doc, ret) {
|
|
79
|
+
ret.id = ret._id.valueOf();
|
|
80
|
+
delete ret._id;
|
|
81
|
+
delete ret.__v;
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
AlfinStatementCreditSchema.statics.build = (attrs) => {
|
|
86
|
+
return new AlfinStatementCredit(attrs);
|
|
87
|
+
};
|
|
88
|
+
const AlfinStatementCredit = mongoose.model("AlfinStatementCredit", AlfinStatementCreditSchema);
|
|
89
|
+
return AlfinStatementCredit;
|
|
90
|
+
};
|
|
91
|
+
exports.buildAlfinStatementCredit = buildAlfinStatementCredit;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riocrypto/common-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2881",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@google-cloud/secret-manager": "^5.6.0",
|
|
29
29
|
"@google-cloud/storage": "^7.19.0",
|
|
30
30
|
"@hyperdx/node-opentelemetry": "^0.10.3",
|
|
31
|
-
"@riocrypto/common": "1.0.
|
|
31
|
+
"@riocrypto/common": "1.0.2702",
|
|
32
32
|
"@slack/web-api": "^7.15.0",
|
|
33
33
|
"@types/express": "^4.17.25",
|
|
34
34
|
"axios": "1.18.1",
|