backend-manager 5.0.175 → 5.0.177
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 +11 -0
- package/_zombie-sub-guard-wip/journey-payments-zombie-sub.js +159 -0
- package/_zombie-sub-guard-wip/on-write.js +442 -0
- package/_zombie-sub-guard-wip/test-accounts.diff +21 -0
- package/package.json +1 -1
- package/src/manager/events/firestore/payments-disputes/on-write.js +14 -260
- package/src/manager/events/firestore/payments-disputes/processors/stripe.js +213 -0
- package/src/manager/events/firestore/payments-webhooks/transitions/send-email.js +9 -4
- package/src/manager/events/firestore/payments-webhooks/transitions/subscription/payment-recovered.js +1 -0
- package/src/manager/routes/payments/dispute-alert/processors/chargeblast.js +2 -2
- package/test/routes/payments/dispute-alert.js +89 -4
|
@@ -115,6 +115,14 @@ module.exports = {
|
|
|
115
115
|
amount: 29.99,
|
|
116
116
|
transactionDate: '2026-03-07 14:30:00',
|
|
117
117
|
processor: 'stripe',
|
|
118
|
+
alertType: 'FRAUD',
|
|
119
|
+
customerEmail: 'test@example.com',
|
|
120
|
+
externalOrder: 'ch_test123',
|
|
121
|
+
metadata: 'pi_test456',
|
|
122
|
+
externalUrl: 'https://dashboard.stripe.com/charges/ch_test123',
|
|
123
|
+
reasonCode: 'WIP',
|
|
124
|
+
subprovider: 'Ethoca',
|
|
125
|
+
isRefunded: false,
|
|
118
126
|
});
|
|
119
127
|
|
|
120
128
|
assert.isSuccess(response, 'Should accept valid Chargeblast alert');
|
|
@@ -129,13 +137,23 @@ module.exports = {
|
|
|
129
137
|
'Status should be pending or processing',
|
|
130
138
|
);
|
|
131
139
|
|
|
132
|
-
// Verify normalized alert data
|
|
140
|
+
// Verify core normalized alert data
|
|
133
141
|
assert.equal(doc.alert.card.last4, '4242', 'Should extract last4 from full card number');
|
|
134
142
|
assert.equal(doc.alert.card.brand, 'visa', 'Should lowercase card brand');
|
|
135
143
|
assert.equal(doc.alert.amount, 29.99, 'Amount should be preserved');
|
|
136
144
|
assert.equal(doc.alert.transactionDate, '2026-03-07', 'Should extract date without time');
|
|
137
145
|
assert.equal(doc.alert.processor, 'stripe', 'Processor should be stripe');
|
|
138
146
|
|
|
147
|
+
// Verify new normalized fields
|
|
148
|
+
assert.equal(doc.alert.alertType, 'FRAUD', 'Alert type should be preserved');
|
|
149
|
+
assert.equal(doc.alert.customerEmail, 'test@example.com', 'Customer email should be preserved');
|
|
150
|
+
assert.equal(doc.alert.chargeId, 'ch_test123', 'Charge ID should be extracted from externalOrder');
|
|
151
|
+
assert.equal(doc.alert.paymentIntentId, 'pi_test456', 'Payment intent ID should be extracted from metadata');
|
|
152
|
+
assert.equal(doc.alert.stripeUrl, 'https://dashboard.stripe.com/charges/ch_test123', 'Stripe URL should be preserved');
|
|
153
|
+
assert.equal(doc.alert.reasonCode, 'WIP', 'Reason code should be preserved');
|
|
154
|
+
assert.equal(doc.alert.subprovider, 'Ethoca', 'Subprovider should be preserved');
|
|
155
|
+
assert.equal(doc.alert.isRefunded, false, 'isRefunded should be preserved');
|
|
156
|
+
|
|
139
157
|
// Verify raw payload is preserved
|
|
140
158
|
assert.ok(doc.raw, 'Raw payload should be preserved');
|
|
141
159
|
assert.equal(doc.raw.id, alertId, 'Raw id should match');
|
|
@@ -145,6 +163,73 @@ module.exports = {
|
|
|
145
163
|
},
|
|
146
164
|
},
|
|
147
165
|
|
|
166
|
+
{
|
|
167
|
+
name: 'accepts-alert-with-alertId-field',
|
|
168
|
+
auth: 'none',
|
|
169
|
+
async run({ http, assert, firestore }) {
|
|
170
|
+
const alertId = '_test-dispute-alertid-field';
|
|
171
|
+
|
|
172
|
+
// Clean up any existing doc
|
|
173
|
+
await firestore.delete(`payments-disputes/${alertId}`);
|
|
174
|
+
|
|
175
|
+
// Chargeblast alert.created events use alertId instead of id
|
|
176
|
+
const response = await http.as('none').post(`payments/dispute-alert?key=${process.env.BACKEND_MANAGER_KEY}`, {
|
|
177
|
+
alertId: alertId,
|
|
178
|
+
card: '546616******5805',
|
|
179
|
+
cardBrand: 'Mastercard',
|
|
180
|
+
amount: 8,
|
|
181
|
+
transactionDate: '2026-03-19 00:00:00.000000Z',
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
assert.isSuccess(response, 'Should accept alert using alertId field');
|
|
185
|
+
|
|
186
|
+
const doc = await firestore.get(`payments-disputes/${alertId}`);
|
|
187
|
+
assert.ok(doc, 'Dispute doc should exist in Firestore');
|
|
188
|
+
assert.equal(doc.id, alertId, 'Doc ID should match alertId');
|
|
189
|
+
assert.equal(doc.alert.id, alertId, 'Alert id should be set from alertId');
|
|
190
|
+
assert.equal(doc.alert.card.last4, '5805', 'Should extract last4 from masked card');
|
|
191
|
+
|
|
192
|
+
// Clean up
|
|
193
|
+
await firestore.delete(`payments-disputes/${alertId}`);
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
{
|
|
198
|
+
name: 'accepts-alert-without-optional-fields',
|
|
199
|
+
auth: 'none',
|
|
200
|
+
async run({ http, assert, firestore }) {
|
|
201
|
+
const alertId = '_test-dispute-minimal';
|
|
202
|
+
|
|
203
|
+
// Clean up any existing doc
|
|
204
|
+
await firestore.delete(`payments-disputes/${alertId}`);
|
|
205
|
+
|
|
206
|
+
// Send minimal alert (alert.created shape — no externalOrder, metadata, etc.)
|
|
207
|
+
const response = await http.as('none').post(`payments/dispute-alert?key=${process.env.BACKEND_MANAGER_KEY}`, {
|
|
208
|
+
id: alertId,
|
|
209
|
+
card: '9124',
|
|
210
|
+
amount: 10,
|
|
211
|
+
transactionDate: '2026-03-21 00:01:02',
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
assert.isSuccess(response, 'Should accept minimal alert');
|
|
215
|
+
|
|
216
|
+
const doc = await firestore.get(`payments-disputes/${alertId}`);
|
|
217
|
+
assert.equal(doc.alert.card.last4, '9124', 'Should use card as last4');
|
|
218
|
+
assert.equal(doc.alert.processor, 'stripe', 'Processor should default to stripe');
|
|
219
|
+
assert.equal(doc.alert.chargeId, null, 'Charge ID should be null when not provided');
|
|
220
|
+
assert.equal(doc.alert.paymentIntentId, null, 'Payment intent should be null when not provided');
|
|
221
|
+
assert.equal(doc.alert.customerEmail, null, 'Customer email should be null when not provided');
|
|
222
|
+
assert.equal(doc.alert.alertType, null, 'Alert type should be null when not provided');
|
|
223
|
+
assert.equal(doc.alert.stripeUrl, null, 'Stripe URL should be null when not provided');
|
|
224
|
+
assert.equal(doc.alert.reasonCode, null, 'Reason code should be null when not provided');
|
|
225
|
+
assert.equal(doc.alert.subprovider, null, 'Subprovider should be null when not provided');
|
|
226
|
+
assert.equal(doc.alert.isRefunded, false, 'isRefunded should default to false');
|
|
227
|
+
|
|
228
|
+
// Clean up
|
|
229
|
+
await firestore.delete(`payments-disputes/${alertId}`);
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
|
|
148
233
|
{
|
|
149
234
|
name: 'accepts-alert-with-last4-only',
|
|
150
235
|
auth: 'none',
|
|
@@ -242,7 +327,7 @@ module.exports = {
|
|
|
242
327
|
},
|
|
243
328
|
|
|
244
329
|
{
|
|
245
|
-
name: 'defaults-
|
|
330
|
+
name: 'defaults-provider-to-chargeblast',
|
|
246
331
|
auth: 'none',
|
|
247
332
|
async run({ http, assert, firestore }) {
|
|
248
333
|
const alertId = '_test-dispute-default-provider';
|
|
@@ -250,7 +335,7 @@ module.exports = {
|
|
|
250
335
|
// Clean up any existing doc
|
|
251
336
|
await firestore.delete(`payments-disputes/${alertId}`);
|
|
252
337
|
|
|
253
|
-
// Send without
|
|
338
|
+
// Send without provider query param
|
|
254
339
|
const response = await http.as('none').post(`payments/dispute-alert?key=${process.env.BACKEND_MANAGER_KEY}`, {
|
|
255
340
|
id: alertId,
|
|
256
341
|
card: '4242',
|
|
@@ -258,7 +343,7 @@ module.exports = {
|
|
|
258
343
|
transactionDate: '2026-01-15',
|
|
259
344
|
});
|
|
260
345
|
|
|
261
|
-
assert.isSuccess(response, 'Should accept without explicit
|
|
346
|
+
assert.isSuccess(response, 'Should accept without explicit provider param');
|
|
262
347
|
|
|
263
348
|
const doc = await firestore.get(`payments-disputes/${alertId}`);
|
|
264
349
|
assert.equal(doc.provider, 'chargeblast', 'Provider should default to chargeblast');
|