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