@cimplify/sdk 0.102.0 → 0.104.0
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/dist/advanced.d.mts +3 -3
- package/dist/advanced.d.ts +3 -3
- package/dist/advanced.js +23 -22
- package/dist/advanced.mjs +4 -3
- package/dist/{chunk-DCMXUKDQ.mjs → chunk-2WPVUIHX.mjs} +455 -105
- package/dist/{chunk-NIOUSKQQ.js → chunk-4BKOKHE3.js} +9 -0
- package/dist/{chunk-YDA46OZ6.js → chunk-5BDYDZ4U.js} +722 -90
- package/dist/{chunk-4KNFBPV2.mjs → chunk-5RT4HYMP.mjs} +61 -15
- package/dist/{chunk-WMEC5JWN.js → chunk-7PDEX54K.js} +50 -13
- package/dist/chunk-CNN7Z2IP.js +125 -0
- package/dist/{chunk-DLW3RWRK.mjs → chunk-DYIAX3WI.mjs} +46 -12
- package/dist/{chunk-LOWSMGRT.js → chunk-E4K2VQDD.js} +64 -16
- package/dist/chunk-GOHSXBKW.mjs +105 -0
- package/dist/{chunk-O3YUHLZL.mjs → chunk-H3RATH4B.mjs} +9 -0
- package/dist/{chunk-YER7DIOM.js → chunk-IQFFSKE2.js} +753 -594
- package/dist/{chunk-Z3K2D3TE.mjs → chunk-OCCNG6MO.mjs} +735 -558
- package/dist/{chunk-DKLHCZ5M.mjs → chunk-OKADBZAI.mjs} +652 -25
- package/dist/{chunk-EAZGA7LD.js → chunk-YVAEY3VC.js} +457 -107
- package/dist/{client-nsiMwuC1.d.ts → client-BVNWjk6W.d.ts} +2 -2
- package/dist/{client-B40KFazg.d.ts → client-BuLcOWLv.d.ts} +202 -319
- package/dist/{client-BizGfqB7.d.mts → client-D5AoobFc.d.mts} +202 -319
- package/dist/{client-BdErclfU.d.mts → client-fM716k7G.d.mts} +2 -2
- package/dist/{index-DpmnI__D.d.mts → index-BtcoqrY1.d.ts} +14 -4
- package/dist/{index-nEyXWIyR.d.ts → index-D7Tf3v7c.d.mts} +14 -4
- package/dist/index.d.mts +83 -8
- package/dist/index.d.ts +83 -8
- package/dist/index.js +203 -169
- package/dist/index.mjs +7 -5
- package/dist/link-D9iSVxt5.d.mts +308 -0
- package/dist/link-D9iSVxt5.d.ts +308 -0
- package/dist/mock/cli.mjs +463 -104
- package/dist/mock/library.js +463 -104
- package/dist/mock/library.mjs +463 -104
- package/dist/mock/msw.js +463 -104
- package/dist/mock/msw.mjs +463 -104
- package/dist/{product-Byf0unSy.d.mts → payment-g0HFkEDU.d.mts} +708 -61
- package/dist/{product-Byf0unSy.d.ts → payment-g0HFkEDU.d.ts} +708 -61
- package/dist/{price-BstChV9a.d.ts → price-BLIeAb8K.d.ts} +1 -1
- package/dist/{price-CS4E5zLS.d.mts → price-Czq_cTC_.d.mts} +1 -1
- package/dist/react.d.mts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js +194 -169
- package/dist/react.mjs +55 -30
- package/dist/{server-DqbZh8Bk.d.mts → server-BkVhOIwn.d.mts} +14 -10
- package/dist/{server-Cj40R2ZD.d.ts → server-DKK_D-PP.d.ts} +14 -10
- package/dist/server.d.mts +4 -4
- package/dist/server.d.ts +4 -4
- package/dist/server.js +12 -10
- package/dist/server.mjs +6 -4
- package/dist/testing/msw.d.mts +2 -2
- package/dist/testing/msw.d.ts +2 -2
- package/dist/testing/msw.js +4 -3
- package/dist/testing/msw.mjs +3 -2
- package/dist/testing/suite.d.mts +6 -6
- package/dist/testing/suite.d.ts +6 -6
- package/dist/testing/suite.js +26 -25
- package/dist/testing/suite.mjs +7 -6
- package/dist/testing.d.mts +195 -56
- package/dist/testing.d.ts +195 -56
- package/dist/testing.js +95 -82
- package/dist/testing.mjs +14 -9
- package/dist/utils.d.mts +4 -4
- package/dist/utils.d.ts +4 -4
- package/dist/utils.js +37 -29
- package/dist/utils.mjs +2 -2
- package/package.json +7 -1
- package/registry/chat-widget.json +1 -1
- package/dist/payment-l0rkieEQ.d.mts +0 -113
- package/dist/payment-vzNnIi1n.d.ts +0 -113
package/dist/mock/cli.mjs
CHANGED
|
@@ -3034,10 +3034,14 @@ var ERROR_SUGGESTIONS = {
|
|
|
3034
3034
|
PRICE_CHANGED: "Prices changed since the quote was created. Refresh pricing, show the new total to the shopper, and require explicit confirmation before re-submitting.",
|
|
3035
3035
|
PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
|
|
3036
3036
|
PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
|
|
3037
|
+
PAYMENT_CAPABILITY_MISMATCH: "Refresh collection capabilities for the exact tenant and presentment currency before retrying.",
|
|
3038
|
+
UNSUPPORTED_CURRENCY: "Choose a supported presentment currency before loading payment methods or submitting checkout.",
|
|
3037
3039
|
INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
|
|
3038
3040
|
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
3039
3041
|
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
3040
3042
|
OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
|
|
3043
|
+
OTP_CHALLENGE_EXHAUSTED: "This verification challenge has no attempts left. Continue checkout without saved details or request a fresh challenge.",
|
|
3044
|
+
OTP_CHALLENGE_CONSUMED: "This verification challenge has already been used. Continue with the established session or request a fresh challenge.",
|
|
3041
3045
|
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
3042
3046
|
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
3043
3047
|
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
@@ -3182,6 +3186,12 @@ function getQueryNum(c, key) {
|
|
|
3182
3186
|
return Number.isFinite(n) ? n : void 0;
|
|
3183
3187
|
}
|
|
3184
3188
|
|
|
3189
|
+
// src/constants.ts
|
|
3190
|
+
var PAYMENT_METHOD = {
|
|
3191
|
+
MOBILE_MONEY: "mobile_money",
|
|
3192
|
+
CARD: "card"
|
|
3193
|
+
};
|
|
3194
|
+
|
|
3185
3195
|
// src/mock/routes/v1.ts
|
|
3186
3196
|
function buildV1(deps) {
|
|
3187
3197
|
const app = new Hono2();
|
|
@@ -3198,10 +3208,22 @@ function buildV1(deps) {
|
|
|
3198
3208
|
}));
|
|
3199
3209
|
});
|
|
3200
3210
|
app.get("/business", (c) => tryRoute(c, () => deps.business.primary()));
|
|
3201
|
-
app.get(
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3211
|
+
app.get(
|
|
3212
|
+
"/business/by-handle/:handle",
|
|
3213
|
+
(c) => tryRoute(c, () => deps.business.byHandle(c.req.param("handle")))
|
|
3214
|
+
);
|
|
3215
|
+
app.get(
|
|
3216
|
+
"/business/by-domain",
|
|
3217
|
+
(c) => tryRoute(c, () => deps.business.byDomain(c.req.query("domain") ?? ""))
|
|
3218
|
+
);
|
|
3219
|
+
app.get(
|
|
3220
|
+
"/business/settings",
|
|
3221
|
+
(c) => tryRoute(c, () => deps.business.settings(deps.defaultBusinessId))
|
|
3222
|
+
);
|
|
3223
|
+
app.get(
|
|
3224
|
+
"/business/locations",
|
|
3225
|
+
(c) => tryRoute(c, () => deps.business.locations(deps.defaultBusinessId))
|
|
3226
|
+
);
|
|
3205
3227
|
app.get("/business/hours", (c) => tryRoute(c, () => deps.business.hours(deps.defaultBusinessId)));
|
|
3206
3228
|
app.get("/catalogue", (c) => tryRoute(c, () => deps.catalogue.snapshot(deps.defaultBusinessId)));
|
|
3207
3229
|
app.get(
|
|
@@ -3216,57 +3238,165 @@ function buildV1(deps) {
|
|
|
3216
3238
|
})
|
|
3217
3239
|
)
|
|
3218
3240
|
);
|
|
3219
|
-
app.get(
|
|
3220
|
-
|
|
3221
|
-
|
|
3241
|
+
app.get(
|
|
3242
|
+
"/catalogue/products/:product_id",
|
|
3243
|
+
(c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("product_id")))
|
|
3244
|
+
);
|
|
3245
|
+
app.get(
|
|
3246
|
+
"/catalogue/products/:product_id/variants",
|
|
3247
|
+
(c) => tryRoute(c, () => deps.catalogue.getProductVariants(c.req.param("product_id")))
|
|
3248
|
+
);
|
|
3249
|
+
app.get(
|
|
3250
|
+
"/catalogue/products/:product_id/variant-axes",
|
|
3251
|
+
(c) => tryRoute(c, () => deps.catalogue.getProductVariantAxes(c.req.param("product_id")))
|
|
3252
|
+
);
|
|
3222
3253
|
app.get(
|
|
3223
3254
|
"/catalogue/products/:product_id/variants/:variant_id",
|
|
3224
|
-
(c) => tryRoute(
|
|
3255
|
+
(c) => tryRoute(
|
|
3256
|
+
c,
|
|
3257
|
+
() => deps.catalogue.getProductVariantById(c.req.param("product_id"), c.req.param("variant_id"))
|
|
3258
|
+
)
|
|
3225
3259
|
);
|
|
3226
3260
|
app.post("/catalogue/products/:product_id/variants/find", async (c) => {
|
|
3227
3261
|
const body = await c.req.json().catch(() => ({}));
|
|
3228
3262
|
return tryRoute(
|
|
3229
3263
|
c,
|
|
3230
|
-
() => deps.catalogue.findProductVariant(
|
|
3264
|
+
() => deps.catalogue.findProductVariant(
|
|
3265
|
+
c.req.param("product_id"),
|
|
3266
|
+
body.axis_selections ?? body.properties ?? {}
|
|
3267
|
+
)
|
|
3231
3268
|
);
|
|
3232
3269
|
});
|
|
3233
|
-
app.get(
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
app.get(
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
app.get(
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
app.get(
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3270
|
+
app.get(
|
|
3271
|
+
"/catalogue/products/:product_id/add-ons",
|
|
3272
|
+
(c) => tryRoute(c, () => deps.catalogue.getProductAddOns(c.req.param("product_id")))
|
|
3273
|
+
);
|
|
3274
|
+
app.get(
|
|
3275
|
+
"/catalogue/categories",
|
|
3276
|
+
(c) => tryRoute(c, () => deps.catalogue.listCategories(deps.defaultBusinessId))
|
|
3277
|
+
);
|
|
3278
|
+
app.get(
|
|
3279
|
+
"/catalogue/categories/:category_id",
|
|
3280
|
+
(c) => tryRoute(c, () => deps.catalogue.getCategory(c.req.param("category_id")))
|
|
3281
|
+
);
|
|
3282
|
+
app.get(
|
|
3283
|
+
"/catalogue/categories/:category_id/products",
|
|
3284
|
+
(c) => tryRoute(c, () => deps.catalogue.getCategoryProducts(c.req.param("category_id")))
|
|
3285
|
+
);
|
|
3286
|
+
app.get(
|
|
3287
|
+
"/catalogue/categories/:category_id/attributes",
|
|
3288
|
+
(c) => tryRoute(c, () => deps.catalogue.getCategoryAttributes(c.req.param("category_id")))
|
|
3289
|
+
);
|
|
3290
|
+
app.get(
|
|
3291
|
+
"/catalogue/categories/:category_id/deals",
|
|
3292
|
+
(c) => tryRoute(c, () => deps.catalogue.getCategoryDeals(c.req.param("category_id")))
|
|
3293
|
+
);
|
|
3294
|
+
app.get(
|
|
3295
|
+
"/catalogue/collections",
|
|
3296
|
+
(c) => tryRoute(c, () => deps.catalogue.listCollections(deps.defaultBusinessId))
|
|
3297
|
+
);
|
|
3298
|
+
app.get(
|
|
3299
|
+
"/catalogue/collections/:collection_id",
|
|
3300
|
+
(c) => tryRoute(c, () => deps.catalogue.getCollection(c.req.param("collection_id")))
|
|
3301
|
+
);
|
|
3302
|
+
app.get(
|
|
3303
|
+
"/catalogue/collections/:collection_id/products",
|
|
3304
|
+
(c) => tryRoute(c, () => deps.catalogue.getCollectionProducts(c.req.param("collection_id")))
|
|
3305
|
+
);
|
|
3306
|
+
app.get(
|
|
3307
|
+
"/catalogue/collections/:collection_id/attributes",
|
|
3308
|
+
(c) => tryRoute(c, () => deps.catalogue.getCollectionAttributes(c.req.param("collection_id")))
|
|
3309
|
+
);
|
|
3310
|
+
app.get(
|
|
3311
|
+
"/catalogue/collections/:collection_id/deals",
|
|
3312
|
+
(c) => tryRoute(c, () => deps.catalogue.getCollectionDeals(c.req.param("collection_id")))
|
|
3313
|
+
);
|
|
3314
|
+
app.get(
|
|
3315
|
+
"/catalogue/bundles",
|
|
3316
|
+
(c) => tryRoute(c, () => deps.catalogue.listBundles(deps.defaultBusinessId))
|
|
3317
|
+
);
|
|
3318
|
+
app.get(
|
|
3319
|
+
"/catalogue/bundles/:bundle_id",
|
|
3320
|
+
(c) => tryRoute(c, () => deps.catalogue.getBundle(c.req.param("bundle_id")))
|
|
3321
|
+
);
|
|
3322
|
+
app.get(
|
|
3323
|
+
"/catalogue/composites",
|
|
3324
|
+
(c) => tryRoute(c, () => deps.catalogue.listComposites(deps.defaultBusinessId))
|
|
3325
|
+
);
|
|
3326
|
+
app.get(
|
|
3327
|
+
"/catalogue/composites/by-product/:product_id",
|
|
3328
|
+
(c) => tryRoute(c, () => deps.catalogue.getCompositeByProduct(c.req.param("product_id")))
|
|
3329
|
+
);
|
|
3330
|
+
app.get(
|
|
3331
|
+
"/catalogue/composites/:composite_id",
|
|
3332
|
+
(c) => tryRoute(c, () => deps.catalogue.getComposite(c.req.param("composite_id")))
|
|
3333
|
+
);
|
|
3249
3334
|
app.post("/catalogue/composites/:composite_id/calculate-price", async (c) => {
|
|
3250
3335
|
const body = await c.req.json().catch(() => ({}));
|
|
3251
|
-
return tryRoute(
|
|
3336
|
+
return tryRoute(
|
|
3337
|
+
c,
|
|
3338
|
+
() => deps.catalogue.calculateCompositePrice(c.req.param("composite_id"), body)
|
|
3339
|
+
);
|
|
3252
3340
|
});
|
|
3253
|
-
app.get(
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
app.get(
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3341
|
+
app.get(
|
|
3342
|
+
"/catalogue/taxonomies",
|
|
3343
|
+
(c) => tryRoute(c, () => deps.catalogue.listTaxonomies(deps.defaultBusinessId))
|
|
3344
|
+
);
|
|
3345
|
+
app.get(
|
|
3346
|
+
"/catalogue/taxonomies/search",
|
|
3347
|
+
(c) => tryRoute(
|
|
3348
|
+
c,
|
|
3349
|
+
() => deps.catalogue.searchTaxonomies(deps.defaultBusinessId, c.req.query("q") ?? "")
|
|
3350
|
+
)
|
|
3351
|
+
);
|
|
3352
|
+
app.get(
|
|
3353
|
+
"/catalogue/taxonomies/:taxonomy_id",
|
|
3354
|
+
(c) => tryRoute(c, () => deps.catalogue.getTaxonomy(c.req.param("taxonomy_id")))
|
|
3355
|
+
);
|
|
3356
|
+
app.get(
|
|
3357
|
+
"/catalogue/taxonomies/:taxonomy_id/attributes",
|
|
3358
|
+
(c) => tryRoute(c, () => deps.catalogue.getTaxonomyAttributes(c.req.param("taxonomy_id")))
|
|
3359
|
+
);
|
|
3360
|
+
app.get(
|
|
3361
|
+
"/catalogue/taxonomies/:taxonomy_id/path",
|
|
3362
|
+
(c) => tryRoute(c, () => deps.catalogue.getTaxonomyPath(c.req.param("taxonomy_id")))
|
|
3363
|
+
);
|
|
3364
|
+
app.get(
|
|
3365
|
+
"/catalogue/attributes",
|
|
3366
|
+
(c) => tryRoute(c, () => deps.catalogue.listAttributes(deps.defaultBusinessId))
|
|
3367
|
+
);
|
|
3368
|
+
app.get(
|
|
3369
|
+
"/catalogue/properties/facets",
|
|
3370
|
+
(c) => tryRoute(c, () => deps.catalogue.listPropertyFacets(deps.defaultBusinessId))
|
|
3371
|
+
);
|
|
3372
|
+
app.get(
|
|
3373
|
+
"/catalogue/tags",
|
|
3374
|
+
(c) => tryRoute(c, () => deps.catalogue.listTags(deps.defaultBusinessId))
|
|
3375
|
+
);
|
|
3261
3376
|
app.get("/catalogue/menu", (c) => tryRoute(c, () => deps.lite.getMenu(deps.defaultBusinessId)));
|
|
3262
|
-
app.get(
|
|
3263
|
-
|
|
3264
|
-
|
|
3377
|
+
app.get(
|
|
3378
|
+
"/catalogue/menu/categories/:category_id",
|
|
3379
|
+
(c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id")))
|
|
3380
|
+
);
|
|
3381
|
+
app.get(
|
|
3382
|
+
"/catalogue/menu/items/:item_id",
|
|
3383
|
+
(c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("item_id")))
|
|
3384
|
+
);
|
|
3385
|
+
app.get(
|
|
3386
|
+
"/catalogue/knowledge-base/articles",
|
|
3387
|
+
(c) => tryRoute(c, () => ({ articles: deps.catalogue.listKnowledgeArticles(deps.defaultBusinessId) }))
|
|
3388
|
+
);
|
|
3265
3389
|
app.get(
|
|
3266
3390
|
"/catalogue/knowledge-base/search",
|
|
3267
|
-
(c) => tryRoute(c, () => ({
|
|
3391
|
+
(c) => tryRoute(c, () => ({
|
|
3392
|
+
results: deps.catalogue.searchKnowledgeBase(deps.defaultBusinessId, c.req.query("q") ?? ""),
|
|
3393
|
+
query: c.req.query("q") ?? ""
|
|
3394
|
+
}))
|
|
3395
|
+
);
|
|
3396
|
+
app.get(
|
|
3397
|
+
"/catalogue/products/:product_id/attributes",
|
|
3398
|
+
(c) => tryRoute(c, () => deps.catalogue.getProductAttributes(c.req.param("product_id")))
|
|
3268
3399
|
);
|
|
3269
|
-
app.get("/catalogue/products/:product_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getProductAttributes(c.req.param("product_id"))));
|
|
3270
3400
|
app.get(
|
|
3271
3401
|
"/catalogue/products/:product_id/available-now",
|
|
3272
3402
|
(c) => tryRoute(c, () => {
|
|
@@ -3285,22 +3415,75 @@ function buildV1(deps) {
|
|
|
3285
3415
|
"/catalogue/products/:product_id/schedules",
|
|
3286
3416
|
(c) => tryRoute(c, () => {
|
|
3287
3417
|
const p = deps.registry.products.get(c.req.param("product_id"));
|
|
3288
|
-
return {
|
|
3418
|
+
return {
|
|
3419
|
+
schedules: p?.metadata?.["time_profiles"] ?? []
|
|
3420
|
+
};
|
|
3289
3421
|
})
|
|
3290
3422
|
);
|
|
3291
|
-
app.get(
|
|
3292
|
-
|
|
3423
|
+
app.get(
|
|
3424
|
+
"/catalogue/deals",
|
|
3425
|
+
(c) => tryRoute(c, () => deps.catalogue.listDeals(deps.defaultBusinessId))
|
|
3426
|
+
);
|
|
3427
|
+
app.get(
|
|
3428
|
+
"/catalogue/deals/on-sale",
|
|
3429
|
+
(c) => tryRoute(c, () => deps.catalogue.listOnSale(deps.defaultBusinessId))
|
|
3430
|
+
);
|
|
3293
3431
|
app.post("/catalogue/deals/validate", async (c) => {
|
|
3294
3432
|
const body = await c.req.json().catch(() => ({}));
|
|
3295
|
-
return tryRoute(
|
|
3433
|
+
return tryRoute(
|
|
3434
|
+
c,
|
|
3435
|
+
() => deps.catalogue.validateDiscount(
|
|
3436
|
+
body.discount_code ?? body.code ?? "",
|
|
3437
|
+
deps.defaultBusinessId
|
|
3438
|
+
)
|
|
3439
|
+
);
|
|
3296
3440
|
});
|
|
3297
|
-
app.get(
|
|
3441
|
+
app.get(
|
|
3442
|
+
"/catalogue/products/:product_id/deals",
|
|
3443
|
+
(c) => tryRoute(c, () => deps.catalogue.getProductDeals(c.req.param("product_id")))
|
|
3444
|
+
);
|
|
3298
3445
|
app.post("/catalogue/quotes", async (c) => {
|
|
3299
3446
|
const body = await c.req.json().catch(() => ({}));
|
|
3300
3447
|
return tryRoute(c, () => deps.catalogue.createQuote(deps.defaultBusinessId, body));
|
|
3301
3448
|
});
|
|
3302
|
-
app.get(
|
|
3303
|
-
|
|
3449
|
+
app.get(
|
|
3450
|
+
"/catalogue/quotes/:quote_id",
|
|
3451
|
+
(c) => tryRoute(c, () => deps.catalogue.getQuote(c.req.param("quote_id")))
|
|
3452
|
+
);
|
|
3453
|
+
app.post(
|
|
3454
|
+
"/catalogue/quotes/:quote_id/refresh",
|
|
3455
|
+
(c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
|
|
3456
|
+
);
|
|
3457
|
+
app.get("/reviews/summary", (c) => {
|
|
3458
|
+
const productId = c.req.query("product_id");
|
|
3459
|
+
if (productId !== void 0 && (productId.length === 0 || productId.trim() !== productId)) {
|
|
3460
|
+
return fail(c, validation("product_id must be a non-empty canonical identifier"));
|
|
3461
|
+
}
|
|
3462
|
+
const response = {
|
|
3463
|
+
data: {
|
|
3464
|
+
ratings: {
|
|
3465
|
+
product_id: productId ?? null,
|
|
3466
|
+
review_count: 0,
|
|
3467
|
+
rating_sum: 0,
|
|
3468
|
+
average_rating: null,
|
|
3469
|
+
distribution: { one: 0, two: 0, three: 0, four: 0, five: 0 }
|
|
3470
|
+
},
|
|
3471
|
+
trust_chips: {
|
|
3472
|
+
on_time_delivery_percent: null,
|
|
3473
|
+
delivery_sample_size: 0,
|
|
3474
|
+
average_first_response_seconds: null,
|
|
3475
|
+
support_sample_size: 0
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
};
|
|
3479
|
+
return c.json(response);
|
|
3480
|
+
});
|
|
3481
|
+
app.get("/reviews", (c) => {
|
|
3482
|
+
const response = {
|
|
3483
|
+
data: { items: [], next_cursor: null }
|
|
3484
|
+
};
|
|
3485
|
+
return c.json(response);
|
|
3486
|
+
});
|
|
3304
3487
|
app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
|
|
3305
3488
|
app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
|
|
3306
3489
|
app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
|
|
@@ -3311,9 +3494,15 @@ function buildV1(deps) {
|
|
|
3311
3494
|
app.patch("/cart/items/:cart_item_id", async (c) => {
|
|
3312
3495
|
const body = await c.req.json().catch(() => ({}));
|
|
3313
3496
|
if (typeof body.quantity !== "number") return fail(c, validation("quantity required"));
|
|
3314
|
-
return tryRoute(
|
|
3497
|
+
return tryRoute(
|
|
3498
|
+
c,
|
|
3499
|
+
() => deps.cart.updateQuantity(c.var.session, c.req.param("cart_item_id"), body.quantity)
|
|
3500
|
+
);
|
|
3315
3501
|
});
|
|
3316
|
-
app.delete(
|
|
3502
|
+
app.delete(
|
|
3503
|
+
"/cart/items/:cart_item_id",
|
|
3504
|
+
(c) => tryRoute(c, () => deps.cart.removeItem(c.var.session, c.req.param("cart_item_id")))
|
|
3505
|
+
);
|
|
3317
3506
|
app.get("/cart/count", (c) => tryRoute(c, () => deps.cart.getCount(c.var.session)));
|
|
3318
3507
|
app.get("/cart/total", (c) => tryRoute(c, () => deps.cart.getTotal(c.var.session)));
|
|
3319
3508
|
app.post("/cart/destination-quote", async (c) => {
|
|
@@ -3324,10 +3513,25 @@ function buildV1(deps) {
|
|
|
3324
3513
|
const body = await c.req.json().catch(() => ({}));
|
|
3325
3514
|
return tryRoute(c, () => deps.cart.applyCoupon(c.var.session, body.coupon_code ?? ""));
|
|
3326
3515
|
});
|
|
3327
|
-
app.delete(
|
|
3328
|
-
|
|
3516
|
+
app.delete(
|
|
3517
|
+
"/cart/coupons/current",
|
|
3518
|
+
(c) => tryRoute(c, () => deps.cart.removeCoupon(c.var.session))
|
|
3519
|
+
);
|
|
3520
|
+
app.get(
|
|
3521
|
+
"/orders",
|
|
3522
|
+
(c) => tryRoute(
|
|
3523
|
+
c,
|
|
3524
|
+
() => deps.orders.list(c.var.session, {
|
|
3525
|
+
limit: getQueryNum(c, "limit"),
|
|
3526
|
+
status: c.req.query("status")
|
|
3527
|
+
})
|
|
3528
|
+
)
|
|
3529
|
+
);
|
|
3329
3530
|
app.get("/orders/:order_id", (c) => tryRoute(c, () => deps.orders.get(c.req.param("order_id"))));
|
|
3330
|
-
app.get(
|
|
3531
|
+
app.get(
|
|
3532
|
+
"/orders/:order_id/payment-status",
|
|
3533
|
+
(c) => tryRoute(c, () => deps.orders.getPaymentStatus(c.req.param("order_id")))
|
|
3534
|
+
);
|
|
3331
3535
|
app.post("/orders/:order_id/cancel", async (c) => {
|
|
3332
3536
|
const body = await c.req.json().catch(() => ({}));
|
|
3333
3537
|
return tryRoute(c, () => deps.orders.cancel(c.req.param("order_id"), body.reason));
|
|
@@ -3336,13 +3540,46 @@ function buildV1(deps) {
|
|
|
3336
3540
|
const body = await c.req.json().catch(() => ({}));
|
|
3337
3541
|
return tryRoute(c, () => deps.orders.updateCustomer(c.req.param("order_id"), body));
|
|
3338
3542
|
});
|
|
3339
|
-
app.post(
|
|
3543
|
+
app.post(
|
|
3544
|
+
"/orders/:order_id/verify-payment",
|
|
3545
|
+
(c) => tryRoute(c, () => deps.orders.verifyPayment(c.req.param("order_id")))
|
|
3546
|
+
);
|
|
3340
3547
|
app.get("/subscriptions", (c) => tryRoute(c, () => deps.subscriptions.list(c.var.session)));
|
|
3341
|
-
app.get(
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
app.post(
|
|
3548
|
+
app.get(
|
|
3549
|
+
"/subscriptions/:subscription_id",
|
|
3550
|
+
(c) => tryRoute(c, () => deps.subscriptions.get(c.req.param("subscription_id")))
|
|
3551
|
+
);
|
|
3552
|
+
app.post(
|
|
3553
|
+
"/subscriptions/:subscription_id/cancel",
|
|
3554
|
+
(c) => tryRoute(c, () => deps.subscriptions.cancel(c.req.param("subscription_id")))
|
|
3555
|
+
);
|
|
3556
|
+
app.post(
|
|
3557
|
+
"/subscriptions/:subscription_id/pause",
|
|
3558
|
+
(c) => tryRoute(c, () => deps.subscriptions.pause(c.req.param("subscription_id")))
|
|
3559
|
+
);
|
|
3560
|
+
app.post(
|
|
3561
|
+
"/subscriptions/:subscription_id/resume",
|
|
3562
|
+
(c) => tryRoute(c, () => deps.subscriptions.resume(c.req.param("subscription_id")))
|
|
3563
|
+
);
|
|
3564
|
+
app.post(
|
|
3565
|
+
"/subscriptions/:subscription_id/skip",
|
|
3566
|
+
(c) => tryRoute(c, () => deps.subscriptions.skipNext(c.req.param("subscription_id")))
|
|
3567
|
+
);
|
|
3568
|
+
app.get("/payments/collection-options", (c) => {
|
|
3569
|
+
const currency = c.req.query("currency")?.trim().toUpperCase();
|
|
3570
|
+
if (!currency || !/^[A-Z]{3}$/.test(currency)) {
|
|
3571
|
+
return fail(c, validation("currency must be a canonical three-letter code"));
|
|
3572
|
+
}
|
|
3573
|
+
return tryRoute(c, () => ({
|
|
3574
|
+
presentment_currency: currency,
|
|
3575
|
+
options: currency === "GHS" ? [
|
|
3576
|
+
{ method: PAYMENT_METHOD.CARD, network: null },
|
|
3577
|
+
{ method: PAYMENT_METHOD.MOBILE_MONEY, network: "mtn" },
|
|
3578
|
+
{ method: PAYMENT_METHOD.MOBILE_MONEY, network: "telecel" },
|
|
3579
|
+
{ method: PAYMENT_METHOD.MOBILE_MONEY, network: "airteltigo" }
|
|
3580
|
+
] : currency === "USD" ? [{ method: PAYMENT_METHOD.CARD, network: null }] : []
|
|
3581
|
+
}));
|
|
3582
|
+
});
|
|
3346
3583
|
app.post("/checkout", async (c) => {
|
|
3347
3584
|
const body = await c.req.json().catch(() => ({}));
|
|
3348
3585
|
return tryRoute(c, () => deps.checkout.process(c.var.session, body));
|
|
@@ -3396,15 +3633,33 @@ function buildV1(deps) {
|
|
|
3396
3633
|
return { success: true, message: "Profile updated successfully" };
|
|
3397
3634
|
});
|
|
3398
3635
|
});
|
|
3399
|
-
app.get(
|
|
3400
|
-
|
|
3636
|
+
app.get(
|
|
3637
|
+
"/inventory/products/:product_id/stock",
|
|
3638
|
+
(c) => tryRoute(c, () => deps.inventory.productStock(c.req.param("product_id")))
|
|
3639
|
+
);
|
|
3640
|
+
app.get(
|
|
3641
|
+
"/inventory/variants/:variant_id/stock",
|
|
3642
|
+
(c) => tryRoute(c, () => deps.inventory.variantStock(c.req.param("variant_id")))
|
|
3643
|
+
);
|
|
3401
3644
|
app.get(
|
|
3402
3645
|
"/inventory/products/:product_id/availability",
|
|
3403
|
-
(c) => tryRoute(
|
|
3646
|
+
(c) => tryRoute(
|
|
3647
|
+
c,
|
|
3648
|
+
() => deps.inventory.productAvailability(
|
|
3649
|
+
c.req.param("product_id"),
|
|
3650
|
+
getQueryNum(c, "quantity") ?? 1
|
|
3651
|
+
)
|
|
3652
|
+
)
|
|
3404
3653
|
);
|
|
3405
3654
|
app.get(
|
|
3406
3655
|
"/inventory/variants/:variant_id/availability",
|
|
3407
|
-
(c) => tryRoute(
|
|
3656
|
+
(c) => tryRoute(
|
|
3657
|
+
c,
|
|
3658
|
+
() => deps.inventory.variantAvailability(
|
|
3659
|
+
c.req.param("variant_id"),
|
|
3660
|
+
getQueryNum(c, "quantity") ?? 1
|
|
3661
|
+
)
|
|
3662
|
+
)
|
|
3408
3663
|
);
|
|
3409
3664
|
app.get(
|
|
3410
3665
|
"/delivery/fee",
|
|
@@ -3431,35 +3686,75 @@ function buildV1(deps) {
|
|
|
3431
3686
|
);
|
|
3432
3687
|
app.post("/places/autocomplete", async (c) => {
|
|
3433
3688
|
const body = await c.req.json().catch(() => ({}));
|
|
3434
|
-
return tryRoute(
|
|
3689
|
+
return tryRoute(
|
|
3690
|
+
c,
|
|
3691
|
+
() => deps.places.autocomplete({ query: body.input ?? body.query ?? "", country: body.country })
|
|
3692
|
+
);
|
|
3435
3693
|
});
|
|
3436
3694
|
app.post("/places/details", async (c) => {
|
|
3437
3695
|
const body = await c.req.json().catch(() => ({}));
|
|
3438
3696
|
return tryRoute(c, () => deps.places.details({ place_id: body.place_id ?? "" }));
|
|
3439
3697
|
});
|
|
3440
|
-
app.get(
|
|
3441
|
-
|
|
3442
|
-
|
|
3698
|
+
app.get(
|
|
3699
|
+
"/scheduling/services",
|
|
3700
|
+
(c) => tryRoute(c, () => deps.scheduling.listServices(deps.defaultBusinessId))
|
|
3701
|
+
);
|
|
3702
|
+
app.get(
|
|
3703
|
+
"/scheduling/services/:service_id",
|
|
3704
|
+
(c) => tryRoute(c, () => deps.scheduling.getService(c.req.param("service_id")))
|
|
3705
|
+
);
|
|
3706
|
+
app.get(
|
|
3707
|
+
"/scheduling/slots",
|
|
3708
|
+
(c) => tryRoute(
|
|
3709
|
+
c,
|
|
3710
|
+
() => deps.scheduling.getSlots(c.req.query("service_id") ?? "", { date: c.req.query("date") })
|
|
3711
|
+
)
|
|
3712
|
+
);
|
|
3443
3713
|
app.get(
|
|
3444
3714
|
"/scheduling/slots/check",
|
|
3445
|
-
(c) => tryRoute(
|
|
3715
|
+
(c) => tryRoute(
|
|
3716
|
+
c,
|
|
3717
|
+
() => deps.scheduling.checkSlot(
|
|
3718
|
+
c.req.query("service_id") ?? "",
|
|
3719
|
+
c.req.query("start") ?? "",
|
|
3720
|
+
c.req.query("end") ?? ""
|
|
3721
|
+
)
|
|
3722
|
+
)
|
|
3723
|
+
);
|
|
3724
|
+
app.get(
|
|
3725
|
+
"/scheduling/availability",
|
|
3726
|
+
(c) => tryRoute(c, () => deps.scheduling.getServiceAvailability(c.req.query("service_id") ?? ""))
|
|
3727
|
+
);
|
|
3728
|
+
app.get(
|
|
3729
|
+
"/scheduling/bookings",
|
|
3730
|
+
(c) => tryRoute(c, () => deps.scheduling.getCustomerBookings(c.var.session))
|
|
3446
3731
|
);
|
|
3447
|
-
app.get("/scheduling/availability", (c) => tryRoute(c, () => deps.scheduling.getServiceAvailability(c.req.query("service_id") ?? "")));
|
|
3448
|
-
app.get("/scheduling/bookings", (c) => tryRoute(c, () => deps.scheduling.getCustomerBookings(c.var.session)));
|
|
3449
3732
|
app.post("/scheduling/bookings/reschedule", async (c) => {
|
|
3450
3733
|
const body = await c.req.json().catch(() => ({}));
|
|
3451
3734
|
return tryRoute(c, () => deps.scheduling.rescheduleBooking(body));
|
|
3452
3735
|
});
|
|
3453
|
-
app.get(
|
|
3736
|
+
app.get(
|
|
3737
|
+
"/scheduling/bookings/:booking_id",
|
|
3738
|
+
(c) => tryRoute(c, () => deps.scheduling.getBooking(c.req.param("booking_id")))
|
|
3739
|
+
);
|
|
3454
3740
|
app.post("/scheduling/bookings/:booking_id/cancel", async (c) => {
|
|
3455
3741
|
const body = await c.req.json().catch(() => ({}));
|
|
3456
3742
|
return tryRoute(c, () => deps.scheduling.cancelBooking(c.req.param("booking_id"), body.reason));
|
|
3457
3743
|
});
|
|
3458
3744
|
app.get("/lite/bootstrap", (c) => tryRoute(c, () => deps.lite.bootstrap(deps.defaultBusinessId)));
|
|
3459
|
-
app.get(
|
|
3745
|
+
app.get(
|
|
3746
|
+
"/lite/resources/:resource_id",
|
|
3747
|
+
(c) => tryRoute(c, () => deps.lite.getResource(c.req.param("resource_id")))
|
|
3748
|
+
);
|
|
3460
3749
|
app.get("/lite/menu", (c) => tryRoute(c, () => deps.lite.getMenu(deps.defaultBusinessId)));
|
|
3461
|
-
app.get(
|
|
3462
|
-
|
|
3750
|
+
app.get(
|
|
3751
|
+
"/lite/menu/categories/:category_id",
|
|
3752
|
+
(c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id")))
|
|
3753
|
+
);
|
|
3754
|
+
app.get(
|
|
3755
|
+
"/fx/rate",
|
|
3756
|
+
(c) => tryRoute(c, () => deps.fx.getRate(c.req.query("from") ?? "USD", c.req.query("to") ?? "GHS"))
|
|
3757
|
+
);
|
|
3463
3758
|
app.post("/fx/quotes", async (c) => {
|
|
3464
3759
|
const body = await c.req.json().catch(() => ({}));
|
|
3465
3760
|
return tryRoute(c, () => deps.fx.lockQuote(body));
|
|
@@ -3472,31 +3767,47 @@ function buildV1(deps) {
|
|
|
3472
3767
|
const body = await c.req.json().catch(() => ({}));
|
|
3473
3768
|
return tryRoute(c, () => deps.uploads.confirm(body));
|
|
3474
3769
|
});
|
|
3475
|
-
app.get(
|
|
3476
|
-
"/store-credit/balance",
|
|
3477
|
-
(c) => c.json({ data: { balance: "0.00", currency: "USD" } })
|
|
3478
|
-
);
|
|
3770
|
+
app.get("/store-credit/balance", (c) => c.json({ data: { balance: "0.00", currency: "USD" } }));
|
|
3479
3771
|
app.post("/activity/session", async (c) => {
|
|
3480
3772
|
await c.req.json().catch(() => ({}));
|
|
3481
3773
|
return c.json({ data: { recorded: true } });
|
|
3482
3774
|
});
|
|
3483
3775
|
app.post("/activity/events", async (c) => {
|
|
3484
3776
|
const body = await c.req.json().catch(() => ({}));
|
|
3485
|
-
return tryRoute(
|
|
3777
|
+
return tryRoute(
|
|
3778
|
+
c,
|
|
3779
|
+
() => deps.activity.recordEvents(
|
|
3780
|
+
deps.defaultBusinessId,
|
|
3781
|
+
body.analytics_session_id ?? c.var.session.id,
|
|
3782
|
+
body.events ?? []
|
|
3783
|
+
)
|
|
3784
|
+
);
|
|
3486
3785
|
});
|
|
3487
|
-
app.get(
|
|
3488
|
-
|
|
3786
|
+
app.get(
|
|
3787
|
+
"/activity/state",
|
|
3788
|
+
(c) => tryRoute(c, () => deps.activity.getState(deps.defaultBusinessId, c.var.session.id))
|
|
3789
|
+
);
|
|
3790
|
+
app.get(
|
|
3791
|
+
"/activity/recommendations",
|
|
3792
|
+
(c) => tryRoute(c, () => deps.activity.getRecommendations(deps.defaultBusinessId))
|
|
3793
|
+
);
|
|
3489
3794
|
app.post("/activity/messages/dismiss", async (c) => {
|
|
3490
3795
|
const body = await c.req.json().catch(() => ({}));
|
|
3491
3796
|
return tryRoute(c, () => deps.activity.dismissMessage(body.code ?? body.message_id ?? ""));
|
|
3492
3797
|
});
|
|
3493
3798
|
app.post(
|
|
3494
3799
|
"/support/conversation",
|
|
3495
|
-
(c) => tryRoute(
|
|
3800
|
+
(c) => tryRoute(
|
|
3801
|
+
c,
|
|
3802
|
+
() => deps.support.openConversation(deps.defaultBusinessId, c.var.session.customer_id)
|
|
3803
|
+
)
|
|
3496
3804
|
);
|
|
3497
3805
|
app.get(
|
|
3498
3806
|
"/support/conversation",
|
|
3499
|
-
(c) => tryRoute(
|
|
3807
|
+
(c) => tryRoute(
|
|
3808
|
+
c,
|
|
3809
|
+
() => deps.support.peekConversation(deps.defaultBusinessId, c.var.session.customer_id)
|
|
3810
|
+
)
|
|
3500
3811
|
);
|
|
3501
3812
|
app.post("/support/conversation/messages", async (c) => {
|
|
3502
3813
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -3512,7 +3823,12 @@ function buildV1(deps) {
|
|
|
3512
3823
|
});
|
|
3513
3824
|
app.get(
|
|
3514
3825
|
"/support/conversation/messages",
|
|
3515
|
-
(c) => tryRoute(
|
|
3826
|
+
(c) => tryRoute(
|
|
3827
|
+
c,
|
|
3828
|
+
() => deps.support.listMessages(c.req.query("conversation_id") ?? "", {
|
|
3829
|
+
limit: getQueryNum(c, "limit")
|
|
3830
|
+
})
|
|
3831
|
+
)
|
|
3516
3832
|
);
|
|
3517
3833
|
app.post("/support/conversation/messages/:messageId/reactions", async (c) => {
|
|
3518
3834
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -3533,7 +3849,10 @@ function buildV1(deps) {
|
|
|
3533
3849
|
});
|
|
3534
3850
|
app.get(
|
|
3535
3851
|
"/support/conversation/ws",
|
|
3536
|
-
(c) => c.json(
|
|
3852
|
+
(c) => c.json(
|
|
3853
|
+
{ note: "WebSocket connection \u2014 connect via ws:// at the same path", supported: false },
|
|
3854
|
+
426
|
|
3855
|
+
)
|
|
3537
3856
|
);
|
|
3538
3857
|
return app;
|
|
3539
3858
|
}
|
|
@@ -4060,9 +4379,10 @@ function buildLink(deps) {
|
|
|
4060
4379
|
app.post("/auth/request-otp", async (c) => {
|
|
4061
4380
|
const body = await c.req.json().catch(() => ({}));
|
|
4062
4381
|
return tryRoute(c, () => {
|
|
4063
|
-
deps.auth.requestOtp(body.contact ?? "");
|
|
4382
|
+
const challenge = deps.auth.requestOtp(body.contact ?? "");
|
|
4064
4383
|
return {
|
|
4065
4384
|
success: true,
|
|
4385
|
+
challenge_id: challenge.otp_id,
|
|
4066
4386
|
message: `OTP sent to ${body.contact ?? "contact"}`,
|
|
4067
4387
|
expires_in: 300,
|
|
4068
4388
|
is_new_account: false
|
|
@@ -4072,7 +4392,11 @@ function buildLink(deps) {
|
|
|
4072
4392
|
app.post("/auth/verify-otp", async (c) => {
|
|
4073
4393
|
const body = await c.req.json().catch(() => ({}));
|
|
4074
4394
|
return tryRoute(c, () => {
|
|
4075
|
-
const session = deps.auth.verifyOtp(
|
|
4395
|
+
const session = deps.auth.verifyOtp(
|
|
4396
|
+
body.contact ?? "",
|
|
4397
|
+
body.otp_code ?? "",
|
|
4398
|
+
body.challenge_id
|
|
4399
|
+
);
|
|
4076
4400
|
c.header("x-session-token", session.token);
|
|
4077
4401
|
const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
|
|
4078
4402
|
email: body.contact?.includes("@") ? body.contact : void 0,
|
|
@@ -4166,10 +4490,7 @@ function buildLink(deps) {
|
|
|
4166
4490
|
};
|
|
4167
4491
|
});
|
|
4168
4492
|
});
|
|
4169
|
-
app.get(
|
|
4170
|
-
"/preferences",
|
|
4171
|
-
(c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
|
|
4172
|
-
);
|
|
4493
|
+
app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
|
|
4173
4494
|
app.post("/preferences", async (c) => {
|
|
4174
4495
|
const body = await c.req.json().catch(() => ({}));
|
|
4175
4496
|
return tryRoute(c, () => {
|
|
@@ -4646,9 +4967,16 @@ function createAuthService(opts) {
|
|
|
4646
4967
|
code_hint: options.mode === "permissive" ? code : void 0
|
|
4647
4968
|
};
|
|
4648
4969
|
},
|
|
4649
|
-
verifyOtp(contact, code) {
|
|
4650
|
-
|
|
4651
|
-
|
|
4970
|
+
verifyOtp(contact, code, challengeId) {
|
|
4971
|
+
let otp = challengeId ? registry.otps.get(challengeId) : void 0;
|
|
4972
|
+
if (!challengeId) {
|
|
4973
|
+
const matching = registry.otps.list((o) => o.contact === contact);
|
|
4974
|
+
otp = matching[matching.length - 1];
|
|
4975
|
+
}
|
|
4976
|
+
if (challengeId) {
|
|
4977
|
+
if (!otp) throw new Error("No OTP challenge found");
|
|
4978
|
+
if (otp.contact !== contact) throw new Error("OTP challenge does not match contact");
|
|
4979
|
+
}
|
|
4652
4980
|
if (options.mode === "strict") {
|
|
4653
4981
|
if (!otp) throw new Error("No OTP requested");
|
|
4654
4982
|
if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
|
|
@@ -5976,7 +6304,7 @@ function createCartService(opts) {
|
|
|
5976
6304
|
|
|
5977
6305
|
// src/mock/domain/checkout.ts
|
|
5978
6306
|
function createCheckoutService(opts) {
|
|
5979
|
-
const { registry, clock, ids, bus} = opts;
|
|
6307
|
+
const { registry, clock, ids, bus } = opts;
|
|
5980
6308
|
return {
|
|
5981
6309
|
process(session, body) {
|
|
5982
6310
|
if (!body.cart_id) throw validation("cart_id required");
|
|
@@ -5985,9 +6313,11 @@ function createCheckoutService(opts) {
|
|
|
5985
6313
|
if (c.items.length === 0) throw validation("Cart is empty", { code: "CART_EMPTY" });
|
|
5986
6314
|
const orderId = ids.order();
|
|
5987
6315
|
const orderNumber = ids.orderNumber();
|
|
6316
|
+
const paymentId = ids.payment();
|
|
5988
6317
|
const reference = ids.payment();
|
|
5989
6318
|
const requiresAuth = body.payment_method === "mobile_money";
|
|
5990
6319
|
const isCard = body.payment_method === "card" || body.payment_method === "stripe";
|
|
6320
|
+
const cardProvider = body.payment_method === "stripe" || body.pay_currency?.toUpperCase() === "USD" ? "stripe" : "paystack";
|
|
5991
6321
|
const order = {
|
|
5992
6322
|
id: orderId,
|
|
5993
6323
|
business_id: c.business_id,
|
|
@@ -6011,6 +6341,7 @@ function createCheckoutService(opts) {
|
|
|
6011
6341
|
items: c.items,
|
|
6012
6342
|
applied_discount_ids: c.applied_discount_ids,
|
|
6013
6343
|
applied_discount_codes: c.applied_discount_codes,
|
|
6344
|
+
payment_id: paymentId,
|
|
6014
6345
|
payment_reference: reference,
|
|
6015
6346
|
metadata: body.metadata,
|
|
6016
6347
|
created_at: clock.iso(),
|
|
@@ -6027,31 +6358,57 @@ function createCheckoutService(opts) {
|
|
|
6027
6358
|
const result = {
|
|
6028
6359
|
order_id: orderId,
|
|
6029
6360
|
order_number: orderNumber,
|
|
6030
|
-
|
|
6361
|
+
payment_id: paymentId,
|
|
6362
|
+
payment_status: requiresAuth || isCard ? "pending" : "succeeded",
|
|
6031
6363
|
payment_reference: reference,
|
|
6032
6364
|
requires_authorization: requiresAuth,
|
|
6033
6365
|
authorization_type: requiresAuth ? "otp" : void 0,
|
|
6034
|
-
next_action: requiresAuth ? {
|
|
6035
|
-
|
|
6366
|
+
next_action: requiresAuth ? {
|
|
6367
|
+
type: "authorization",
|
|
6368
|
+
authorization_type: "otp",
|
|
6369
|
+
display_text: "Approve on your mobile money app"
|
|
6370
|
+
} : { type: "none" },
|
|
6371
|
+
provider: isCard ? cardProvider : body.payment_method,
|
|
6036
6372
|
bill_token: billToken
|
|
6037
6373
|
};
|
|
6038
6374
|
if (isCard) {
|
|
6039
|
-
result.next_action = { type: "redirect", authorization_url: `https://mock.cimplify.io/pay/${reference}` };
|
|
6040
|
-
result.authorization_url = `https://mock.cimplify.io/pay/${reference}`;
|
|
6041
|
-
result.client_secret = `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}`;
|
|
6042
6375
|
const proc = globalThis.process;
|
|
6043
|
-
result.
|
|
6376
|
+
result.client_secret = cardProvider === "stripe" ? `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}` : `access_${reference}`;
|
|
6377
|
+
result.public_key = cardProvider === "stripe" ? proc?.env?.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ?? "pk_test_mock_stripe" : proc?.env?.NEXT_PUBLIC_PAYSTACK_PUBLIC_KEY ?? "pk_test_mock_paystack";
|
|
6378
|
+
result.next_action = {
|
|
6379
|
+
type: "card_popup",
|
|
6380
|
+
provider: cardProvider,
|
|
6381
|
+
client_secret: result.client_secret,
|
|
6382
|
+
public_key: result.public_key
|
|
6383
|
+
};
|
|
6044
6384
|
}
|
|
6045
6385
|
return result;
|
|
6046
6386
|
},
|
|
6047
6387
|
authorize(body) {
|
|
6048
|
-
|
|
6049
|
-
if (!
|
|
6050
|
-
const
|
|
6388
|
+
if (!body.payment_id?.trim()) throw validation("payment_id required");
|
|
6389
|
+
if (!body.authorization) throw validation("authorization required");
|
|
6390
|
+
const order = registry.orders.list(
|
|
6391
|
+
(candidate) => candidate.payment_id === body.payment_id
|
|
6392
|
+
)[0];
|
|
6393
|
+
if (!order) throw notFound(`Payment ${body.payment_id} not found`);
|
|
6394
|
+
const updated = {
|
|
6395
|
+
...order,
|
|
6396
|
+
payment_state: "paid",
|
|
6397
|
+
status: "confirmed",
|
|
6398
|
+
updated_at: clock.iso()
|
|
6399
|
+
};
|
|
6051
6400
|
registry.orders.put(order.id, updated);
|
|
6052
6401
|
bus.emit("order.payment.captured", { order_id: order.id }, order.business_id);
|
|
6053
6402
|
bus.emit("order.confirmed", { order_id: order.id }, order.business_id);
|
|
6054
|
-
return {
|
|
6403
|
+
return {
|
|
6404
|
+
order_id: order.id,
|
|
6405
|
+
order_number: order.user_friendly_id,
|
|
6406
|
+
payment_id: body.payment_id,
|
|
6407
|
+
payment_reference: order.payment_reference,
|
|
6408
|
+
payment_status: "succeeded",
|
|
6409
|
+
requires_authorization: false,
|
|
6410
|
+
next_action: { type: "none" }
|
|
6411
|
+
};
|
|
6055
6412
|
}
|
|
6056
6413
|
};
|
|
6057
6414
|
}
|
|
@@ -6434,6 +6791,7 @@ function createDeliveryService() {
|
|
|
6434
6791
|
rate_id: "dlvrt_mock_standard",
|
|
6435
6792
|
name: "Standard",
|
|
6436
6793
|
fee: standardFree ? money(0) : money(15),
|
|
6794
|
+
fee_status: "priced",
|
|
6437
6795
|
currency: "GHS",
|
|
6438
6796
|
free_delivery_applied: standardFree,
|
|
6439
6797
|
free_over_amount: money(200),
|
|
@@ -6447,6 +6805,7 @@ function createDeliveryService() {
|
|
|
6447
6805
|
name: "Express",
|
|
6448
6806
|
description: "Delivered within the hour",
|
|
6449
6807
|
fee: money(25),
|
|
6808
|
+
fee_status: "priced",
|
|
6450
6809
|
currency: "GHS",
|
|
6451
6810
|
free_delivery_applied: false,
|
|
6452
6811
|
eta_min_minutes: 30,
|