@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/msw.mjs
CHANGED
|
@@ -2092,10 +2092,14 @@ var ERROR_SUGGESTIONS = {
|
|
|
2092
2092
|
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.",
|
|
2093
2093
|
PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
|
|
2094
2094
|
PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
|
|
2095
|
+
PAYMENT_CAPABILITY_MISMATCH: "Refresh collection capabilities for the exact tenant and presentment currency before retrying.",
|
|
2096
|
+
UNSUPPORTED_CURRENCY: "Choose a supported presentment currency before loading payment methods or submitting checkout.",
|
|
2095
2097
|
INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
|
|
2096
2098
|
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
2097
2099
|
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
2098
2100
|
OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
|
|
2101
|
+
OTP_CHALLENGE_EXHAUSTED: "This verification challenge has no attempts left. Continue checkout without saved details or request a fresh challenge.",
|
|
2102
|
+
OTP_CHALLENGE_CONSUMED: "This verification challenge has already been used. Continue with the established session or request a fresh challenge.",
|
|
2099
2103
|
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
2100
2104
|
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
2101
2105
|
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
@@ -2240,6 +2244,12 @@ function getQueryNum(c, key) {
|
|
|
2240
2244
|
return Number.isFinite(n) ? n : void 0;
|
|
2241
2245
|
}
|
|
2242
2246
|
|
|
2247
|
+
// src/constants.ts
|
|
2248
|
+
var PAYMENT_METHOD = {
|
|
2249
|
+
MOBILE_MONEY: "mobile_money",
|
|
2250
|
+
CARD: "card"
|
|
2251
|
+
};
|
|
2252
|
+
|
|
2243
2253
|
// src/mock/routes/v1.ts
|
|
2244
2254
|
function buildV1(deps) {
|
|
2245
2255
|
const app = new Hono2();
|
|
@@ -2256,10 +2266,22 @@ function buildV1(deps) {
|
|
|
2256
2266
|
}));
|
|
2257
2267
|
});
|
|
2258
2268
|
app.get("/business", (c) => tryRoute(c, () => deps.business.primary()));
|
|
2259
|
-
app.get(
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2269
|
+
app.get(
|
|
2270
|
+
"/business/by-handle/:handle",
|
|
2271
|
+
(c) => tryRoute(c, () => deps.business.byHandle(c.req.param("handle")))
|
|
2272
|
+
);
|
|
2273
|
+
app.get(
|
|
2274
|
+
"/business/by-domain",
|
|
2275
|
+
(c) => tryRoute(c, () => deps.business.byDomain(c.req.query("domain") ?? ""))
|
|
2276
|
+
);
|
|
2277
|
+
app.get(
|
|
2278
|
+
"/business/settings",
|
|
2279
|
+
(c) => tryRoute(c, () => deps.business.settings(deps.defaultBusinessId))
|
|
2280
|
+
);
|
|
2281
|
+
app.get(
|
|
2282
|
+
"/business/locations",
|
|
2283
|
+
(c) => tryRoute(c, () => deps.business.locations(deps.defaultBusinessId))
|
|
2284
|
+
);
|
|
2263
2285
|
app.get("/business/hours", (c) => tryRoute(c, () => deps.business.hours(deps.defaultBusinessId)));
|
|
2264
2286
|
app.get("/catalogue", (c) => tryRoute(c, () => deps.catalogue.snapshot(deps.defaultBusinessId)));
|
|
2265
2287
|
app.get(
|
|
@@ -2274,57 +2296,165 @@ function buildV1(deps) {
|
|
|
2274
2296
|
})
|
|
2275
2297
|
)
|
|
2276
2298
|
);
|
|
2277
|
-
app.get(
|
|
2278
|
-
|
|
2279
|
-
|
|
2299
|
+
app.get(
|
|
2300
|
+
"/catalogue/products/:product_id",
|
|
2301
|
+
(c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("product_id")))
|
|
2302
|
+
);
|
|
2303
|
+
app.get(
|
|
2304
|
+
"/catalogue/products/:product_id/variants",
|
|
2305
|
+
(c) => tryRoute(c, () => deps.catalogue.getProductVariants(c.req.param("product_id")))
|
|
2306
|
+
);
|
|
2307
|
+
app.get(
|
|
2308
|
+
"/catalogue/products/:product_id/variant-axes",
|
|
2309
|
+
(c) => tryRoute(c, () => deps.catalogue.getProductVariantAxes(c.req.param("product_id")))
|
|
2310
|
+
);
|
|
2280
2311
|
app.get(
|
|
2281
2312
|
"/catalogue/products/:product_id/variants/:variant_id",
|
|
2282
|
-
(c) => tryRoute(
|
|
2313
|
+
(c) => tryRoute(
|
|
2314
|
+
c,
|
|
2315
|
+
() => deps.catalogue.getProductVariantById(c.req.param("product_id"), c.req.param("variant_id"))
|
|
2316
|
+
)
|
|
2283
2317
|
);
|
|
2284
2318
|
app.post("/catalogue/products/:product_id/variants/find", async (c) => {
|
|
2285
2319
|
const body = await c.req.json().catch(() => ({}));
|
|
2286
2320
|
return tryRoute(
|
|
2287
2321
|
c,
|
|
2288
|
-
() => deps.catalogue.findProductVariant(
|
|
2322
|
+
() => deps.catalogue.findProductVariant(
|
|
2323
|
+
c.req.param("product_id"),
|
|
2324
|
+
body.axis_selections ?? body.properties ?? {}
|
|
2325
|
+
)
|
|
2289
2326
|
);
|
|
2290
2327
|
});
|
|
2291
|
-
app.get(
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
app.get(
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
app.get(
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
app.get(
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2328
|
+
app.get(
|
|
2329
|
+
"/catalogue/products/:product_id/add-ons",
|
|
2330
|
+
(c) => tryRoute(c, () => deps.catalogue.getProductAddOns(c.req.param("product_id")))
|
|
2331
|
+
);
|
|
2332
|
+
app.get(
|
|
2333
|
+
"/catalogue/categories",
|
|
2334
|
+
(c) => tryRoute(c, () => deps.catalogue.listCategories(deps.defaultBusinessId))
|
|
2335
|
+
);
|
|
2336
|
+
app.get(
|
|
2337
|
+
"/catalogue/categories/:category_id",
|
|
2338
|
+
(c) => tryRoute(c, () => deps.catalogue.getCategory(c.req.param("category_id")))
|
|
2339
|
+
);
|
|
2340
|
+
app.get(
|
|
2341
|
+
"/catalogue/categories/:category_id/products",
|
|
2342
|
+
(c) => tryRoute(c, () => deps.catalogue.getCategoryProducts(c.req.param("category_id")))
|
|
2343
|
+
);
|
|
2344
|
+
app.get(
|
|
2345
|
+
"/catalogue/categories/:category_id/attributes",
|
|
2346
|
+
(c) => tryRoute(c, () => deps.catalogue.getCategoryAttributes(c.req.param("category_id")))
|
|
2347
|
+
);
|
|
2348
|
+
app.get(
|
|
2349
|
+
"/catalogue/categories/:category_id/deals",
|
|
2350
|
+
(c) => tryRoute(c, () => deps.catalogue.getCategoryDeals(c.req.param("category_id")))
|
|
2351
|
+
);
|
|
2352
|
+
app.get(
|
|
2353
|
+
"/catalogue/collections",
|
|
2354
|
+
(c) => tryRoute(c, () => deps.catalogue.listCollections(deps.defaultBusinessId))
|
|
2355
|
+
);
|
|
2356
|
+
app.get(
|
|
2357
|
+
"/catalogue/collections/:collection_id",
|
|
2358
|
+
(c) => tryRoute(c, () => deps.catalogue.getCollection(c.req.param("collection_id")))
|
|
2359
|
+
);
|
|
2360
|
+
app.get(
|
|
2361
|
+
"/catalogue/collections/:collection_id/products",
|
|
2362
|
+
(c) => tryRoute(c, () => deps.catalogue.getCollectionProducts(c.req.param("collection_id")))
|
|
2363
|
+
);
|
|
2364
|
+
app.get(
|
|
2365
|
+
"/catalogue/collections/:collection_id/attributes",
|
|
2366
|
+
(c) => tryRoute(c, () => deps.catalogue.getCollectionAttributes(c.req.param("collection_id")))
|
|
2367
|
+
);
|
|
2368
|
+
app.get(
|
|
2369
|
+
"/catalogue/collections/:collection_id/deals",
|
|
2370
|
+
(c) => tryRoute(c, () => deps.catalogue.getCollectionDeals(c.req.param("collection_id")))
|
|
2371
|
+
);
|
|
2372
|
+
app.get(
|
|
2373
|
+
"/catalogue/bundles",
|
|
2374
|
+
(c) => tryRoute(c, () => deps.catalogue.listBundles(deps.defaultBusinessId))
|
|
2375
|
+
);
|
|
2376
|
+
app.get(
|
|
2377
|
+
"/catalogue/bundles/:bundle_id",
|
|
2378
|
+
(c) => tryRoute(c, () => deps.catalogue.getBundle(c.req.param("bundle_id")))
|
|
2379
|
+
);
|
|
2380
|
+
app.get(
|
|
2381
|
+
"/catalogue/composites",
|
|
2382
|
+
(c) => tryRoute(c, () => deps.catalogue.listComposites(deps.defaultBusinessId))
|
|
2383
|
+
);
|
|
2384
|
+
app.get(
|
|
2385
|
+
"/catalogue/composites/by-product/:product_id",
|
|
2386
|
+
(c) => tryRoute(c, () => deps.catalogue.getCompositeByProduct(c.req.param("product_id")))
|
|
2387
|
+
);
|
|
2388
|
+
app.get(
|
|
2389
|
+
"/catalogue/composites/:composite_id",
|
|
2390
|
+
(c) => tryRoute(c, () => deps.catalogue.getComposite(c.req.param("composite_id")))
|
|
2391
|
+
);
|
|
2307
2392
|
app.post("/catalogue/composites/:composite_id/calculate-price", async (c) => {
|
|
2308
2393
|
const body = await c.req.json().catch(() => ({}));
|
|
2309
|
-
return tryRoute(
|
|
2394
|
+
return tryRoute(
|
|
2395
|
+
c,
|
|
2396
|
+
() => deps.catalogue.calculateCompositePrice(c.req.param("composite_id"), body)
|
|
2397
|
+
);
|
|
2310
2398
|
});
|
|
2311
|
-
app.get(
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
app.get(
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2399
|
+
app.get(
|
|
2400
|
+
"/catalogue/taxonomies",
|
|
2401
|
+
(c) => tryRoute(c, () => deps.catalogue.listTaxonomies(deps.defaultBusinessId))
|
|
2402
|
+
);
|
|
2403
|
+
app.get(
|
|
2404
|
+
"/catalogue/taxonomies/search",
|
|
2405
|
+
(c) => tryRoute(
|
|
2406
|
+
c,
|
|
2407
|
+
() => deps.catalogue.searchTaxonomies(deps.defaultBusinessId, c.req.query("q") ?? "")
|
|
2408
|
+
)
|
|
2409
|
+
);
|
|
2410
|
+
app.get(
|
|
2411
|
+
"/catalogue/taxonomies/:taxonomy_id",
|
|
2412
|
+
(c) => tryRoute(c, () => deps.catalogue.getTaxonomy(c.req.param("taxonomy_id")))
|
|
2413
|
+
);
|
|
2414
|
+
app.get(
|
|
2415
|
+
"/catalogue/taxonomies/:taxonomy_id/attributes",
|
|
2416
|
+
(c) => tryRoute(c, () => deps.catalogue.getTaxonomyAttributes(c.req.param("taxonomy_id")))
|
|
2417
|
+
);
|
|
2418
|
+
app.get(
|
|
2419
|
+
"/catalogue/taxonomies/:taxonomy_id/path",
|
|
2420
|
+
(c) => tryRoute(c, () => deps.catalogue.getTaxonomyPath(c.req.param("taxonomy_id")))
|
|
2421
|
+
);
|
|
2422
|
+
app.get(
|
|
2423
|
+
"/catalogue/attributes",
|
|
2424
|
+
(c) => tryRoute(c, () => deps.catalogue.listAttributes(deps.defaultBusinessId))
|
|
2425
|
+
);
|
|
2426
|
+
app.get(
|
|
2427
|
+
"/catalogue/properties/facets",
|
|
2428
|
+
(c) => tryRoute(c, () => deps.catalogue.listPropertyFacets(deps.defaultBusinessId))
|
|
2429
|
+
);
|
|
2430
|
+
app.get(
|
|
2431
|
+
"/catalogue/tags",
|
|
2432
|
+
(c) => tryRoute(c, () => deps.catalogue.listTags(deps.defaultBusinessId))
|
|
2433
|
+
);
|
|
2319
2434
|
app.get("/catalogue/menu", (c) => tryRoute(c, () => deps.lite.getMenu(deps.defaultBusinessId)));
|
|
2320
|
-
app.get(
|
|
2321
|
-
|
|
2322
|
-
|
|
2435
|
+
app.get(
|
|
2436
|
+
"/catalogue/menu/categories/:category_id",
|
|
2437
|
+
(c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id")))
|
|
2438
|
+
);
|
|
2439
|
+
app.get(
|
|
2440
|
+
"/catalogue/menu/items/:item_id",
|
|
2441
|
+
(c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("item_id")))
|
|
2442
|
+
);
|
|
2443
|
+
app.get(
|
|
2444
|
+
"/catalogue/knowledge-base/articles",
|
|
2445
|
+
(c) => tryRoute(c, () => ({ articles: deps.catalogue.listKnowledgeArticles(deps.defaultBusinessId) }))
|
|
2446
|
+
);
|
|
2323
2447
|
app.get(
|
|
2324
2448
|
"/catalogue/knowledge-base/search",
|
|
2325
|
-
(c) => tryRoute(c, () => ({
|
|
2449
|
+
(c) => tryRoute(c, () => ({
|
|
2450
|
+
results: deps.catalogue.searchKnowledgeBase(deps.defaultBusinessId, c.req.query("q") ?? ""),
|
|
2451
|
+
query: c.req.query("q") ?? ""
|
|
2452
|
+
}))
|
|
2453
|
+
);
|
|
2454
|
+
app.get(
|
|
2455
|
+
"/catalogue/products/:product_id/attributes",
|
|
2456
|
+
(c) => tryRoute(c, () => deps.catalogue.getProductAttributes(c.req.param("product_id")))
|
|
2326
2457
|
);
|
|
2327
|
-
app.get("/catalogue/products/:product_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getProductAttributes(c.req.param("product_id"))));
|
|
2328
2458
|
app.get(
|
|
2329
2459
|
"/catalogue/products/:product_id/available-now",
|
|
2330
2460
|
(c) => tryRoute(c, () => {
|
|
@@ -2343,22 +2473,75 @@ function buildV1(deps) {
|
|
|
2343
2473
|
"/catalogue/products/:product_id/schedules",
|
|
2344
2474
|
(c) => tryRoute(c, () => {
|
|
2345
2475
|
const p = deps.registry.products.get(c.req.param("product_id"));
|
|
2346
|
-
return {
|
|
2476
|
+
return {
|
|
2477
|
+
schedules: p?.metadata?.["time_profiles"] ?? []
|
|
2478
|
+
};
|
|
2347
2479
|
})
|
|
2348
2480
|
);
|
|
2349
|
-
app.get(
|
|
2350
|
-
|
|
2481
|
+
app.get(
|
|
2482
|
+
"/catalogue/deals",
|
|
2483
|
+
(c) => tryRoute(c, () => deps.catalogue.listDeals(deps.defaultBusinessId))
|
|
2484
|
+
);
|
|
2485
|
+
app.get(
|
|
2486
|
+
"/catalogue/deals/on-sale",
|
|
2487
|
+
(c) => tryRoute(c, () => deps.catalogue.listOnSale(deps.defaultBusinessId))
|
|
2488
|
+
);
|
|
2351
2489
|
app.post("/catalogue/deals/validate", async (c) => {
|
|
2352
2490
|
const body = await c.req.json().catch(() => ({}));
|
|
2353
|
-
return tryRoute(
|
|
2491
|
+
return tryRoute(
|
|
2492
|
+
c,
|
|
2493
|
+
() => deps.catalogue.validateDiscount(
|
|
2494
|
+
body.discount_code ?? body.code ?? "",
|
|
2495
|
+
deps.defaultBusinessId
|
|
2496
|
+
)
|
|
2497
|
+
);
|
|
2354
2498
|
});
|
|
2355
|
-
app.get(
|
|
2499
|
+
app.get(
|
|
2500
|
+
"/catalogue/products/:product_id/deals",
|
|
2501
|
+
(c) => tryRoute(c, () => deps.catalogue.getProductDeals(c.req.param("product_id")))
|
|
2502
|
+
);
|
|
2356
2503
|
app.post("/catalogue/quotes", async (c) => {
|
|
2357
2504
|
const body = await c.req.json().catch(() => ({}));
|
|
2358
2505
|
return tryRoute(c, () => deps.catalogue.createQuote(deps.defaultBusinessId, body));
|
|
2359
2506
|
});
|
|
2360
|
-
app.get(
|
|
2361
|
-
|
|
2507
|
+
app.get(
|
|
2508
|
+
"/catalogue/quotes/:quote_id",
|
|
2509
|
+
(c) => tryRoute(c, () => deps.catalogue.getQuote(c.req.param("quote_id")))
|
|
2510
|
+
);
|
|
2511
|
+
app.post(
|
|
2512
|
+
"/catalogue/quotes/:quote_id/refresh",
|
|
2513
|
+
(c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
|
|
2514
|
+
);
|
|
2515
|
+
app.get("/reviews/summary", (c) => {
|
|
2516
|
+
const productId = c.req.query("product_id");
|
|
2517
|
+
if (productId !== void 0 && (productId.length === 0 || productId.trim() !== productId)) {
|
|
2518
|
+
return fail(c, validation("product_id must be a non-empty canonical identifier"));
|
|
2519
|
+
}
|
|
2520
|
+
const response = {
|
|
2521
|
+
data: {
|
|
2522
|
+
ratings: {
|
|
2523
|
+
product_id: productId ?? null,
|
|
2524
|
+
review_count: 0,
|
|
2525
|
+
rating_sum: 0,
|
|
2526
|
+
average_rating: null,
|
|
2527
|
+
distribution: { one: 0, two: 0, three: 0, four: 0, five: 0 }
|
|
2528
|
+
},
|
|
2529
|
+
trust_chips: {
|
|
2530
|
+
on_time_delivery_percent: null,
|
|
2531
|
+
delivery_sample_size: 0,
|
|
2532
|
+
average_first_response_seconds: null,
|
|
2533
|
+
support_sample_size: 0
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
};
|
|
2537
|
+
return c.json(response);
|
|
2538
|
+
});
|
|
2539
|
+
app.get("/reviews", (c) => {
|
|
2540
|
+
const response = {
|
|
2541
|
+
data: { items: [], next_cursor: null }
|
|
2542
|
+
};
|
|
2543
|
+
return c.json(response);
|
|
2544
|
+
});
|
|
2362
2545
|
app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
|
|
2363
2546
|
app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
|
|
2364
2547
|
app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
|
|
@@ -2369,9 +2552,15 @@ function buildV1(deps) {
|
|
|
2369
2552
|
app.patch("/cart/items/:cart_item_id", async (c) => {
|
|
2370
2553
|
const body = await c.req.json().catch(() => ({}));
|
|
2371
2554
|
if (typeof body.quantity !== "number") return fail(c, validation("quantity required"));
|
|
2372
|
-
return tryRoute(
|
|
2555
|
+
return tryRoute(
|
|
2556
|
+
c,
|
|
2557
|
+
() => deps.cart.updateQuantity(c.var.session, c.req.param("cart_item_id"), body.quantity)
|
|
2558
|
+
);
|
|
2373
2559
|
});
|
|
2374
|
-
app.delete(
|
|
2560
|
+
app.delete(
|
|
2561
|
+
"/cart/items/:cart_item_id",
|
|
2562
|
+
(c) => tryRoute(c, () => deps.cart.removeItem(c.var.session, c.req.param("cart_item_id")))
|
|
2563
|
+
);
|
|
2375
2564
|
app.get("/cart/count", (c) => tryRoute(c, () => deps.cart.getCount(c.var.session)));
|
|
2376
2565
|
app.get("/cart/total", (c) => tryRoute(c, () => deps.cart.getTotal(c.var.session)));
|
|
2377
2566
|
app.post("/cart/destination-quote", async (c) => {
|
|
@@ -2382,10 +2571,25 @@ function buildV1(deps) {
|
|
|
2382
2571
|
const body = await c.req.json().catch(() => ({}));
|
|
2383
2572
|
return tryRoute(c, () => deps.cart.applyCoupon(c.var.session, body.coupon_code ?? ""));
|
|
2384
2573
|
});
|
|
2385
|
-
app.delete(
|
|
2386
|
-
|
|
2574
|
+
app.delete(
|
|
2575
|
+
"/cart/coupons/current",
|
|
2576
|
+
(c) => tryRoute(c, () => deps.cart.removeCoupon(c.var.session))
|
|
2577
|
+
);
|
|
2578
|
+
app.get(
|
|
2579
|
+
"/orders",
|
|
2580
|
+
(c) => tryRoute(
|
|
2581
|
+
c,
|
|
2582
|
+
() => deps.orders.list(c.var.session, {
|
|
2583
|
+
limit: getQueryNum(c, "limit"),
|
|
2584
|
+
status: c.req.query("status")
|
|
2585
|
+
})
|
|
2586
|
+
)
|
|
2587
|
+
);
|
|
2387
2588
|
app.get("/orders/:order_id", (c) => tryRoute(c, () => deps.orders.get(c.req.param("order_id"))));
|
|
2388
|
-
app.get(
|
|
2589
|
+
app.get(
|
|
2590
|
+
"/orders/:order_id/payment-status",
|
|
2591
|
+
(c) => tryRoute(c, () => deps.orders.getPaymentStatus(c.req.param("order_id")))
|
|
2592
|
+
);
|
|
2389
2593
|
app.post("/orders/:order_id/cancel", async (c) => {
|
|
2390
2594
|
const body = await c.req.json().catch(() => ({}));
|
|
2391
2595
|
return tryRoute(c, () => deps.orders.cancel(c.req.param("order_id"), body.reason));
|
|
@@ -2394,13 +2598,46 @@ function buildV1(deps) {
|
|
|
2394
2598
|
const body = await c.req.json().catch(() => ({}));
|
|
2395
2599
|
return tryRoute(c, () => deps.orders.updateCustomer(c.req.param("order_id"), body));
|
|
2396
2600
|
});
|
|
2397
|
-
app.post(
|
|
2601
|
+
app.post(
|
|
2602
|
+
"/orders/:order_id/verify-payment",
|
|
2603
|
+
(c) => tryRoute(c, () => deps.orders.verifyPayment(c.req.param("order_id")))
|
|
2604
|
+
);
|
|
2398
2605
|
app.get("/subscriptions", (c) => tryRoute(c, () => deps.subscriptions.list(c.var.session)));
|
|
2399
|
-
app.get(
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
app.post(
|
|
2606
|
+
app.get(
|
|
2607
|
+
"/subscriptions/:subscription_id",
|
|
2608
|
+
(c) => tryRoute(c, () => deps.subscriptions.get(c.req.param("subscription_id")))
|
|
2609
|
+
);
|
|
2610
|
+
app.post(
|
|
2611
|
+
"/subscriptions/:subscription_id/cancel",
|
|
2612
|
+
(c) => tryRoute(c, () => deps.subscriptions.cancel(c.req.param("subscription_id")))
|
|
2613
|
+
);
|
|
2614
|
+
app.post(
|
|
2615
|
+
"/subscriptions/:subscription_id/pause",
|
|
2616
|
+
(c) => tryRoute(c, () => deps.subscriptions.pause(c.req.param("subscription_id")))
|
|
2617
|
+
);
|
|
2618
|
+
app.post(
|
|
2619
|
+
"/subscriptions/:subscription_id/resume",
|
|
2620
|
+
(c) => tryRoute(c, () => deps.subscriptions.resume(c.req.param("subscription_id")))
|
|
2621
|
+
);
|
|
2622
|
+
app.post(
|
|
2623
|
+
"/subscriptions/:subscription_id/skip",
|
|
2624
|
+
(c) => tryRoute(c, () => deps.subscriptions.skipNext(c.req.param("subscription_id")))
|
|
2625
|
+
);
|
|
2626
|
+
app.get("/payments/collection-options", (c) => {
|
|
2627
|
+
const currency = c.req.query("currency")?.trim().toUpperCase();
|
|
2628
|
+
if (!currency || !/^[A-Z]{3}$/.test(currency)) {
|
|
2629
|
+
return fail(c, validation("currency must be a canonical three-letter code"));
|
|
2630
|
+
}
|
|
2631
|
+
return tryRoute(c, () => ({
|
|
2632
|
+
presentment_currency: currency,
|
|
2633
|
+
options: currency === "GHS" ? [
|
|
2634
|
+
{ method: PAYMENT_METHOD.CARD, network: null },
|
|
2635
|
+
{ method: PAYMENT_METHOD.MOBILE_MONEY, network: "mtn" },
|
|
2636
|
+
{ method: PAYMENT_METHOD.MOBILE_MONEY, network: "telecel" },
|
|
2637
|
+
{ method: PAYMENT_METHOD.MOBILE_MONEY, network: "airteltigo" }
|
|
2638
|
+
] : currency === "USD" ? [{ method: PAYMENT_METHOD.CARD, network: null }] : []
|
|
2639
|
+
}));
|
|
2640
|
+
});
|
|
2404
2641
|
app.post("/checkout", async (c) => {
|
|
2405
2642
|
const body = await c.req.json().catch(() => ({}));
|
|
2406
2643
|
return tryRoute(c, () => deps.checkout.process(c.var.session, body));
|
|
@@ -2454,15 +2691,33 @@ function buildV1(deps) {
|
|
|
2454
2691
|
return { success: true, message: "Profile updated successfully" };
|
|
2455
2692
|
});
|
|
2456
2693
|
});
|
|
2457
|
-
app.get(
|
|
2458
|
-
|
|
2694
|
+
app.get(
|
|
2695
|
+
"/inventory/products/:product_id/stock",
|
|
2696
|
+
(c) => tryRoute(c, () => deps.inventory.productStock(c.req.param("product_id")))
|
|
2697
|
+
);
|
|
2698
|
+
app.get(
|
|
2699
|
+
"/inventory/variants/:variant_id/stock",
|
|
2700
|
+
(c) => tryRoute(c, () => deps.inventory.variantStock(c.req.param("variant_id")))
|
|
2701
|
+
);
|
|
2459
2702
|
app.get(
|
|
2460
2703
|
"/inventory/products/:product_id/availability",
|
|
2461
|
-
(c) => tryRoute(
|
|
2704
|
+
(c) => tryRoute(
|
|
2705
|
+
c,
|
|
2706
|
+
() => deps.inventory.productAvailability(
|
|
2707
|
+
c.req.param("product_id"),
|
|
2708
|
+
getQueryNum(c, "quantity") ?? 1
|
|
2709
|
+
)
|
|
2710
|
+
)
|
|
2462
2711
|
);
|
|
2463
2712
|
app.get(
|
|
2464
2713
|
"/inventory/variants/:variant_id/availability",
|
|
2465
|
-
(c) => tryRoute(
|
|
2714
|
+
(c) => tryRoute(
|
|
2715
|
+
c,
|
|
2716
|
+
() => deps.inventory.variantAvailability(
|
|
2717
|
+
c.req.param("variant_id"),
|
|
2718
|
+
getQueryNum(c, "quantity") ?? 1
|
|
2719
|
+
)
|
|
2720
|
+
)
|
|
2466
2721
|
);
|
|
2467
2722
|
app.get(
|
|
2468
2723
|
"/delivery/fee",
|
|
@@ -2489,35 +2744,75 @@ function buildV1(deps) {
|
|
|
2489
2744
|
);
|
|
2490
2745
|
app.post("/places/autocomplete", async (c) => {
|
|
2491
2746
|
const body = await c.req.json().catch(() => ({}));
|
|
2492
|
-
return tryRoute(
|
|
2747
|
+
return tryRoute(
|
|
2748
|
+
c,
|
|
2749
|
+
() => deps.places.autocomplete({ query: body.input ?? body.query ?? "", country: body.country })
|
|
2750
|
+
);
|
|
2493
2751
|
});
|
|
2494
2752
|
app.post("/places/details", async (c) => {
|
|
2495
2753
|
const body = await c.req.json().catch(() => ({}));
|
|
2496
2754
|
return tryRoute(c, () => deps.places.details({ place_id: body.place_id ?? "" }));
|
|
2497
2755
|
});
|
|
2498
|
-
app.get(
|
|
2499
|
-
|
|
2500
|
-
|
|
2756
|
+
app.get(
|
|
2757
|
+
"/scheduling/services",
|
|
2758
|
+
(c) => tryRoute(c, () => deps.scheduling.listServices(deps.defaultBusinessId))
|
|
2759
|
+
);
|
|
2760
|
+
app.get(
|
|
2761
|
+
"/scheduling/services/:service_id",
|
|
2762
|
+
(c) => tryRoute(c, () => deps.scheduling.getService(c.req.param("service_id")))
|
|
2763
|
+
);
|
|
2764
|
+
app.get(
|
|
2765
|
+
"/scheduling/slots",
|
|
2766
|
+
(c) => tryRoute(
|
|
2767
|
+
c,
|
|
2768
|
+
() => deps.scheduling.getSlots(c.req.query("service_id") ?? "", { date: c.req.query("date") })
|
|
2769
|
+
)
|
|
2770
|
+
);
|
|
2501
2771
|
app.get(
|
|
2502
2772
|
"/scheduling/slots/check",
|
|
2503
|
-
(c) => tryRoute(
|
|
2773
|
+
(c) => tryRoute(
|
|
2774
|
+
c,
|
|
2775
|
+
() => deps.scheduling.checkSlot(
|
|
2776
|
+
c.req.query("service_id") ?? "",
|
|
2777
|
+
c.req.query("start") ?? "",
|
|
2778
|
+
c.req.query("end") ?? ""
|
|
2779
|
+
)
|
|
2780
|
+
)
|
|
2781
|
+
);
|
|
2782
|
+
app.get(
|
|
2783
|
+
"/scheduling/availability",
|
|
2784
|
+
(c) => tryRoute(c, () => deps.scheduling.getServiceAvailability(c.req.query("service_id") ?? ""))
|
|
2785
|
+
);
|
|
2786
|
+
app.get(
|
|
2787
|
+
"/scheduling/bookings",
|
|
2788
|
+
(c) => tryRoute(c, () => deps.scheduling.getCustomerBookings(c.var.session))
|
|
2504
2789
|
);
|
|
2505
|
-
app.get("/scheduling/availability", (c) => tryRoute(c, () => deps.scheduling.getServiceAvailability(c.req.query("service_id") ?? "")));
|
|
2506
|
-
app.get("/scheduling/bookings", (c) => tryRoute(c, () => deps.scheduling.getCustomerBookings(c.var.session)));
|
|
2507
2790
|
app.post("/scheduling/bookings/reschedule", async (c) => {
|
|
2508
2791
|
const body = await c.req.json().catch(() => ({}));
|
|
2509
2792
|
return tryRoute(c, () => deps.scheduling.rescheduleBooking(body));
|
|
2510
2793
|
});
|
|
2511
|
-
app.get(
|
|
2794
|
+
app.get(
|
|
2795
|
+
"/scheduling/bookings/:booking_id",
|
|
2796
|
+
(c) => tryRoute(c, () => deps.scheduling.getBooking(c.req.param("booking_id")))
|
|
2797
|
+
);
|
|
2512
2798
|
app.post("/scheduling/bookings/:booking_id/cancel", async (c) => {
|
|
2513
2799
|
const body = await c.req.json().catch(() => ({}));
|
|
2514
2800
|
return tryRoute(c, () => deps.scheduling.cancelBooking(c.req.param("booking_id"), body.reason));
|
|
2515
2801
|
});
|
|
2516
2802
|
app.get("/lite/bootstrap", (c) => tryRoute(c, () => deps.lite.bootstrap(deps.defaultBusinessId)));
|
|
2517
|
-
app.get(
|
|
2803
|
+
app.get(
|
|
2804
|
+
"/lite/resources/:resource_id",
|
|
2805
|
+
(c) => tryRoute(c, () => deps.lite.getResource(c.req.param("resource_id")))
|
|
2806
|
+
);
|
|
2518
2807
|
app.get("/lite/menu", (c) => tryRoute(c, () => deps.lite.getMenu(deps.defaultBusinessId)));
|
|
2519
|
-
app.get(
|
|
2520
|
-
|
|
2808
|
+
app.get(
|
|
2809
|
+
"/lite/menu/categories/:category_id",
|
|
2810
|
+
(c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id")))
|
|
2811
|
+
);
|
|
2812
|
+
app.get(
|
|
2813
|
+
"/fx/rate",
|
|
2814
|
+
(c) => tryRoute(c, () => deps.fx.getRate(c.req.query("from") ?? "USD", c.req.query("to") ?? "GHS"))
|
|
2815
|
+
);
|
|
2521
2816
|
app.post("/fx/quotes", async (c) => {
|
|
2522
2817
|
const body = await c.req.json().catch(() => ({}));
|
|
2523
2818
|
return tryRoute(c, () => deps.fx.lockQuote(body));
|
|
@@ -2530,31 +2825,47 @@ function buildV1(deps) {
|
|
|
2530
2825
|
const body = await c.req.json().catch(() => ({}));
|
|
2531
2826
|
return tryRoute(c, () => deps.uploads.confirm(body));
|
|
2532
2827
|
});
|
|
2533
|
-
app.get(
|
|
2534
|
-
"/store-credit/balance",
|
|
2535
|
-
(c) => c.json({ data: { balance: "0.00", currency: "USD" } })
|
|
2536
|
-
);
|
|
2828
|
+
app.get("/store-credit/balance", (c) => c.json({ data: { balance: "0.00", currency: "USD" } }));
|
|
2537
2829
|
app.post("/activity/session", async (c) => {
|
|
2538
2830
|
await c.req.json().catch(() => ({}));
|
|
2539
2831
|
return c.json({ data: { recorded: true } });
|
|
2540
2832
|
});
|
|
2541
2833
|
app.post("/activity/events", async (c) => {
|
|
2542
2834
|
const body = await c.req.json().catch(() => ({}));
|
|
2543
|
-
return tryRoute(
|
|
2835
|
+
return tryRoute(
|
|
2836
|
+
c,
|
|
2837
|
+
() => deps.activity.recordEvents(
|
|
2838
|
+
deps.defaultBusinessId,
|
|
2839
|
+
body.analytics_session_id ?? c.var.session.id,
|
|
2840
|
+
body.events ?? []
|
|
2841
|
+
)
|
|
2842
|
+
);
|
|
2544
2843
|
});
|
|
2545
|
-
app.get(
|
|
2546
|
-
|
|
2844
|
+
app.get(
|
|
2845
|
+
"/activity/state",
|
|
2846
|
+
(c) => tryRoute(c, () => deps.activity.getState(deps.defaultBusinessId, c.var.session.id))
|
|
2847
|
+
);
|
|
2848
|
+
app.get(
|
|
2849
|
+
"/activity/recommendations",
|
|
2850
|
+
(c) => tryRoute(c, () => deps.activity.getRecommendations(deps.defaultBusinessId))
|
|
2851
|
+
);
|
|
2547
2852
|
app.post("/activity/messages/dismiss", async (c) => {
|
|
2548
2853
|
const body = await c.req.json().catch(() => ({}));
|
|
2549
2854
|
return tryRoute(c, () => deps.activity.dismissMessage(body.code ?? body.message_id ?? ""));
|
|
2550
2855
|
});
|
|
2551
2856
|
app.post(
|
|
2552
2857
|
"/support/conversation",
|
|
2553
|
-
(c) => tryRoute(
|
|
2858
|
+
(c) => tryRoute(
|
|
2859
|
+
c,
|
|
2860
|
+
() => deps.support.openConversation(deps.defaultBusinessId, c.var.session.customer_id)
|
|
2861
|
+
)
|
|
2554
2862
|
);
|
|
2555
2863
|
app.get(
|
|
2556
2864
|
"/support/conversation",
|
|
2557
|
-
(c) => tryRoute(
|
|
2865
|
+
(c) => tryRoute(
|
|
2866
|
+
c,
|
|
2867
|
+
() => deps.support.peekConversation(deps.defaultBusinessId, c.var.session.customer_id)
|
|
2868
|
+
)
|
|
2558
2869
|
);
|
|
2559
2870
|
app.post("/support/conversation/messages", async (c) => {
|
|
2560
2871
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -2570,7 +2881,12 @@ function buildV1(deps) {
|
|
|
2570
2881
|
});
|
|
2571
2882
|
app.get(
|
|
2572
2883
|
"/support/conversation/messages",
|
|
2573
|
-
(c) => tryRoute(
|
|
2884
|
+
(c) => tryRoute(
|
|
2885
|
+
c,
|
|
2886
|
+
() => deps.support.listMessages(c.req.query("conversation_id") ?? "", {
|
|
2887
|
+
limit: getQueryNum(c, "limit")
|
|
2888
|
+
})
|
|
2889
|
+
)
|
|
2574
2890
|
);
|
|
2575
2891
|
app.post("/support/conversation/messages/:messageId/reactions", async (c) => {
|
|
2576
2892
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -2591,7 +2907,10 @@ function buildV1(deps) {
|
|
|
2591
2907
|
});
|
|
2592
2908
|
app.get(
|
|
2593
2909
|
"/support/conversation/ws",
|
|
2594
|
-
(c) => c.json(
|
|
2910
|
+
(c) => c.json(
|
|
2911
|
+
{ note: "WebSocket connection \u2014 connect via ws:// at the same path", supported: false },
|
|
2912
|
+
426
|
|
2913
|
+
)
|
|
2595
2914
|
);
|
|
2596
2915
|
return app;
|
|
2597
2916
|
}
|
|
@@ -3118,9 +3437,10 @@ function buildLink(deps) {
|
|
|
3118
3437
|
app.post("/auth/request-otp", async (c) => {
|
|
3119
3438
|
const body = await c.req.json().catch(() => ({}));
|
|
3120
3439
|
return tryRoute(c, () => {
|
|
3121
|
-
deps.auth.requestOtp(body.contact ?? "");
|
|
3440
|
+
const challenge = deps.auth.requestOtp(body.contact ?? "");
|
|
3122
3441
|
return {
|
|
3123
3442
|
success: true,
|
|
3443
|
+
challenge_id: challenge.otp_id,
|
|
3124
3444
|
message: `OTP sent to ${body.contact ?? "contact"}`,
|
|
3125
3445
|
expires_in: 300,
|
|
3126
3446
|
is_new_account: false
|
|
@@ -3130,7 +3450,11 @@ function buildLink(deps) {
|
|
|
3130
3450
|
app.post("/auth/verify-otp", async (c) => {
|
|
3131
3451
|
const body = await c.req.json().catch(() => ({}));
|
|
3132
3452
|
return tryRoute(c, () => {
|
|
3133
|
-
const session = deps.auth.verifyOtp(
|
|
3453
|
+
const session = deps.auth.verifyOtp(
|
|
3454
|
+
body.contact ?? "",
|
|
3455
|
+
body.otp_code ?? "",
|
|
3456
|
+
body.challenge_id
|
|
3457
|
+
);
|
|
3134
3458
|
c.header("x-session-token", session.token);
|
|
3135
3459
|
const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
|
|
3136
3460
|
email: body.contact?.includes("@") ? body.contact : void 0,
|
|
@@ -3224,10 +3548,7 @@ function buildLink(deps) {
|
|
|
3224
3548
|
};
|
|
3225
3549
|
});
|
|
3226
3550
|
});
|
|
3227
|
-
app.get(
|
|
3228
|
-
"/preferences",
|
|
3229
|
-
(c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
|
|
3230
|
-
);
|
|
3551
|
+
app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
|
|
3231
3552
|
app.post("/preferences", async (c) => {
|
|
3232
3553
|
const body = await c.req.json().catch(() => ({}));
|
|
3233
3554
|
return tryRoute(c, () => {
|
|
@@ -3704,9 +4025,16 @@ function createAuthService(opts) {
|
|
|
3704
4025
|
code_hint: options.mode === "permissive" ? code : void 0
|
|
3705
4026
|
};
|
|
3706
4027
|
},
|
|
3707
|
-
verifyOtp(contact, code) {
|
|
3708
|
-
|
|
3709
|
-
|
|
4028
|
+
verifyOtp(contact, code, challengeId) {
|
|
4029
|
+
let otp = challengeId ? registry.otps.get(challengeId) : void 0;
|
|
4030
|
+
if (!challengeId) {
|
|
4031
|
+
const matching = registry.otps.list((o) => o.contact === contact);
|
|
4032
|
+
otp = matching[matching.length - 1];
|
|
4033
|
+
}
|
|
4034
|
+
if (challengeId) {
|
|
4035
|
+
if (!otp) throw new Error("No OTP challenge found");
|
|
4036
|
+
if (otp.contact !== contact) throw new Error("OTP challenge does not match contact");
|
|
4037
|
+
}
|
|
3710
4038
|
if (options.mode === "strict") {
|
|
3711
4039
|
if (!otp) throw new Error("No OTP requested");
|
|
3712
4040
|
if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
|
|
@@ -5034,7 +5362,7 @@ function createCartService(opts) {
|
|
|
5034
5362
|
|
|
5035
5363
|
// src/mock/domain/checkout.ts
|
|
5036
5364
|
function createCheckoutService(opts) {
|
|
5037
|
-
const { registry, clock, ids, bus} = opts;
|
|
5365
|
+
const { registry, clock, ids, bus } = opts;
|
|
5038
5366
|
return {
|
|
5039
5367
|
process(session, body) {
|
|
5040
5368
|
if (!body.cart_id) throw validation("cart_id required");
|
|
@@ -5043,9 +5371,11 @@ function createCheckoutService(opts) {
|
|
|
5043
5371
|
if (c.items.length === 0) throw validation("Cart is empty", { code: "CART_EMPTY" });
|
|
5044
5372
|
const orderId = ids.order();
|
|
5045
5373
|
const orderNumber = ids.orderNumber();
|
|
5374
|
+
const paymentId = ids.payment();
|
|
5046
5375
|
const reference = ids.payment();
|
|
5047
5376
|
const requiresAuth = body.payment_method === "mobile_money";
|
|
5048
5377
|
const isCard = body.payment_method === "card" || body.payment_method === "stripe";
|
|
5378
|
+
const cardProvider = body.payment_method === "stripe" || body.pay_currency?.toUpperCase() === "USD" ? "stripe" : "paystack";
|
|
5049
5379
|
const order = {
|
|
5050
5380
|
id: orderId,
|
|
5051
5381
|
business_id: c.business_id,
|
|
@@ -5069,6 +5399,7 @@ function createCheckoutService(opts) {
|
|
|
5069
5399
|
items: c.items,
|
|
5070
5400
|
applied_discount_ids: c.applied_discount_ids,
|
|
5071
5401
|
applied_discount_codes: c.applied_discount_codes,
|
|
5402
|
+
payment_id: paymentId,
|
|
5072
5403
|
payment_reference: reference,
|
|
5073
5404
|
metadata: body.metadata,
|
|
5074
5405
|
created_at: clock.iso(),
|
|
@@ -5085,31 +5416,57 @@ function createCheckoutService(opts) {
|
|
|
5085
5416
|
const result = {
|
|
5086
5417
|
order_id: orderId,
|
|
5087
5418
|
order_number: orderNumber,
|
|
5088
|
-
|
|
5419
|
+
payment_id: paymentId,
|
|
5420
|
+
payment_status: requiresAuth || isCard ? "pending" : "succeeded",
|
|
5089
5421
|
payment_reference: reference,
|
|
5090
5422
|
requires_authorization: requiresAuth,
|
|
5091
5423
|
authorization_type: requiresAuth ? "otp" : void 0,
|
|
5092
|
-
next_action: requiresAuth ? {
|
|
5093
|
-
|
|
5424
|
+
next_action: requiresAuth ? {
|
|
5425
|
+
type: "authorization",
|
|
5426
|
+
authorization_type: "otp",
|
|
5427
|
+
display_text: "Approve on your mobile money app"
|
|
5428
|
+
} : { type: "none" },
|
|
5429
|
+
provider: isCard ? cardProvider : body.payment_method,
|
|
5094
5430
|
bill_token: billToken
|
|
5095
5431
|
};
|
|
5096
5432
|
if (isCard) {
|
|
5097
|
-
result.next_action = { type: "redirect", authorization_url: `https://mock.cimplify.io/pay/${reference}` };
|
|
5098
|
-
result.authorization_url = `https://mock.cimplify.io/pay/${reference}`;
|
|
5099
|
-
result.client_secret = `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}`;
|
|
5100
5433
|
const proc = globalThis.process;
|
|
5101
|
-
result.
|
|
5434
|
+
result.client_secret = cardProvider === "stripe" ? `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}` : `access_${reference}`;
|
|
5435
|
+
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";
|
|
5436
|
+
result.next_action = {
|
|
5437
|
+
type: "card_popup",
|
|
5438
|
+
provider: cardProvider,
|
|
5439
|
+
client_secret: result.client_secret,
|
|
5440
|
+
public_key: result.public_key
|
|
5441
|
+
};
|
|
5102
5442
|
}
|
|
5103
5443
|
return result;
|
|
5104
5444
|
},
|
|
5105
5445
|
authorize(body) {
|
|
5106
|
-
|
|
5107
|
-
if (!
|
|
5108
|
-
const
|
|
5446
|
+
if (!body.payment_id?.trim()) throw validation("payment_id required");
|
|
5447
|
+
if (!body.authorization) throw validation("authorization required");
|
|
5448
|
+
const order = registry.orders.list(
|
|
5449
|
+
(candidate) => candidate.payment_id === body.payment_id
|
|
5450
|
+
)[0];
|
|
5451
|
+
if (!order) throw notFound(`Payment ${body.payment_id} not found`);
|
|
5452
|
+
const updated = {
|
|
5453
|
+
...order,
|
|
5454
|
+
payment_state: "paid",
|
|
5455
|
+
status: "confirmed",
|
|
5456
|
+
updated_at: clock.iso()
|
|
5457
|
+
};
|
|
5109
5458
|
registry.orders.put(order.id, updated);
|
|
5110
5459
|
bus.emit("order.payment.captured", { order_id: order.id }, order.business_id);
|
|
5111
5460
|
bus.emit("order.confirmed", { order_id: order.id }, order.business_id);
|
|
5112
|
-
return {
|
|
5461
|
+
return {
|
|
5462
|
+
order_id: order.id,
|
|
5463
|
+
order_number: order.user_friendly_id,
|
|
5464
|
+
payment_id: body.payment_id,
|
|
5465
|
+
payment_reference: order.payment_reference,
|
|
5466
|
+
payment_status: "succeeded",
|
|
5467
|
+
requires_authorization: false,
|
|
5468
|
+
next_action: { type: "none" }
|
|
5469
|
+
};
|
|
5113
5470
|
}
|
|
5114
5471
|
};
|
|
5115
5472
|
}
|
|
@@ -5492,6 +5849,7 @@ function createDeliveryService() {
|
|
|
5492
5849
|
rate_id: "dlvrt_mock_standard",
|
|
5493
5850
|
name: "Standard",
|
|
5494
5851
|
fee: standardFree ? money(0) : money(15),
|
|
5852
|
+
fee_status: "priced",
|
|
5495
5853
|
currency: "GHS",
|
|
5496
5854
|
free_delivery_applied: standardFree,
|
|
5497
5855
|
free_over_amount: money(200),
|
|
@@ -5505,6 +5863,7 @@ function createDeliveryService() {
|
|
|
5505
5863
|
name: "Express",
|
|
5506
5864
|
description: "Delivered within the hour",
|
|
5507
5865
|
fee: money(25),
|
|
5866
|
+
fee_status: "priced",
|
|
5508
5867
|
currency: "GHS",
|
|
5509
5868
|
free_delivery_applied: false,
|
|
5510
5869
|
eta_min_minutes: 30,
|