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