@aglyn/plugins-commerce 1.0.0-beta.264 → 1.0.0-beta.266
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/package.json +13 -13
- package/src/lib/components/console/product-editor-dialog.component.js +10 -1
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +11 -10
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/server/billing-webhook.js +3 -1
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/pos-payment.js +9 -5
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/pos-terminal.d.ts +12 -1
- package/src/lib/server/pos-terminal.js +82 -3
- package/src/lib/server/pos-terminal.js.map +1 -1
- package/src/lib/server/printers.js +33 -5
- package/src/lib/server/printers.js.map +1 -1
- package/src/lib/server/product-drafts.js +3 -2
- package/src/lib/server/product-drafts.js.map +1 -1
- package/src/lib/server/product-writer.js +3 -1
- package/src/lib/server/product-writer.js.map +1 -1
- package/src/lib/server/products-write.js +3 -2
- package/src/lib/server/products-write.js.map +1 -1
- package/src/lib/server/returns.js +3 -1
- package/src/lib/server/returns.js.map +1 -1
- package/src/lib/tenant-emails.js +264 -84
- package/src/lib/tenant-emails.js.map +1 -1
- package/src/lib/testing/memory-firestore.d.ts +5 -3
- package/src/lib/testing/memory-firestore.js +6 -3
- package/src/lib/testing/memory-firestore.js.map +1 -1
- package/src/lib/transfer/products.server.js +3 -2
- package/src/lib/transfer/products.server.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/products-write.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createHash } from 'node:crypto'\nimport { isRefusedIdToken } from '@aglyn/tenant-data-admin/server/id-token-refusal'\nimport { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport { hostRoleCanWrite } from '@aglyn/aglyn/app-utils/organizations'\nimport { dropPluginSiteCache } from '@aglyn/aglyn/plugin-manager/plugin-site-cache'\nimport { type PluginApiHandler } from '@aglyn/aglyn/server'\nimport { firebaseAdmin, getLockdownVerdict, getOrgForHost, isImpersonationSession } from '@aglyn/tenant-data-admin'\nimport { FieldValue } from 'firebase-admin/firestore'\nimport {\n type EditedProduct,\n liftLegacyProduct,\n productCollectionIds,\n productDuplicateFields,\n productDuplicateName,\n productDuplicateSlugBase,\n productEditWrite,\n productMembershipInput,\n productSaveFields,\n smartCollectionRulesOf,\n stockAdjustmentWrite,\n validateProduct,\n type InventoryAdjustmentReason,\n} from '../model'\nimport { planRefusal, roomRefusal } from './product-drafts'\n\n/*\n * `POST /api/commerce/products/save` and `POST /api/commerce/products/stock`\n * (AGL-3652): the console product editor's save and its Adjust stock dialog,\n * for the native apps.\n *\n * The console makes both writes from the browser, computing derived fields\n * first (search keys, stock verdict, price, image, smart-collection\n * membership). These routes run THAT computation (`model/product-write.ts`,\n * which the console imports too) and make the same writes, under the gate\n * the Firestore rules put on them: a verified member with a write role on the\n * site (`canWriteHostContent`), or staff, while the site, its org and the\n * platform are not frozen (`hostWritesFrozen`). A new product also meets the\n * create path's own door: the plan's `commerce` entitlement and its\n * `productsPerHost` quota, counted in the same transaction as the create.\n */\n\ntype Firestore = FirebaseFirestore.Firestore\n\nexport const ROLE_REFUSAL = 'Editing requires the editor role'\nconst MAX_BODY_BYTES = 256_000\n\n/** The reasons the Adjust stock dialog offers. */\nexport const STOCK_ADJUST_REASONS: readonly InventoryAdjustmentReason[] = ['restock', 'correction', 'damage', 'refund']\n\nexport interface ProductsWriteDeps {\n firestore?: () => Firestore\n verifyIdToken?: (token: string) => Promise<Record<string, unknown> & { uid: string }>\n orgForHost?: (hostId: string) => Promise<{ org: Record<string, unknown> } | null>\n lockdown?: (options: Parameters<typeof getLockdownVerdict>[0]) => Promise<unknown>\n dropCache?: typeof dropPluginSiteCache\n now?: () => number\n}\n\ntype Reply = Parameters<PluginApiHandler>[1]\n\nexport function bodyOf(req: Parameters<PluginApiHandler>[0]): Record<string, unknown> {\n const raw = req.body\n if (typeof raw === 'string') {\n if (raw.length > MAX_BODY_BYTES) return {}\n try {\n return JSON.parse(raw || '{}')\n } catch {\n return {}\n }\n }\n return (raw ?? {}) as Record<string, unknown>\n}\n\nexport const validId = (value: unknown): value is string =>\n typeof value === 'string' && /^[A-Za-z0-9_-]{1,128}$/.test(value)\n\nexport interface Gate {\n uid: string\n staff: boolean\n host: FirebaseFirestore.DocumentSnapshot\n org: Record<string, unknown>\n}\n\n/**\n * Who may write this site's products, as the rules decide it. Answers the\n * caller's reply on a refusal and returns null.\n */\nexport async function gate(req: Parameters<PluginApiHandler>[0], res: Reply, hostId: string, deps: Required<ProductsWriteDeps>): Promise<Gate | null> {\n const authorization = String(req.headers.authorization ?? '')\n const token = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : ''\n if (!token) return void res.status(401).json({ error: 'Unauthenticated' }), null\n let decoded: Record<string, unknown> & { uid: string }\n try {\n decoded = await deps.verifyIdToken(token)\n } catch (error) {\n // Only a refused token is the caller's; an Auth outage is a 500 (AGL-2852).\n if (!isRefusedIdToken(error)) throw error\n return void res.status(401).json({ error: 'Sign in again to continue' }), null\n }\n const staff = decoded['staff'] === true\n if (!staff && decoded['email_verified'] !== true && !isImpersonationSession(decoded as never)) {\n return void res.status(403).json({ error: 'Verify your email address to make changes' }), null\n }\n const host = await deps.firestore().collection('hosts').doc(hostId).get()\n if (!host.exists) return void res.status(404).json({ error: 'Unknown site' }), null\n if (!staff && !hostRoleCanWrite((host.get('memberRoles') ?? {})[decoded.uid])) {\n return void res.status(403).json({ error: ROLE_REFUSAL }), null\n }\n const org = ((await deps.orgForHost(hostId))?.org ?? {}) as Record<string, unknown>\n const locked = await deps.lockdown({ staff, uid: decoded.uid, org: org as never, host: host.data() as never, request: { method: 'POST' } as never })\n if (locked) return void res.status(423).json({ error: 'This site is not accepting changes right now' }), null\n return { uid: decoded.uid, staff, host, org }\n}\n\n/** The site-wide cache drop a product change is owed (AGL-3386): an outbox entry in the write, then the drop. */\nexport function outboxEntry(firestore: Firestore, hostId: string) {\n return {\n ref: firestore.collection('publishOutbox').doc(createResourceUid()),\n data: { hostId, paths: ['/'], createdAt: FieldValue.serverTimestamp(), attempts: 0, entireHost: true },\n }\n}\n\nexport async function settleCache(deps: Required<ProductsWriteDeps>, hostId: string, entry: FirebaseFirestore.DocumentReference, reason: string) {\n const dropped = await deps.dropCache({ hostIds: [hostId], reason }).catch(() => ({ complete: false }))\n if (dropped.complete) await entry.delete().catch(() => undefined)\n}\n\nexport function resolved(deps: ProductsWriteDeps): Required<ProductsWriteDeps> {\n return {\n firestore: deps.firestore ?? (() => firebaseAdmin.app().firestore() as unknown as Firestore),\n verifyIdToken: deps.verifyIdToken ?? ((token) => firebaseAdmin.app().auth().verifyIdToken(token) as never),\n orgForHost: deps.orgForHost ?? ((hostId) => getOrgForHost(hostId) as never),\n lockdown: deps.lockdown ?? ((options) => getLockdownVerdict(options)),\n dropCache: deps.dropCache ?? dropPluginSiteCache,\n now: deps.now ?? (() => Date.now()),\n }\n}\n\n/**\n * Saves a product as the console editor does. `create: true` makes a new\n * product under the client-minted `productId` (a retry finds its own product\n * and answers `replayed`); otherwise it replaces the live product, keeping\n * its live stock holds.\n */\nexport function createProductSaveHandler(options: ProductsWriteDeps = {}): PluginApiHandler {\n return async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const deps = resolved(options)\n const body = bodyOf(req)\n const hostId = body['hostId']\n const productId = body['productId']\n const product = body['product'] as EditedProduct | undefined\n if (!validId(hostId) || !validId(productId) || !product || typeof product !== 'object' || !Array.isArray(product.variants)) {\n return res.status(400).json({ error: 'Missing site, product or its variants' })\n }\n if (typeof product.name !== 'string' || !product.name.trim()) return res.status(400).json({ error: 'Product name is required' })\n try {\n const door = await gate(req, res, hostId, deps)\n if (!door) return\n const nowMs = deps.now()\n const fields = productSaveFields(product, nowMs)\n const problem = validateProduct(fields as never)\n if (problem) return res.status(400).json({ error: problem })\n const db = deps.firestore()\n const hostRef = db.collection('hosts').doc(hostId)\n const products = hostRef.collection('products')\n const productRef = products.doc(productId)\n const smartQuery = hostRef.collection('collections').where('kind', '==', 'catalog').where('mode', '==', 'smart')\n const outbox = outboxEntry(db, hostId)\n const create = body['create'] === true\n const answer = await db.runTransaction(async (tx) => {\n const [existing, smart] = await Promise.all([tx.get(productRef), tx.get(smartQuery)])\n const membership = {\n collectionIds: productCollectionIds(\n productMembershipInput(fields, product) as never,\n smart.docs.map((doc) => smartCollectionRulesOf(doc.id, doc.data())),\n ),\n }\n if (create) {\n if (existing.exists) return { status: 200, body: { ok: true, id: productId, replayed: true } }\n const early = planRefusal(door.org as never)\n if (early) return { status: early.status, body: { error: early.error } }\n const used = (await tx.get(products.count())).data().count\n const room = roomRefusal(door.org as never, Number(used) || 0)\n if (room) return { status: room.status, body: { error: room.error } }\n tx.create(productRef, {\n ...fields,\n ...membership,\n createdAtMs: nowMs,\n deletedAt: null,\n createdAt: FieldValue.serverTimestamp(),\n updatedAt: FieldValue.serverTimestamp(),\n createdBy: door.uid,\n })\n } else {\n if (!existing.exists || existing.get('deletedAt')) return { status: 404, body: { error: 'This product was deleted' } }\n tx.set(productRef, {\n ...storedTimestamps(existing.data() ?? {}, product as unknown as Record<string, unknown>),\n ...productEditWrite(fields, existing.get('stockHolds')),\n ...membership,\n updatedAt: FieldValue.serverTimestamp(),\n })\n }\n tx.set(outbox.ref, outbox.data)\n return { status: 200, body: { ok: true, id: productId, replayed: false } }\n })\n if (answer.status === 200 && !(answer.body as { replayed?: boolean }).replayed) {\n await settleCache(deps, hostId, outbox.ref, 'product saved from the app')\n }\n return res.status(answer.status).json(answer.body)\n } catch (error) {\n console.error('[commerce/products/save]', error)\n return res.status(500).json({ error: 'The product could not be saved' })\n }\n }\n}\n\n/**\n * The stored timestamps an edit keeps. The console's replace writes back the\n * Timestamps its seed carried (`createdAt`, a publish time); a client's JSON\n * cannot carry one, so each stored Timestamp field the request does not name\n * is kept as stored.\n */\nexport function storedTimestamps(stored: Record<string, unknown>, asked: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(stored).filter(\n ([key, value]) => !(key in asked) && typeof (value as { toDate?: unknown } | null)?.toDate === 'function',\n ),\n )\n}\n\n/** The ledger row id one attempt owns: the same key from the same member is the same row. */\nexport function stockAttemptId(uid: string, key: string): string {\n return 'app-' + createHash('sha256').update(`${uid}:${key}`).digest('hex').slice(0, 40)\n}\n\n/**\n * Adjusts one variant's stock as the Adjust stock dialog does: the variants\n * and stock fields on the product, and one `inventoryAdjustments` row, in one\n * transaction. The Idempotency-Key names that row, so a retried attempt finds\n * it and moves nothing twice.\n */\nexport function createProductStockHandler(options: ProductsWriteDeps = {}): PluginApiHandler {\n return async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const deps = resolved(options)\n const body = bodyOf(req)\n const hostId = body['hostId']\n const productId = body['productId']\n const variantId = body['variantId']\n const key = String(req.headers['idempotency-key'] ?? '').trim().slice(0, 200)\n const reason = body['reason'] as InventoryAdjustmentReason\n const delta = Math.round(Number(body['delta']))\n const locationId = typeof body['locationId'] === 'string' && body['locationId'] ? body['locationId'] : undefined\n if (!validId(hostId) || !validId(productId) || typeof variantId !== 'string' || !variantId) {\n return res.status(400).json({ error: 'Missing site, product or variant' })\n }\n if (!key) return res.status(400).json({ error: 'Missing Idempotency-Key' })\n if (!STOCK_ADJUST_REASONS.includes(reason)) return res.status(400).json({ error: 'Unknown reason' })\n if (!Number.isFinite(delta) || delta === 0) return res.status(400).json({ error: 'Enter a number of units' })\n try {\n const door = await gate(req, res, hostId, deps)\n if (!door) return\n const db = deps.firestore()\n const hostRef = db.collection('hosts').doc(hostId)\n const productRef = hostRef.collection('products').doc(productId)\n const ledgerRef = hostRef.collection('inventoryAdjustments').doc(stockAttemptId(door.uid, key))\n const outbox = outboxEntry(db, hostId)\n const answer = await db.runTransaction(async (tx) => {\n const [ledger, stored] = await Promise.all([tx.get(ledgerRef), tx.get(productRef)])\n if (ledger.exists) {\n return { status: 200, body: { ok: true, replayed: true, inventory: stored.get('inventory') ?? null } }\n }\n if (!stored.exists || stored.get('deletedAt')) return { status: 404, body: { error: 'This product was deleted' } }\n const product = stored.data() as never as Parameters<typeof stockAdjustmentWrite>[0]\n if (!(product.variants ?? []).some((variant) => variant.id === variantId)) {\n return { status: 404, body: { error: 'That variant is no longer on this product' } }\n }\n const write = stockAdjustmentWrite(product, productId, { variantId, delta, reason, locationId }, deps.now())\n if (!write) return { status: 400, body: { error: 'Enter a number of units' } }\n tx.update(productRef, write.update)\n tx.create(ledgerRef, write.ledger)\n tx.set(outbox.ref, outbox.data)\n return { status: 200, body: { ok: true, replayed: false, inventory: (write.update as { inventory?: unknown }).inventory ?? null } }\n })\n if (answer.status === 200 && !(answer.body as { replayed?: boolean }).replayed) {\n await settleCache(deps, hostId, outbox.ref, 'stock adjusted from the app')\n }\n return res.status(answer.status).json(answer.body)\n } catch (error) {\n console.error('[commerce/products/stock]', error)\n return res.status(500).json({ error: 'Stock could not be adjusted' })\n }\n }\n}\n\n/**\n * The first slug in `base`, `base-2`, `base-3`… no product of the site holds,\n * as the console's slug ledger claims one (`product-slugs.ts`): a second\n * Duplicate of the same product does not mint a second `-copy` (AGL-3321).\n */\nexport async function claimProductSlug(products: FirebaseFirestore.CollectionReference, base: string): Promise<string> {\n for (let suffix = 1; suffix < 1000; suffix += 1) {\n const candidate = suffix < 2 ? base : `${base}-${suffix}`\n const held = await products.where('slug', '==', candidate).limit(1).get()\n if (held.empty) return candidate\n }\n return `${base}-${Date.now()}`\n}\n\n/**\n * `POST /api/commerce/products/duplicate` (AGL-3841): the products list's\n * Duplicate for the native apps. The console builds the copy in the browser\n * (`productDuplicateFields`, its slug ledger, the copy's smart collections)\n * and creates it through the quota-enforcing resources route; this runs the\n * same model over the stored product and creates it under the save route's\n * create door (the plan's commerce entitlement and its product quota, counted\n * in the same transaction). `newProductId` is the client's, so a retry finds\n * its own copy and answers `replayed`.\n */\nexport function createProductDuplicateHandler(options: ProductsWriteDeps = {}): PluginApiHandler {\n return async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const deps = resolved(options)\n const body = bodyOf(req)\n const { hostId, productId, newProductId } = body\n if (!validId(hostId) || !validId(productId) || !validId(newProductId) || productId === newProductId) {\n return res.status(400).json({ error: 'Missing site or product' })\n }\n try {\n const door = await gate(req, res, hostId, deps)\n if (!door) return\n const db = deps.firestore()\n const hostRef = db.collection('hosts').doc(hostId)\n const products = hostRef.collection('products')\n const copyRef = products.doc(newProductId)\n const already = await copyRef.get()\n if (already.exists) return res.status(200).json({ ok: true, id: newProductId, replayed: true })\n const source = await products.doc(productId).get()\n if (!source.exists || source.get('deletedAt')) return res.status(404).json({ error: 'This product was deleted' })\n const product = liftLegacyProduct((source.data() ?? {}) as never)\n const slug = await claimProductSlug(products, productDuplicateSlugBase(product.slug, product.name))\n const nowMs = deps.now()\n const fields = productDuplicateFields(product, slug, nowMs)\n const smartQuery = hostRef.collection('collections').where('kind', '==', 'catalog').where('mode', '==', 'smart')\n const outbox = outboxEntry(db, hostId)\n const answer = await db.runTransaction(async (tx) => {\n const [existing, smart] = await Promise.all([tx.get(copyRef), tx.get(smartQuery)])\n if (existing.exists) return { status: 200, body: { ok: true, id: newProductId, replayed: true } }\n const early = planRefusal(door.org as never)\n if (early) return { status: early.status, body: { error: early.error } }\n const used = (await tx.get(products.count())).data().count\n const room = roomRefusal(door.org as never, Number(used) || 0)\n if (room) return { status: room.status, body: { error: room.error } }\n // The COPY's smart collections: its name differs from the source's.\n const collectionIds = productCollectionIds(\n productMembershipInput({ name: productDuplicateName(product.name) }, product) as never,\n smart.docs.map((doc) => smartCollectionRulesOf(doc.id, doc.data())),\n )\n tx.create(copyRef, {\n ...fields,\n collectionIds,\n deletedAt: null,\n createdAt: FieldValue.serverTimestamp(),\n updatedAt: FieldValue.serverTimestamp(),\n createdBy: door.uid,\n })\n tx.set(outbox.ref, outbox.data)\n return { status: 200, body: { ok: true, id: newProductId, replayed: false, slug } }\n })\n if (answer.status === 200 && !(answer.body as { replayed?: boolean }).replayed) {\n await settleCache(deps, hostId, outbox.ref, 'product duplicated from the app')\n }\n return res.status(answer.status).json(answer.body)\n } catch (error) {\n console.error('[commerce/products/duplicate]', error)\n return res.status(500).json({ error: 'Could not duplicate product' })\n }\n }\n}\n\n/**\n * `POST /api/commerce/products/delete` (AGL-3841): the products list's Delete\n * for the native apps, the console's write (`deletedAt` on the product, which\n * stops it being purchasable) with the site-wide cache drop, under the save\n * route's gate. Deleting a deleted product answers `already`.\n */\nexport function createProductDeleteHandler(options: ProductsWriteDeps = {}): PluginApiHandler {\n return async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const deps = resolved(options)\n const body = bodyOf(req)\n const { hostId, productId } = body\n if (!validId(hostId) || !validId(productId)) return res.status(400).json({ error: 'Missing site or product' })\n try {\n const door = await gate(req, res, hostId, deps)\n if (!door) return\n const db = deps.firestore()\n const productRef = db.collection('hosts').doc(hostId).collection('products').doc(productId)\n const outbox = outboxEntry(db, hostId)\n const answer = await db.runTransaction(async (tx) => {\n const stored = await tx.get(productRef)\n if (!stored.exists) return { status: 404, body: { error: 'This product no longer exists' } }\n if (stored.get('deletedAt')) return { status: 200, body: { ok: true, already: true } }\n tx.update(productRef, { deletedAt: FieldValue.serverTimestamp() })\n tx.set(outbox.ref, outbox.data)\n return { status: 200, body: { ok: true, already: false } }\n })\n if (answer.status === 200 && !(answer.body as { already?: boolean }).already) {\n await settleCache(deps, hostId, outbox.ref, 'product deleted from the app')\n }\n return res.status(answer.status).json(answer.body)\n } catch (error) {\n console.error('[commerce/products/delete]', error)\n return res.status(500).json({ error: 'Could not delete product' })\n }\n }\n}\n\nexport const productSaveHandler = createProductSaveHandler()\nexport const productStockHandler = createProductStockHandler()\nexport const productDuplicateHandler = createProductDuplicateHandler()\nexport const productDeleteHandler = createProductDeleteHandler()\n"],"names":["createHash","isRefusedIdToken","createResourceUid","hostRoleCanWrite","dropPluginSiteCache","firebaseAdmin","getLockdownVerdict","getOrgForHost","isImpersonationSession","FieldValue","liftLegacyProduct","productCollectionIds","productDuplicateFields","productDuplicateName","productDuplicateSlugBase","productEditWrite","productMembershipInput","productSaveFields","smartCollectionRulesOf","stockAdjustmentWrite","validateProduct","planRefusal","roomRefusal","ROLE_REFUSAL","MAX_BODY_BYTES","STOCK_ADJUST_REASONS","bodyOf","req","raw","body","length","JSON","parse","validId","value","test","gate","res","hostId","deps","host","authorization","String","headers","token","startsWith","slice","status","json","error","decoded","verifyIdToken","staff","firestore","collection","doc","get","exists","uid","org","orgForHost","locked","lockdown","data","request","method","outboxEntry","ref","paths","createdAt","serverTimestamp","attempts","entireHost","settleCache","entry","reason","dropped","dropCache","hostIds","catch","complete","delete","undefined","resolved","app","auth","options","now","Date","createProductSaveHandler","productId","product","Array","isArray","variants","name","trim","door","nowMs","fields","problem","db","hostRef","products","productRef","smartQuery","where","outbox","create","answer","runTransaction","tx","existing","smart","Promise","all","membership","collectionIds","docs","map","id","ok","replayed","early","used","count","room","Number","createdAtMs","deletedAt","updatedAt","createdBy","set","storedTimestamps","console","stored","asked","Object","fromEntries","entries","filter","key","toDate","stockAttemptId","update","digest","createProductStockHandler","variantId","delta","Math","round","locationId","includes","isFinite","ledgerRef","ledger","inventory","some","variant","write","claimProductSlug","base","suffix","candidate","held","limit","empty","createProductDuplicateHandler","newProductId","source","copyRef","already","slug","createProductDeleteHandler","productSaveHandler","productStockHandler","productDuplicateHandler","productDeleteHandler"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/products-write.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createHash } from 'node:crypto'\nimport { isRefusedIdToken } from '@aglyn/tenant-data-admin/server/id-token-refusal'\nimport { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport { hostRoleCanWrite } from '@aglyn/aglyn/app-utils/organizations'\nimport { countLiveDocuments } from '@aglyn/aglyn/app-utils/live-document-count'\nimport { dropPluginSiteCache } from '@aglyn/aglyn/plugin-manager/plugin-site-cache'\nimport { type PluginApiHandler } from '@aglyn/aglyn/server'\nimport { firebaseAdmin, getLockdownVerdict, getOrgForHost, isImpersonationSession } from '@aglyn/tenant-data-admin'\nimport { FieldValue } from 'firebase-admin/firestore'\nimport {\n type EditedProduct,\n liftLegacyProduct,\n productCollectionIds,\n productDuplicateFields,\n productDuplicateName,\n productDuplicateSlugBase,\n productEditWrite,\n productMembershipInput,\n productSaveFields,\n smartCollectionRulesOf,\n stockAdjustmentWrite,\n validateProduct,\n type InventoryAdjustmentReason,\n} from '../model'\nimport { planRefusal, roomRefusal } from './product-drafts'\n\n/*\n * `POST /api/commerce/products/save` and `POST /api/commerce/products/stock`\n * (AGL-3652): the console product editor's save and its Adjust stock dialog,\n * for the native apps.\n *\n * The console makes both writes from the browser, computing derived fields\n * first (search keys, stock verdict, price, image, smart-collection\n * membership). These routes run THAT computation (`model/product-write.ts`,\n * which the console imports too) and make the same writes, under the gate\n * the Firestore rules put on them: a verified member with a write role on the\n * site (`canWriteHostContent`), or staff, while the site, its org and the\n * platform are not frozen (`hostWritesFrozen`). A new product also meets the\n * create path's own door: the plan's `commerce` entitlement and its\n * `productsPerHost` quota, counted in the same transaction as the create.\n */\n\ntype Firestore = FirebaseFirestore.Firestore\n\nexport const ROLE_REFUSAL = 'Editing requires the editor role'\nconst MAX_BODY_BYTES = 256_000\n\n/** The reasons the Adjust stock dialog offers. */\nexport const STOCK_ADJUST_REASONS: readonly InventoryAdjustmentReason[] = ['restock', 'correction', 'damage', 'refund']\n\nexport interface ProductsWriteDeps {\n firestore?: () => Firestore\n verifyIdToken?: (token: string) => Promise<Record<string, unknown> & { uid: string }>\n orgForHost?: (hostId: string) => Promise<{ org: Record<string, unknown> } | null>\n lockdown?: (options: Parameters<typeof getLockdownVerdict>[0]) => Promise<unknown>\n dropCache?: typeof dropPluginSiteCache\n now?: () => number\n}\n\ntype Reply = Parameters<PluginApiHandler>[1]\n\nexport function bodyOf(req: Parameters<PluginApiHandler>[0]): Record<string, unknown> {\n const raw = req.body\n if (typeof raw === 'string') {\n if (raw.length > MAX_BODY_BYTES) return {}\n try {\n return JSON.parse(raw || '{}')\n } catch {\n return {}\n }\n }\n return (raw ?? {}) as Record<string, unknown>\n}\n\nexport const validId = (value: unknown): value is string =>\n typeof value === 'string' && /^[A-Za-z0-9_-]{1,128}$/.test(value)\n\nexport interface Gate {\n uid: string\n staff: boolean\n host: FirebaseFirestore.DocumentSnapshot\n org: Record<string, unknown>\n}\n\n/**\n * Who may write this site's products, as the rules decide it. Answers the\n * caller's reply on a refusal and returns null.\n */\nexport async function gate(req: Parameters<PluginApiHandler>[0], res: Reply, hostId: string, deps: Required<ProductsWriteDeps>): Promise<Gate | null> {\n const authorization = String(req.headers.authorization ?? '')\n const token = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : ''\n if (!token) return void res.status(401).json({ error: 'Unauthenticated' }), null\n let decoded: Record<string, unknown> & { uid: string }\n try {\n decoded = await deps.verifyIdToken(token)\n } catch (error) {\n // Only a refused token is the caller's; an Auth outage is a 500 (AGL-2852).\n if (!isRefusedIdToken(error)) throw error\n return void res.status(401).json({ error: 'Sign in again to continue' }), null\n }\n const staff = decoded['staff'] === true\n if (!staff && decoded['email_verified'] !== true && !isImpersonationSession(decoded as never)) {\n return void res.status(403).json({ error: 'Verify your email address to make changes' }), null\n }\n const host = await deps.firestore().collection('hosts').doc(hostId).get()\n if (!host.exists) return void res.status(404).json({ error: 'Unknown site' }), null\n if (!staff && !hostRoleCanWrite((host.get('memberRoles') ?? {})[decoded.uid])) {\n return void res.status(403).json({ error: ROLE_REFUSAL }), null\n }\n const org = ((await deps.orgForHost(hostId))?.org ?? {}) as Record<string, unknown>\n const locked = await deps.lockdown({ staff, uid: decoded.uid, org: org as never, host: host.data() as never, request: { method: 'POST' } as never })\n if (locked) return void res.status(423).json({ error: 'This site is not accepting changes right now' }), null\n return { uid: decoded.uid, staff, host, org }\n}\n\n/** The site-wide cache drop a product change is owed (AGL-3386): an outbox entry in the write, then the drop. */\nexport function outboxEntry(firestore: Firestore, hostId: string) {\n return {\n ref: firestore.collection('publishOutbox').doc(createResourceUid()),\n data: { hostId, paths: ['/'], createdAt: FieldValue.serverTimestamp(), attempts: 0, entireHost: true },\n }\n}\n\nexport async function settleCache(deps: Required<ProductsWriteDeps>, hostId: string, entry: FirebaseFirestore.DocumentReference, reason: string) {\n const dropped = await deps.dropCache({ hostIds: [hostId], reason }).catch(() => ({ complete: false }))\n if (dropped.complete) await entry.delete().catch(() => undefined)\n}\n\nexport function resolved(deps: ProductsWriteDeps): Required<ProductsWriteDeps> {\n return {\n firestore: deps.firestore ?? (() => firebaseAdmin.app().firestore() as unknown as Firestore),\n verifyIdToken: deps.verifyIdToken ?? ((token) => firebaseAdmin.app().auth().verifyIdToken(token) as never),\n orgForHost: deps.orgForHost ?? ((hostId) => getOrgForHost(hostId) as never),\n lockdown: deps.lockdown ?? ((options) => getLockdownVerdict(options)),\n dropCache: deps.dropCache ?? dropPluginSiteCache,\n now: deps.now ?? (() => Date.now()),\n }\n}\n\n/**\n * Saves a product as the console editor does. `create: true` makes a new\n * product under the client-minted `productId` (a retry finds its own product\n * and answers `replayed`); otherwise it replaces the live product, keeping\n * its live stock holds.\n */\nexport function createProductSaveHandler(options: ProductsWriteDeps = {}): PluginApiHandler {\n return async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const deps = resolved(options)\n const body = bodyOf(req)\n const hostId = body['hostId']\n const productId = body['productId']\n const product = body['product'] as EditedProduct | undefined\n if (!validId(hostId) || !validId(productId) || !product || typeof product !== 'object' || !Array.isArray(product.variants)) {\n return res.status(400).json({ error: 'Missing site, product or its variants' })\n }\n if (typeof product.name !== 'string' || !product.name.trim()) return res.status(400).json({ error: 'Product name is required' })\n try {\n const door = await gate(req, res, hostId, deps)\n if (!door) return\n const nowMs = deps.now()\n const fields = productSaveFields(product, nowMs)\n const problem = validateProduct(fields as never)\n if (problem) return res.status(400).json({ error: problem })\n const db = deps.firestore()\n const hostRef = db.collection('hosts').doc(hostId)\n const products = hostRef.collection('products')\n const productRef = products.doc(productId)\n const smartQuery = hostRef.collection('collections').where('kind', '==', 'catalog').where('mode', '==', 'smart')\n const outbox = outboxEntry(db, hostId)\n const create = body['create'] === true\n const answer = await db.runTransaction(async (tx) => {\n const [existing, smart] = await Promise.all([tx.get(productRef), tx.get(smartQuery)])\n const membership = {\n collectionIds: productCollectionIds(\n productMembershipInput(fields, product) as never,\n smart.docs.map((doc) => smartCollectionRulesOf(doc.id, doc.data())),\n ),\n }\n if (create) {\n if (existing.exists) return { status: 200, body: { ok: true, id: productId, replayed: true } }\n const early = planRefusal(door.org as never)\n if (early) return { status: early.status, body: { error: early.error } }\n const used = await countLiveDocuments(products, (aggregate) => tx.get(aggregate))\n const room = roomRefusal(door.org as never, Number(used) || 0)\n if (room) return { status: room.status, body: { error: room.error } }\n tx.create(productRef, {\n ...fields,\n ...membership,\n createdAtMs: nowMs,\n deletedAt: null,\n createdAt: FieldValue.serverTimestamp(),\n updatedAt: FieldValue.serverTimestamp(),\n createdBy: door.uid,\n })\n } else {\n if (!existing.exists || existing.get('deletedAt')) return { status: 404, body: { error: 'This product was deleted' } }\n tx.set(productRef, {\n ...storedTimestamps(existing.data() ?? {}, product as unknown as Record<string, unknown>),\n ...productEditWrite(fields, existing.get('stockHolds')),\n ...membership,\n updatedAt: FieldValue.serverTimestamp(),\n })\n }\n tx.set(outbox.ref, outbox.data)\n return { status: 200, body: { ok: true, id: productId, replayed: false } }\n })\n if (answer.status === 200 && !(answer.body as { replayed?: boolean }).replayed) {\n await settleCache(deps, hostId, outbox.ref, 'product saved from the app')\n }\n return res.status(answer.status).json(answer.body)\n } catch (error) {\n console.error('[commerce/products/save]', error)\n return res.status(500).json({ error: 'The product could not be saved' })\n }\n }\n}\n\n/**\n * The stored timestamps an edit keeps. The console's replace writes back the\n * Timestamps its seed carried (`createdAt`, a publish time); a client's JSON\n * cannot carry one, so each stored Timestamp field the request does not name\n * is kept as stored.\n */\nexport function storedTimestamps(stored: Record<string, unknown>, asked: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(stored).filter(\n ([key, value]) => !(key in asked) && typeof (value as { toDate?: unknown } | null)?.toDate === 'function',\n ),\n )\n}\n\n/** The ledger row id one attempt owns: the same key from the same member is the same row. */\nexport function stockAttemptId(uid: string, key: string): string {\n return 'app-' + createHash('sha256').update(`${uid}:${key}`).digest('hex').slice(0, 40)\n}\n\n/**\n * Adjusts one variant's stock as the Adjust stock dialog does: the variants\n * and stock fields on the product, and one `inventoryAdjustments` row, in one\n * transaction. The Idempotency-Key names that row, so a retried attempt finds\n * it and moves nothing twice.\n */\nexport function createProductStockHandler(options: ProductsWriteDeps = {}): PluginApiHandler {\n return async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const deps = resolved(options)\n const body = bodyOf(req)\n const hostId = body['hostId']\n const productId = body['productId']\n const variantId = body['variantId']\n const key = String(req.headers['idempotency-key'] ?? '').trim().slice(0, 200)\n const reason = body['reason'] as InventoryAdjustmentReason\n const delta = Math.round(Number(body['delta']))\n const locationId = typeof body['locationId'] === 'string' && body['locationId'] ? body['locationId'] : undefined\n if (!validId(hostId) || !validId(productId) || typeof variantId !== 'string' || !variantId) {\n return res.status(400).json({ error: 'Missing site, product or variant' })\n }\n if (!key) return res.status(400).json({ error: 'Missing Idempotency-Key' })\n if (!STOCK_ADJUST_REASONS.includes(reason)) return res.status(400).json({ error: 'Unknown reason' })\n if (!Number.isFinite(delta) || delta === 0) return res.status(400).json({ error: 'Enter a number of units' })\n try {\n const door = await gate(req, res, hostId, deps)\n if (!door) return\n const db = deps.firestore()\n const hostRef = db.collection('hosts').doc(hostId)\n const productRef = hostRef.collection('products').doc(productId)\n const ledgerRef = hostRef.collection('inventoryAdjustments').doc(stockAttemptId(door.uid, key))\n const outbox = outboxEntry(db, hostId)\n const answer = await db.runTransaction(async (tx) => {\n const [ledger, stored] = await Promise.all([tx.get(ledgerRef), tx.get(productRef)])\n if (ledger.exists) {\n return { status: 200, body: { ok: true, replayed: true, inventory: stored.get('inventory') ?? null } }\n }\n if (!stored.exists || stored.get('deletedAt')) return { status: 404, body: { error: 'This product was deleted' } }\n const product = stored.data() as never as Parameters<typeof stockAdjustmentWrite>[0]\n if (!(product.variants ?? []).some((variant) => variant.id === variantId)) {\n return { status: 404, body: { error: 'That variant is no longer on this product' } }\n }\n const write = stockAdjustmentWrite(product, productId, { variantId, delta, reason, locationId }, deps.now())\n if (!write) return { status: 400, body: { error: 'Enter a number of units' } }\n tx.update(productRef, write.update)\n tx.create(ledgerRef, write.ledger)\n tx.set(outbox.ref, outbox.data)\n return { status: 200, body: { ok: true, replayed: false, inventory: (write.update as { inventory?: unknown }).inventory ?? null } }\n })\n if (answer.status === 200 && !(answer.body as { replayed?: boolean }).replayed) {\n await settleCache(deps, hostId, outbox.ref, 'stock adjusted from the app')\n }\n return res.status(answer.status).json(answer.body)\n } catch (error) {\n console.error('[commerce/products/stock]', error)\n return res.status(500).json({ error: 'Stock could not be adjusted' })\n }\n }\n}\n\n/**\n * The first slug in `base`, `base-2`, `base-3`… no product of the site holds,\n * as the console's slug ledger claims one (`product-slugs.ts`): a second\n * Duplicate of the same product does not mint a second `-copy` (AGL-3321).\n */\nexport async function claimProductSlug(products: FirebaseFirestore.CollectionReference, base: string): Promise<string> {\n for (let suffix = 1; suffix < 1000; suffix += 1) {\n const candidate = suffix < 2 ? base : `${base}-${suffix}`\n const held = await products.where('slug', '==', candidate).limit(1).get()\n if (held.empty) return candidate\n }\n return `${base}-${Date.now()}`\n}\n\n/**\n * `POST /api/commerce/products/duplicate` (AGL-3841): the products list's\n * Duplicate for the native apps. The console builds the copy in the browser\n * (`productDuplicateFields`, its slug ledger, the copy's smart collections)\n * and creates it through the quota-enforcing resources route; this runs the\n * same model over the stored product and creates it under the save route's\n * create door (the plan's commerce entitlement and its product quota, counted\n * in the same transaction). `newProductId` is the client's, so a retry finds\n * its own copy and answers `replayed`.\n */\nexport function createProductDuplicateHandler(options: ProductsWriteDeps = {}): PluginApiHandler {\n return async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const deps = resolved(options)\n const body = bodyOf(req)\n const { hostId, productId, newProductId } = body\n if (!validId(hostId) || !validId(productId) || !validId(newProductId) || productId === newProductId) {\n return res.status(400).json({ error: 'Missing site or product' })\n }\n try {\n const door = await gate(req, res, hostId, deps)\n if (!door) return\n const db = deps.firestore()\n const hostRef = db.collection('hosts').doc(hostId)\n const products = hostRef.collection('products')\n const copyRef = products.doc(newProductId)\n const already = await copyRef.get()\n if (already.exists) return res.status(200).json({ ok: true, id: newProductId, replayed: true })\n const source = await products.doc(productId).get()\n if (!source.exists || source.get('deletedAt')) return res.status(404).json({ error: 'This product was deleted' })\n const product = liftLegacyProduct((source.data() ?? {}) as never)\n const slug = await claimProductSlug(products, productDuplicateSlugBase(product.slug, product.name))\n const nowMs = deps.now()\n const fields = productDuplicateFields(product, slug, nowMs)\n const smartQuery = hostRef.collection('collections').where('kind', '==', 'catalog').where('mode', '==', 'smart')\n const outbox = outboxEntry(db, hostId)\n const answer = await db.runTransaction(async (tx) => {\n const [existing, smart] = await Promise.all([tx.get(copyRef), tx.get(smartQuery)])\n if (existing.exists) return { status: 200, body: { ok: true, id: newProductId, replayed: true } }\n const early = planRefusal(door.org as never)\n if (early) return { status: early.status, body: { error: early.error } }\n const used = await countLiveDocuments(products, (aggregate) => tx.get(aggregate))\n const room = roomRefusal(door.org as never, Number(used) || 0)\n if (room) return { status: room.status, body: { error: room.error } }\n // The COPY's smart collections: its name differs from the source's.\n const collectionIds = productCollectionIds(\n productMembershipInput({ name: productDuplicateName(product.name) }, product) as never,\n smart.docs.map((doc) => smartCollectionRulesOf(doc.id, doc.data())),\n )\n tx.create(copyRef, {\n ...fields,\n collectionIds,\n deletedAt: null,\n createdAt: FieldValue.serverTimestamp(),\n updatedAt: FieldValue.serverTimestamp(),\n createdBy: door.uid,\n })\n tx.set(outbox.ref, outbox.data)\n return { status: 200, body: { ok: true, id: newProductId, replayed: false, slug } }\n })\n if (answer.status === 200 && !(answer.body as { replayed?: boolean }).replayed) {\n await settleCache(deps, hostId, outbox.ref, 'product duplicated from the app')\n }\n return res.status(answer.status).json(answer.body)\n } catch (error) {\n console.error('[commerce/products/duplicate]', error)\n return res.status(500).json({ error: 'Could not duplicate product' })\n }\n }\n}\n\n/**\n * `POST /api/commerce/products/delete` (AGL-3841): the products list's Delete\n * for the native apps, the console's write (`deletedAt` on the product, which\n * stops it being purchasable) with the site-wide cache drop, under the save\n * route's gate. Deleting a deleted product answers `already`.\n */\nexport function createProductDeleteHandler(options: ProductsWriteDeps = {}): PluginApiHandler {\n return async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const deps = resolved(options)\n const body = bodyOf(req)\n const { hostId, productId } = body\n if (!validId(hostId) || !validId(productId)) return res.status(400).json({ error: 'Missing site or product' })\n try {\n const door = await gate(req, res, hostId, deps)\n if (!door) return\n const db = deps.firestore()\n const productRef = db.collection('hosts').doc(hostId).collection('products').doc(productId)\n const outbox = outboxEntry(db, hostId)\n const answer = await db.runTransaction(async (tx) => {\n const stored = await tx.get(productRef)\n if (!stored.exists) return { status: 404, body: { error: 'This product no longer exists' } }\n if (stored.get('deletedAt')) return { status: 200, body: { ok: true, already: true } }\n tx.update(productRef, { deletedAt: FieldValue.serverTimestamp() })\n tx.set(outbox.ref, outbox.data)\n return { status: 200, body: { ok: true, already: false } }\n })\n if (answer.status === 200 && !(answer.body as { already?: boolean }).already) {\n await settleCache(deps, hostId, outbox.ref, 'product deleted from the app')\n }\n return res.status(answer.status).json(answer.body)\n } catch (error) {\n console.error('[commerce/products/delete]', error)\n return res.status(500).json({ error: 'Could not delete product' })\n }\n }\n}\n\nexport const productSaveHandler = createProductSaveHandler()\nexport const productStockHandler = createProductStockHandler()\nexport const productDuplicateHandler = createProductDuplicateHandler()\nexport const productDeleteHandler = createProductDeleteHandler()\n"],"names":["createHash","isRefusedIdToken","createResourceUid","hostRoleCanWrite","countLiveDocuments","dropPluginSiteCache","firebaseAdmin","getLockdownVerdict","getOrgForHost","isImpersonationSession","FieldValue","liftLegacyProduct","productCollectionIds","productDuplicateFields","productDuplicateName","productDuplicateSlugBase","productEditWrite","productMembershipInput","productSaveFields","smartCollectionRulesOf","stockAdjustmentWrite","validateProduct","planRefusal","roomRefusal","ROLE_REFUSAL","MAX_BODY_BYTES","STOCK_ADJUST_REASONS","bodyOf","req","raw","body","length","JSON","parse","validId","value","test","gate","res","hostId","deps","host","authorization","String","headers","token","startsWith","slice","status","json","error","decoded","verifyIdToken","staff","firestore","collection","doc","get","exists","uid","org","orgForHost","locked","lockdown","data","request","method","outboxEntry","ref","paths","createdAt","serverTimestamp","attempts","entireHost","settleCache","entry","reason","dropped","dropCache","hostIds","catch","complete","delete","undefined","resolved","app","auth","options","now","Date","createProductSaveHandler","productId","product","Array","isArray","variants","name","trim","door","nowMs","fields","problem","db","hostRef","products","productRef","smartQuery","where","outbox","create","answer","runTransaction","tx","existing","smart","Promise","all","membership","collectionIds","docs","map","id","ok","replayed","early","used","aggregate","room","Number","createdAtMs","deletedAt","updatedAt","createdBy","set","storedTimestamps","console","stored","asked","Object","fromEntries","entries","filter","key","toDate","stockAttemptId","update","digest","createProductStockHandler","variantId","delta","Math","round","locationId","includes","isFinite","ledgerRef","ledger","inventory","some","variant","write","claimProductSlug","base","suffix","candidate","held","limit","empty","createProductDuplicateHandler","newProductId","source","copyRef","already","slug","createProductDeleteHandler","productSaveHandler","productStockHandler","productDuplicateHandler","productDeleteHandler"],"mappings":"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"}
|
|
@@ -17,6 +17,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
17
17
|
*/ import * as Aglyn from "@aglyn/aglyn/server";
|
|
18
18
|
import { createResourceUid } from "@aglyn/aglyn/app-utils/create-resource-uid";
|
|
19
19
|
import { findUserByUidAcrossPools, firebaseAdmin, getOrgForHost, hostSendingIdentity, meterHostEmail, notifyHostManagers, renderHostEmailWithTokens } from "@aglyn/tenant-data-admin";
|
|
20
|
+
import { hostConsoleUrl } from "@aglyn/tenant-data-admin/server/host-console-link";
|
|
20
21
|
import { isEmailConfigured, sendEmail } from "@aglyn/shared-util-email";
|
|
21
22
|
import * as CommerceModel from "../model/index.js";
|
|
22
23
|
import { RETURN_APPROVED_EVENT, RETURN_DECLINED_EVENT, RETURN_RECEIVED_EVENT, RETURN_REFUNDED_EVENT, RETURN_REQUESTED_EVENT } from "../model/order-events.js";
|
|
@@ -572,7 +573,8 @@ async function sendReturnEmail(hostId, key, to, tokens, fallback) {
|
|
|
572
573
|
'order.number': entry.orderNumber,
|
|
573
574
|
'return.items': items,
|
|
574
575
|
'buyer.email': String((_entry_customerEmail1 = entry.customerEmail) != null ? _entry_customerEmail1 : ''),
|
|
575
|
-
'return.customerNote': String((_entry_customerNote = entry.customerNote) != null ? _entry_customerNote : '')
|
|
576
|
+
'return.customerNote': String((_entry_customerNote = entry.customerNote) != null ? _entry_customerNote : ''),
|
|
577
|
+
'return.url': await hostConsoleUrl(hostId, `/${hostId}/products/returns?return=${encodeURIComponent(returnId)}`)
|
|
576
578
|
}, {
|
|
577
579
|
subject: `Return requested for order ${entry.orderNumber}`,
|
|
578
580
|
text: `${(_entry_customerEmail2 = entry.customerEmail) != null ? _entry_customerEmail2 : 'A buyer'} wants to return items from order ${entry.orderNumber}.\n\n${items}` + (entry.customerNote ? `\n\n"${entry.customerNote}"` : '') + `\n\nApprove or decline it under Products → Returns.`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/returns.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn/server'\nimport { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport type { PluginApiHandler, PluginApiRequest, PluginApiResponse } from '@aglyn/aglyn/server'\nimport {\n findUserByUidAcrossPools,\n firebaseAdmin,\n getOrgForHost,\n hostSendingIdentity,\n meterHostEmail,\n notifyHostManagers,\n renderHostEmailWithTokens,\n} from '@aglyn/tenant-data-admin'\nimport { isEmailConfigured, sendEmail } from '@aglyn/shared-util-email'\nimport * as CommerceModel from '../model'\nimport {\n RETURN_APPROVED_EVENT,\n RETURN_DECLINED_EVENT,\n RETURN_RECEIVED_EVENT,\n RETURN_REFUNDED_EVENT,\n RETURN_REQUESTED_EVENT,\n} from '../model/order-events'\nimport { raiseOrderEvent, stageOrderEvent } from './order-events'\nimport { orderStatusUrl, verifyOrderStatusToken } from './order-status-token'\nimport { readActiveMemberSession } from './membership'\nimport { resolveTrackedRestockLines } from './restock-flag'\nimport { refundHandler } from './refund'\n\n/**\n * Returns (RMA, AGL-3611): the buyer's door, the merchant's door, and the\n * writes behind both. The rules — what is returnable, the window, the state\n * machine, what a refund is worth — are the model's (`commerce-returns.ts`);\n * this is where they are re-asked under the write.\n *\n * EVERY WRITE IS A TRANSACTION that reads the return, the order and, when it\n * opens one, every return already on the order — so two requests for the last\n * unit cannot both be granted, and a stale console cannot approve a return a\n * colleague declined a moment ago.\n *\n * THE MONEY MOVES THROUGH THE ORDER'S REFUND ROUTE, never here. A return's\n * refund calls `refund.ts` with the merchant's own credentials and a key\n * derived from the return, so its gates (an admin of the whole workspace,\n * the over-refund cap, the open-dispute block, Stripe's idempotency) are the\n * ones every refund passes, and asking twice refunds once.\n *\n * STOCK COMES BACK WHEN THE PARCEL DOES. Receiving a return puts the units\n * the merchant chose back on the shelf, at the location they chose, with an\n * inventory adjustment row — the products hub's history shows it beside the\n * sale. A refund then answers the order's restock question with what the\n * return already did, so nobody is asked to restock the same units twice.\n */\n\ntype Firestore = FirebaseFirestore.Firestore\n\nconst hostRefFor = (firestore: Firestore, hostId: string) => firestore.collection('hosts').doc(hostId)\n\nconst isId = (value: string) => Boolean(value) && value.length <= 200 && !/^__.*__$/.test(value) && !value.includes('/')\n\n/** The store's settings document and what the return emails need from the host. */\nasync function readStore(firestore: Firestore, hostId: string) {\n const hostRef = hostRefFor(firestore, hostId)\n const [host, store] = await Promise.all([\n hostRef.get().catch(() => null),\n hostRef.collection('settings').doc('store').get().catch(() => null),\n ])\n const settings = (store?.data() ?? {}) as Record<string, unknown>\n return {\n host: (host?.data() ?? {}) as Record<string, unknown>,\n returnSettings: CommerceModel.readReturnSettings(settings['returns']),\n currency: String(settings['currency'] ?? 'USD').toUpperCase(),\n }\n}\n\nfunction money(cents: number, currency: string): string {\n try {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(cents / 100)\n } catch {\n return `$${(cents / 100).toFixed(2)}`\n }\n}\n\n/** The return as an event carries it. */\nfunction returnEventView(id: string, entry: CommerceModel.HostReturn) {\n return {\n id,\n status: entry.status,\n lines: entry.lines.map((line) => ({ ...line })),\n refundCents: entry.refundCents ?? null,\n restock: entry.restock ? entry.restock.lines.map((line) => ({ ...line })) : null,\n }\n}\n\n/** \"1× House Blend — Arrived damaged\", one per line. */\nfunction returnItemsText(order: CommerceModel.HostOrder, entry: Pick<CommerceModel.HostReturn, 'lines'>): string {\n return entry.lines\n .map(\n (line) =>\n `${line.quantity}× ${order.lineItems?.[line.lineItemId]?.name ?? `line ${line.lineItemId}`} — ${\n CommerceModel.RETURN_REASON_LABELS[line.reason] ?? line.reason\n }`,\n )\n .join('\\n')\n}\n\nexport type OpenReturnOutcome =\n | { outcome: 'created'; returnId: string; entry: CommerceModel.HostReturn; order: CommerceModel.HostOrder }\n | { outcome: 'refused'; message: string }\n | { outcome: 'no_such_order' }\n\n/**\n * Opens a return. A buyer's starts `requested`; a merchant's starts\n * `approved`, since the merchant asking is the approval.\n */\nexport async function openReturn(request: {\n hostId: string\n orderId: string\n lines: ReadonlyArray<{ lineItemId: unknown; quantity: unknown; reason: unknown }>\n note?: string\n by: 'buyer' | 'merchant'\n now?: number\n}): Promise<OpenReturnOutcome> {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = hostRefFor(firestore, request.hostId)\n const orderRef = hostRef.collection('orders').doc(request.orderId)\n const { returnSettings } = await readStore(firestore, request.hostId)\n const now = request.now ?? Date.now()\n const note = String(request.note ?? '').trim().slice(0, CommerceModel.RETURN_NOTE_MAX)\n return firestore.runTransaction(async (transaction): Promise<OpenReturnOutcome> => {\n const orderSnapshot = await transaction.get(orderRef)\n if (!orderSnapshot.exists) return { outcome: 'no_such_order' }\n const existing = await transaction.get(\n hostRef.collection('returns').where('orderId', '==', request.orderId),\n )\n const order = CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never)\n const verdict = CommerceModel.validateReturnRequest({\n order,\n existing: existing.docs.map((entry) => entry.data() as CommerceModel.HostReturn),\n settings: returnSettings,\n lines: request.lines,\n by: request.by,\n now,\n })\n if (!('lines' in verdict)) {\n return { outcome: 'refused', message: CommerceModel.describeReturnRequestProblem(verdict) }\n }\n const status: CommerceModel.ReturnStatus = request.by === 'merchant' ? 'approved' : 'requested'\n const entry: CommerceModel.HostReturn = {\n orderId: request.orderId,\n orderNumber: CommerceModel.returnOrderNumber(order, request.orderId),\n customerEmail: order.customerEmail ?? null,\n customerName: order.customerName ?? null,\n lines: verdict.lines.map((line) => ({\n ...line,\n name: String(order.lineItems?.[line.lineItemId]?.name ?? '').slice(0, 200),\n })),\n status,\n requestedBy: request.by,\n ...(note ? (request.by === 'buyer' ? { customerNote: note } : { merchantNote: note }) : {}),\n timeline: [\n {\n atMs: now,\n event: status,\n detail: `${request.by === 'buyer' ? 'Requested by the buyer' : 'Opened by the store'}: ${CommerceModel.describeReturnLines(order, verdict.lines)}`,\n },\n ],\n createdAtMs: now,\n updatedAtMs: now,\n }\n const returnRef = hostRef.collection('returns').doc(createResourceUid())\n transaction.create(returnRef, entry)\n const orderPatch = {\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'return-requested',\n CommerceModel.describeReturnLines(order, verdict.lines),\n now,\n ),\n }\n transaction.update(orderRef, orderPatch)\n stageOrderEvent(transaction, RETURN_REQUESTED_EVENT, {\n hostId: request.hostId,\n orderId: request.orderId,\n key: `return:${returnRef.id}`,\n order: { ...orderSnapshot.data(), ...orderPatch },\n extra: { return: returnEventView(returnRef.id, entry) },\n })\n // The store opening a return is its approval.\n if (status === 'approved') {\n stageOrderEvent(transaction, RETURN_APPROVED_EVENT, {\n hostId: request.hostId,\n orderId: request.orderId,\n key: `return-approved:${returnRef.id}`,\n order: { ...orderSnapshot.data(), ...orderPatch },\n extra: { return: returnEventView(returnRef.id, entry) },\n })\n }\n return { outcome: 'created', returnId: returnRef.id, entry, order }\n })\n}\n\nexport type ReturnAction = 'approve' | 'decline' | 'close' | 'note' | 'attach-label'\n\nexport type ChangeReturnOutcome =\n | { outcome: 'changed'; entry: CommerceModel.HostReturn; order: CommerceModel.HostOrder | null }\n | { outcome: 'already'; entry: CommerceModel.HostReturn }\n | { outcome: 'refused'; message: string }\n | { outcome: 'no_such_return' }\n\nconst ACTION_TARGET: Partial<Record<ReturnAction, CommerceModel.ReturnStatus>> = {\n approve: 'approved',\n decline: 'declined',\n close: 'closed',\n}\n\n/**\n * Approve, decline, close, a note, or a return label — the writes that move\n * no stock and no money. The transition is re-asked under the write.\n */\nexport async function changeReturn(request: {\n hostId: string\n returnId: string\n action: ReturnAction\n merchantNote?: string\n label?: { carrier: string; trackingNumber: string; labelUrl: string; trackingUrl?: string }\n now?: number\n}): Promise<ChangeReturnOutcome> {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = hostRefFor(firestore, request.hostId)\n const returnRef = hostRef.collection('returns').doc(request.returnId)\n const now = request.now ?? Date.now()\n const note = request.merchantNote === undefined ? undefined : String(request.merchantNote).trim().slice(0, CommerceModel.RETURN_NOTE_MAX)\n return firestore.runTransaction(async (transaction): Promise<ChangeReturnOutcome> => {\n const snapshot = await transaction.get(returnRef)\n if (!snapshot.exists) return { outcome: 'no_such_return' }\n const entry = snapshot.data() as CommerceModel.HostReturn\n const orderSnapshot = await transaction.get(hostRef.collection('orders').doc(entry.orderId))\n const order = orderSnapshot.exists ? CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never) : null\n const target = ACTION_TARGET[request.action]\n let patch: Partial<CommerceModel.HostReturn>\n if (target) {\n if (entry.status === target) return { outcome: 'already', entry }\n if (!CommerceModel.canTransitionReturn(entry.status, target)) {\n return {\n outcome: 'refused',\n message: `A return that is ${CommerceModel.RETURN_STATUS_LABELS[entry.status].toLowerCase()} cannot be ${CommerceModel.RETURN_STATUS_LABELS[target].toLowerCase()}`,\n }\n }\n patch = {\n status: target,\n ...(note !== undefined && note ? { merchantNote: note } : {}),\n timeline: CommerceModel.appendReturnEvent(entry, target, note || undefined, now),\n }\n } else if (request.action === 'attach-label') {\n const label = request.label\n if (!label?.labelUrl || !/^https:\\/\\//i.test(label.labelUrl)) {\n return { outcome: 'refused', message: 'A return label needs an https link' }\n }\n if (!CommerceModel.returnIsOpen(entry) || entry.status === 'refunded') {\n return { outcome: 'refused', message: 'This return is finished; a label can no longer be attached' }\n }\n const carrier = String(label.carrier ?? '').trim().slice(0, 40)\n const trackingNumber = String(label.trackingNumber ?? '').trim().slice(0, 60)\n const trackingUrl =\n (label.trackingUrl && /^https:\\/\\//i.test(label.trackingUrl) ? label.trackingUrl : null) ??\n CommerceModel.trackingUrlFor(carrier, trackingNumber)\n patch = {\n returnLabel: {\n carrier,\n trackingNumber,\n labelUrl: String(label.labelUrl).slice(0, 2048),\n ...(trackingUrl ? { trackingUrl } : {}),\n attachedAtMs: now,\n },\n timeline: CommerceModel.appendReturnEvent(entry, 'label', `${carrier} ${trackingNumber}`.trim() || 'Return label attached', now),\n }\n } else {\n patch = {\n merchantNote: note ?? '',\n timeline: CommerceModel.appendReturnEvent(entry, 'note', note || 'Note cleared', now),\n }\n }\n transaction.update(returnRef, { ...patch, updatedAtMs: now })\n const changed = { ...entry, ...patch, updatedAtMs: now }\n const event = target === 'approved' ? RETURN_APPROVED_EVENT : target === 'declined' ? RETURN_DECLINED_EVENT : null\n if (event && orderSnapshot.exists) {\n stageOrderEvent(transaction, event, {\n hostId: request.hostId,\n orderId: entry.orderId,\n key: `return-${target}:${request.returnId}`,\n order: orderSnapshot.data() ?? {},\n extra: { return: returnEventView(request.returnId, changed) },\n })\n }\n return { outcome: 'changed', entry: changed, order }\n })\n}\n\n/**\n * The parcel arrived: the return is `received`, and the units the merchant\n * chose go back on the shelf, at the location they chose. A unit the sale\n * never took off a tracked count (an untracked variant, a deleted product)\n * has nothing to go back to and is left out, as a cancellation leaves it.\n */\nexport async function receiveReturn(request: {\n hostId: string\n returnId: string\n restock: ReadonlyArray<{ lineItemId: unknown; quantity: unknown }>\n locationId?: string\n now?: number\n}): Promise<ChangeReturnOutcome & { units?: number }> {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = hostRefFor(firestore, request.hostId)\n const returnRef = hostRef.collection('returns').doc(request.returnId)\n const now = request.now ?? Date.now()\n const locationId = String(request.locationId ?? '').trim().slice(0, 100)\n return firestore.runTransaction(async (transaction) => {\n const snapshot = await transaction.get(returnRef)\n if (!snapshot.exists) return { outcome: 'no_such_return' as const }\n const entry = snapshot.data() as CommerceModel.HostReturn\n if (entry.status === 'received' || entry.restock) return { outcome: 'already' as const, entry }\n if (!CommerceModel.canTransitionReturn(entry.status, 'received')) {\n return {\n outcome: 'refused' as const,\n message: `A return that is ${CommerceModel.RETURN_STATUS_LABELS[entry.status].toLowerCase()} cannot be received`,\n }\n }\n // What may go back: at most what the return covers, per line.\n const covered = new Map(entry.lines.map((line) => [line.lineItemId, line.quantity]))\n const wanted = new Map<number, number>()\n for (const line of request.restock) {\n const lineItemId = Number(line?.lineItemId)\n const quantity = Number(line?.quantity)\n if (!covered.has(lineItemId)) {\n return { outcome: 'refused' as const, message: `Line ${lineItemId} is not part of this return` }\n }\n if (!Number.isInteger(quantity) || quantity < 0) {\n return { outcome: 'refused' as const, message: 'Restock quantities must be whole numbers' }\n }\n const total = (wanted.get(lineItemId) ?? 0) + quantity\n if (total > (covered.get(lineItemId) ?? 0)) {\n return { outcome: 'refused' as const, message: `Only ${covered.get(lineItemId)} of line ${lineItemId} came back` }\n }\n if (quantity > 0) wanted.set(lineItemId, total)\n }\n if (locationId && wanted.size > 0) {\n const location = await transaction.get(hostRef.collection('locations').doc(locationId))\n if (!location.exists) return { outcome: 'refused' as const, message: 'That stock location no longer exists' }\n }\n const orderRef = hostRef.collection('orders').doc(entry.orderId)\n const orderSnapshot = await transaction.get(orderRef)\n const order = orderSnapshot.exists ? CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never) : null\n // Every read before any write, as a transaction requires.\n const tracked =\n order && wanted.size > 0\n ? await resolveTrackedRestockLines(hostRef, order, (ref) => transaction.get(ref))\n : { lines: [], products: new Map<string, CommerceModel.HostProduct>() }\n const byProduct = new Map<string, Array<{ variantId: string; quantity: number }>>()\n for (const line of tracked.lines) {\n const quantity = Math.min(line.quantity, wanted.get(line.lineIndex ?? -1) ?? 0)\n if (quantity <= 0) continue\n byProduct.set(line.productId, [...(byProduct.get(line.productId) ?? []), { variantId: line.variantId, quantity }])\n }\n let units = 0\n for (const [productId, lines] of byProduct) {\n const product = tracked.products.get(productId)\n if (!product) continue\n let variants = product.variants\n for (const line of lines) {\n variants = CommerceModel.adjustVariantInventory({ variants }, line.variantId, line.quantity, locationId || undefined)\n }\n transaction.update(hostRef.collection('products').doc(productId), {\n variants,\n ...CommerceModel.productStockFields({ ...product, variants }),\n updatedAtMs: now,\n })\n for (const line of lines) {\n units += line.quantity\n transaction.create(hostRef.collection('inventoryAdjustments').doc(createResourceUid()), {\n productId,\n variantId: line.variantId,\n delta: line.quantity,\n reason: 'restock',\n orderId: entry.orderId,\n ...(locationId ? { locationId } : {}),\n atMs: now,\n } satisfies CommerceModel.InventoryAdjustment)\n }\n }\n const restock: CommerceModel.ReturnRestock = {\n lines: [...wanted.entries()].map(([lineItemId, quantity]) => ({ lineItemId, quantity })),\n ...(locationId ? { locationId } : {}),\n atMs: now,\n }\n const patch = {\n status: 'received' as const,\n restock,\n timeline: CommerceModel.appendReturnEvent(\n entry,\n 'received',\n units > 0 ? `${units} ${units === 1 ? 'unit' : 'units'} back in stock` : 'Nothing restocked',\n now,\n ),\n updatedAtMs: now,\n }\n transaction.update(returnRef, patch)\n const received = { ...entry, ...patch }\n if (order) {\n const orderPatch = {\n timeline: CommerceModel.appendOrderEvent(order, 'return-received', units > 0 ? `${units} restocked` : undefined, now),\n }\n transaction.update(orderRef, orderPatch)\n stageOrderEvent(transaction, RETURN_RECEIVED_EVENT, {\n hostId: request.hostId,\n orderId: entry.orderId,\n key: `return-received:${request.returnId}`,\n order: { ...orderSnapshot.data(), ...orderPatch },\n extra: { return: returnEventView(request.returnId, received) },\n })\n }\n return { outcome: 'changed' as const, entry: received, order, units }\n })\n}\n\n/**\n * Records a refund that went through the order's refund route against the\n * return, and answers the order's restock question with what the return\n * already did, so the merchant is not asked to restock the same units again.\n */\nexport async function markReturnRefunded(request: {\n hostId: string\n returnId: string\n refundCents: number\n uid: string\n now?: number\n}): Promise<ChangeReturnOutcome> {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = hostRefFor(firestore, request.hostId)\n const returnRef = hostRef.collection('returns').doc(request.returnId)\n const now = request.now ?? Date.now()\n return firestore.runTransaction(async (transaction): Promise<ChangeReturnOutcome> => {\n const snapshot = await transaction.get(returnRef)\n if (!snapshot.exists) return { outcome: 'no_such_return' }\n const entry = snapshot.data() as CommerceModel.HostReturn\n if (entry.status === 'refunded' || entry.refundedAtMs) return { outcome: 'already', entry }\n const orderRef = hostRef.collection('orders').doc(entry.orderId)\n const orderSnapshot = await transaction.get(orderRef)\n const order = orderSnapshot.exists ? CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never) : null\n const patch = {\n status: 'refunded' as const,\n refundedAtMs: now,\n refundCents: Math.max(0, Math.round(request.refundCents)),\n timeline: CommerceModel.appendReturnEvent(entry, 'refunded', undefined, now),\n updatedAtMs: now,\n }\n transaction.update(returnRef, patch)\n const check = order?.restockCheck\n if (order && check && !check.resolution && entry.restock) {\n const restocked = entry.restock.lines.some((line) => line.quantity > 0)\n transaction.update(orderRef, {\n restockCheck: {\n ...check,\n resolution: restocked ? 'restocked' : 'dismissed',\n resolvedAtMs: now,\n ...(request.uid ? { resolvedBy: request.uid } : {}),\n } satisfies CommerceModel.OrderRestockCheck,\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'restock-check',\n restocked ? 'answered by the return — restocked' : 'answered by the return — no restock',\n now,\n ),\n })\n }\n return { outcome: 'changed', entry: { ...entry, ...patch }, order }\n })\n}\n\n/** Calls the order's own refund route in-process, with the caller's credentials. */\nasync function callRefundRoute(\n req: PluginApiRequest,\n body: Record<string, unknown>,\n idempotencyKey: string,\n): Promise<{ status: number; body: Record<string, any> }> {\n let status = 200\n let payload: Record<string, any> = {}\n const res = {\n status(code: number) {\n status = code\n return res\n },\n json(value: unknown) {\n payload = (value ?? {}) as Record<string, any>\n return res\n },\n send(value: unknown) {\n payload = { error: String(value ?? '') }\n return res\n },\n setHeader() {\n return res\n },\n end() {\n return res\n },\n } as unknown as PluginApiResponse\n await refundHandler(\n {\n ...req,\n method: 'POST',\n headers: { authorization: String(req.headers.authorization ?? ''), 'idempotency-key': idempotencyKey },\n body,\n } as PluginApiRequest,\n res,\n )\n return { status, body: payload }\n}\n\n// ---------------------------------------------------------------------------\n// Emails\n// ---------------------------------------------------------------------------\n\ntype ReturnEmailKey = 'return-requested' | 'return-approved' | 'return-declined' | 'return-refunded'\n\nasync function sendReturnEmail(\n hostId: string,\n key: ReturnEmailKey,\n to: string,\n tokens: Record<string, string>,\n fallback: { subject: string; text: string },\n): Promise<void> {\n if (!to || !isEmailConfigured()) return\n try {\n const firestore = firebaseAdmin.app().firestore()\n const designed = await renderHostEmailWithTokens(firestore, hostId, key, tokens)\n const org = await getOrgForHost(hostId).catch(() => null)\n await sendEmail({\n to,\n subject: designed?.subject ?? fallback.subject,\n text: designed?.text || fallback.text,\n ...(designed?.html ? { html: designed.html } : {}),\n fromName: Aglyn.resolveBrandingProfile(org?.org as never).fromName,\n sendingIdentity: await hostSendingIdentity(hostId),\n audience: 'tenant',\n context: key,\n // Owed to the recipient by their own order (AGL-3356).\n owedFor: 'order',\n })\n await meterHostEmail(hostId)\n } catch (error) {\n // A return that is recorded is not undone because its email failed.\n console.error(`[returns] ${key} not sent`, hostId, error)\n }\n}\n\n/** Tells the store a buyer asked, in the console and by email to the owner. */\nasync function tellStoreOfRequest(hostId: string, returnId: string, entry: CommerceModel.HostReturn, order: CommerceModel.HostOrder) {\n const items = returnItemsText(order, entry)\n await notifyHostManagers(\n hostId,\n {\n type: 'content.order',\n title: `Return requested for order ${entry.orderNumber}`,\n body: `${entry.customerEmail ?? 'A buyer'} wants to return ${CommerceModel.describeReturnLines(order, entry.lines)} from order ${entry.orderNumber} on {site}.`,\n link: `/${hostId}/products/returns?return=${encodeURIComponent(returnId)}`,\n },\n { skipOwnerEmail: true },\n ).catch(() => undefined)\n const ownerUid = (await getOrgForHost(hostId).catch(() => null))?.org?.ownerUid\n const owner = ownerUid ? (await findUserByUidAcrossPools(ownerUid).catch(() => null))?.record : null\n if (!owner?.email) return\n await sendReturnEmail(\n hostId,\n 'return-requested',\n owner.email,\n {\n 'order.number': entry.orderNumber,\n 'return.items': items,\n 'buyer.email': String(entry.customerEmail ?? ''),\n 'return.customerNote': String(entry.customerNote ?? ''),\n },\n {\n subject: `Return requested for order ${entry.orderNumber}`,\n text:\n `${entry.customerEmail ?? 'A buyer'} wants to return items from order ${entry.orderNumber}.\\n\\n${items}` +\n (entry.customerNote ? `\\n\\n\"${entry.customerNote}\"` : '') +\n `\\n\\nApprove or decline it under Products → Returns.`,\n },\n )\n}\n\n/** Tells the buyer what happened to their return. */\nasync function tellBuyer(\n hostId: string,\n key: Exclude<ReturnEmailKey, 'return-requested'>,\n entry: CommerceModel.HostReturn,\n order: CommerceModel.HostOrder | null,\n): Promise<void> {\n const to = String(entry.customerEmail ?? order?.customerEmail ?? '').trim()\n if (!to || !order) return\n const firestore = firebaseAdmin.app().firestore()\n const store = await readStore(firestore, hostId)\n const statusUrl = orderStatusUrl(store.host as never, hostId, entry.orderId) ?? ''\n const items = returnItemsText(order, entry)\n const label = entry.returnLabel\n ? `Print your return label: ${entry.returnLabel.labelUrl}` +\n (entry.returnLabel.trackingNumber ? ` (${[entry.returnLabel.carrier, entry.returnLabel.trackingNumber].filter(Boolean).join(' ')})` : '')\n : ''\n const refundTotal = money(entry.refundCents ?? 0, store.currency)\n const tokens: Record<string, string> = {\n 'order.number': entry.orderNumber,\n 'return.items': items,\n 'return.note': String(entry.merchantNote ?? ''),\n 'return.label': label,\n 'return.refundTotal': refundTotal,\n 'order.statusUrl': statusUrl,\n }\n const fallback =\n key === 'return-approved'\n ? {\n subject: `Your return for order ${entry.orderNumber} is approved`,\n text: `Your return is approved:\\n\\n${items}` + (entry.merchantNote ? `\\n\\n${entry.merchantNote}` : '') + (label ? `\\n\\n${label}` : ''),\n }\n : key === 'return-declined'\n ? {\n subject: `About your return for order ${entry.orderNumber}`,\n text: `We could not accept the return of:\\n\\n${items}` + (entry.merchantNote ? `\\n\\n${entry.merchantNote}` : ''),\n }\n : {\n subject: `Your refund for order ${entry.orderNumber}`,\n text: `We received your return and refunded ${refundTotal}.\\n\\n${items}`,\n }\n if (statusUrl) fallback.text += `\\n\\nView your order: ${statusUrl}`\n await sendReturnEmail(hostId, key, to, tokens, fallback)\n}\n\n// ---------------------------------------------------------------------------\n// The buyer's door (tenant)\n// ---------------------------------------------------------------------------\n\n/**\n * Whether this request may act for the buyer of this order: the signed-in\n * site member whose email the order carries, or the holder of the order's\n * signed status link. Neither reveals whether the order exists to anyone\n * else — both refusals read the same.\n */\nasync function buyerMayActFor(\n req: PluginApiRequest,\n hostId: string,\n orderId: string,\n token: string,\n order: CommerceModel.HostOrder,\n): Promise<boolean> {\n if (token && verifyOrderStatusToken(hostId, orderId, token)) return true\n const session = await readActiveMemberSession(req, hostId)\n if (session.status !== 'active') return false\n const memberEmail = String(session.member.get('email') ?? '').trim().toLowerCase()\n return Boolean(memberEmail) && memberEmail === String(order.customerEmail ?? '').trim().toLowerCase()\n}\n\n/**\n * `GET /api/commerce/return-request?hostId&orderId&t` — what the buyer may\n * send back and until when, and the returns already open.\n * `POST` with `{ hostId, orderId, t?, lines: [{ lineItemId, quantity, reason }], note? }`\n * opens a return.\n */\nexport const returnRequestHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'GET' && req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const input = (req.method === 'GET' ? req.query : typeof req.body === 'string' ? JSON.parse(req.body) : req.body) ?? {}\n const hostId = String(input.hostId ?? '')\n const orderId = String(input.orderId ?? input.o ?? '')\n const token = String(input.t ?? input.token ?? '').slice(0, 100)\n if (!isId(hostId) || !isId(orderId)) return res.status(400).json({ error: 'Missing hostId or orderId' })\n try {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = hostRefFor(firestore, hostId)\n const orderSnapshot = await hostRef.collection('orders').doc(orderId).get()\n const order = orderSnapshot.exists ? CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never) : null\n if (!order || !(await buyerMayActFor(req, hostId, orderId, token, order))) {\n return res.status(404).json({ error: 'We could not find that order' })\n }\n if (req.method === 'GET') {\n const [{ returnSettings }, existing] = await Promise.all([\n readStore(firestore, hostId),\n hostRef.collection('returns').where('orderId', '==', orderId).get(),\n ])\n const returns = existing.docs.map((entry) => ({ id: entry.id, ...(entry.data() as CommerceModel.HostReturn) }))\n const endsAt = CommerceModel.returnWindowEndsAtMs(order, returnSettings)\n return res.status(200).json({\n enabled: returnSettings.enabled,\n windowEndsAtMs: endsAt,\n windowOpen: endsAt === null || Date.now() <= endsAt,\n lines: CommerceModel.returnableLines(order, returns, returnSettings),\n reasons: CommerceModel.RETURN_REASONS.map((reason) => ({ value: reason, label: CommerceModel.RETURN_REASON_LABELS[reason] })),\n returns: returns.map((entry) => ({\n id: entry.id,\n status: entry.status,\n lines: entry.lines,\n createdAtMs: entry.createdAtMs,\n ...(entry.returnLabel ? { returnLabel: { labelUrl: entry.returnLabel.labelUrl, carrier: entry.returnLabel.carrier, trackingNumber: entry.returnLabel.trackingNumber } } : {}),\n ...(entry.status === 'declined' && entry.merchantNote ? { merchantNote: entry.merchantNote } : {}),\n })),\n })\n }\n const outcome = await openReturn({\n hostId,\n orderId,\n lines: Array.isArray(input.lines) ? (input.lines as unknown[]).slice(0, 100) as never : [],\n note: String(input.note ?? ''),\n by: 'buyer',\n })\n if (outcome.outcome === 'no_such_order') return res.status(404).json({ error: 'We could not find that order' })\n if (outcome.outcome === 'refused') return res.status(409).json({ error: outcome.message })\n await tellStoreOfRequest(hostId, outcome.returnId, outcome.entry, outcome.order)\n return res.status(200).json({ ok: true, returnId: outcome.returnId, status: outcome.entry.status })\n } catch (error) {\n console.error('return request failed', error)\n return res.status(500).json({ error: 'Your return could not be requested. Please try again.' })\n }\n}\n\n// ---------------------------------------------------------------------------\n// The merchant's door (console)\n// ---------------------------------------------------------------------------\n\nconst MERCHANT_ACTIONS = ['create', 'approve', 'decline', 'close', 'note', 'attach-label', 'receive', 'refund'] as const\ntype MerchantAction = (typeof MERCHANT_ACTIONS)[number]\n\n/**\n * `POST /api/commerce/returns` with `{ hostId, action, … }`. Admins and\n * editors run the return; the refund goes through the order's refund route,\n * which asks for an admin of the whole workspace on its own.\n */\nexport const returnsHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const authorization = String(req.headers.authorization ?? '')\n const idToken = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : undefined\n if (!idToken) return res.status(401).json({ error: 'Unauthenticated' })\n const body = (typeof req.body === 'string' ? JSON.parse(req.body) : req.body) ?? {}\n const hostId = String(body.hostId ?? '')\n const action = String(body.action ?? '') as MerchantAction\n const returnId = String(body.returnId ?? '')\n if (!isId(hostId)) return res.status(400).json({ error: 'Missing hostId' })\n if (!MERCHANT_ACTIONS.includes(action)) return res.status(400).json({ error: 'Unknown action' })\n if (action !== 'create' && !isId(returnId)) return res.status(400).json({ error: 'Missing returnId' })\n try {\n const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n const firestore = firebaseAdmin.app().firestore()\n const hostSnapshot = await hostRefFor(firestore, hostId).get()\n if (!hostSnapshot.exists) return res.status(404).json({ error: 'Unknown site' })\n const role = (hostSnapshot.get('memberRoles') ?? {})[decoded.uid]\n if (role !== 'admin' && role !== 'editor') return res.status(403).json({ error: 'Not permitted' })\n\n if (action === 'create') {\n const orderId = String(body.orderId ?? '')\n if (!isId(orderId)) return res.status(400).json({ error: 'Missing orderId' })\n const outcome = await openReturn({\n hostId,\n orderId,\n lines: Array.isArray(body.lines) ? (body.lines as unknown[]).slice(0, 100) as never : [],\n note: String(body.note ?? ''),\n by: 'merchant',\n })\n if (outcome.outcome === 'no_such_order') return res.status(404).json({ error: 'Unknown order' })\n if (outcome.outcome === 'refused') return res.status(409).json({ error: outcome.message })\n if (body.notify !== false) await tellBuyer(hostId, 'return-approved', outcome.entry, outcome.order)\n return res.status(200).json({ ok: true, returnId: outcome.returnId, status: outcome.entry.status })\n }\n\n if (action === 'receive') {\n const outcome = await receiveReturn({\n hostId,\n returnId,\n restock: Array.isArray(body.restock) ? (body.restock as unknown[]).slice(0, 100) as never : [],\n locationId: body.locationId ? String(body.locationId) : undefined,\n })\n if (outcome.outcome === 'no_such_return') return res.status(404).json({ error: 'Unknown return' })\n if (outcome.outcome === 'refused') return res.status(409).json({ error: outcome.message })\n return res.status(200).json({\n ok: true,\n ...(outcome.outcome === 'already' ? { already: true } : { units: outcome.units ?? 0 }),\n status: outcome.entry.status,\n })\n }\n\n if (action === 'refund') {\n const returnSnapshot = await hostRefFor(firestore, hostId).collection('returns').doc(returnId).get()\n if (!returnSnapshot.exists) return res.status(404).json({ error: 'Unknown return' })\n const entry = returnSnapshot.data() as CommerceModel.HostReturn\n if (entry.status === 'refunded' || entry.refundedAtMs) {\n return res.status(200).json({ ok: true, already: true, status: entry.status })\n }\n if (!CommerceModel.canTransitionReturn(entry.status, 'refunded')) {\n return res.status(409).json({ error: `A return that is ${CommerceModel.RETURN_STATUS_LABELS[entry.status].toLowerCase()} cannot be refunded` })\n }\n const orderSnapshot = await hostRefFor(firestore, hostId).collection('orders').doc(entry.orderId).get()\n if (!orderSnapshot.exists) return res.status(404).json({ error: 'The order for this return is gone' })\n const order = CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never)\n const suggested = CommerceModel.returnRefundCents(order, entry.lines)\n const amountCents = body.amountCents == null ? suggested : Math.round(Number(body.amountCents))\n if (!Number.isFinite(amountCents) || amountCents <= 0) {\n return res.status(400).json({ error: 'The refund amount must be above zero' })\n }\n const wholeLines = CommerceModel.returnWholeLineIds(order, entry.lines).filter(\n (index) => !CommerceModel.orderLineRefunded(order, index),\n )\n const namedWorth = CommerceModel.orderLineRefundCents(order, wholeLines)\n // Lines are named only when the amount covers them in full, which is\n // what the refund route requires before it withdraws a line's\n // entitlements; a smaller amount refunds by amount alone.\n const refund = await callRefundRoute(\n req,\n {\n hostId,\n orderId: entry.orderId,\n amountCents,\n ...(wholeLines.length > 0 && amountCents >= namedWorth ? { lineItemIds: wholeLines } : {}),\n },\n // One refund per return: asking again replays rather than pays twice.\n `return:${hostId}:${returnId}`,\n )\n if (refund.status !== 200) {\n return res.status(refund.status).json({ error: refund.body?.error ?? 'Refund failed' })\n }\n const marked = await markReturnRefunded({ hostId, returnId, refundCents: amountCents, uid: decoded.uid })\n if (marked.outcome === 'changed') {\n await raiseOrderEvent(RETURN_REFUNDED_EVENT, {\n hostId,\n orderId: entry.orderId,\n key: `return-refunded:${returnId}`,\n extra: { return: returnEventView(returnId, marked.entry) },\n })\n await tellBuyer(hostId, 'return-refunded', marked.entry, marked.order)\n }\n return res.status(200).json({ ok: true, refundCents: amountCents, status: 'refunded' })\n }\n\n const outcome = await changeReturn({\n hostId,\n returnId,\n action: action as ReturnAction,\n ...(body.merchantNote !== undefined ? { merchantNote: String(body.merchantNote) } : {}),\n ...(action === 'attach-label' ? { label: body.label } : {}),\n })\n if (outcome.outcome === 'no_such_return') return res.status(404).json({ error: 'Unknown return' })\n if (outcome.outcome === 'refused') return res.status(409).json({ error: outcome.message })\n if (outcome.outcome === 'changed' && body.notify !== false) {\n if (action === 'approve') await tellBuyer(hostId, 'return-approved', outcome.entry, outcome.order)\n if (action === 'decline') await tellBuyer(hostId, 'return-declined', outcome.entry, outcome.order)\n // A label attached after the approval reaches the buyer the same way,\n // in the approval email, which carries it.\n if (action === 'attach-label' && outcome.entry.status === 'approved') {\n await tellBuyer(hostId, 'return-approved', outcome.entry, outcome.order)\n }\n }\n return res.status(200).json({\n ok: true,\n ...(outcome.outcome === 'already' ? { already: true } : {}),\n status: outcome.entry.status,\n })\n } catch (error) {\n console.error('returns action failed', action, error)\n // Every write here is a transaction or keyed (the refund), so asking\n // again lands once.\n return res.status(500).json({ error: 'The return could not be updated. Retrying is safe.' })\n }\n}\n"],"names":["Aglyn","createResourceUid","findUserByUidAcrossPools","firebaseAdmin","getOrgForHost","hostSendingIdentity","meterHostEmail","notifyHostManagers","renderHostEmailWithTokens","isEmailConfigured","sendEmail","CommerceModel","RETURN_APPROVED_EVENT","RETURN_DECLINED_EVENT","RETURN_RECEIVED_EVENT","RETURN_REFUNDED_EVENT","RETURN_REQUESTED_EVENT","raiseOrderEvent","stageOrderEvent","orderStatusUrl","verifyOrderStatusToken","readActiveMemberSession","resolveTrackedRestockLines","refundHandler","hostRefFor","firestore","hostId","collection","doc","isId","value","Boolean","length","test","includes","readStore","settings","hostRef","host","store","Promise","all","get","catch","data","returnSettings","readReturnSettings","currency","String","toUpperCase","money","cents","Intl","NumberFormat","style","format","toFixed","returnEventView","id","entry","status","lines","map","line","refundCents","restock","returnItemsText","order","quantity","lineItems","lineItemId","name","RETURN_REASON_LABELS","reason","join","openReturn","request","app","orderRef","orderId","now","Date","note","trim","slice","RETURN_NOTE_MAX","runTransaction","transaction","orderSnapshot","exists","outcome","existing","where","liftLegacyOrder","verdict","validateReturnRequest","docs","by","message","describeReturnRequestProblem","orderNumber","returnOrderNumber","customerEmail","customerName","requestedBy","customerNote","merchantNote","timeline","atMs","event","detail","describeReturnLines","createdAtMs","updatedAtMs","returnRef","create","orderPatch","appendOrderEvent","update","key","extra","return","returnId","ACTION_TARGET","approve","decline","close","changeReturn","undefined","snapshot","target","action","patch","canTransitionReturn","RETURN_STATUS_LABELS","toLowerCase","appendReturnEvent","label","labelUrl","returnIsOpen","carrier","trackingNumber","trackingUrl","trackingUrlFor","returnLabel","attachedAtMs","changed","receiveReturn","locationId","covered","Map","wanted","Number","has","isInteger","total","set","size","location","tracked","ref","products","byProduct","Math","min","lineIndex","productId","variantId","units","product","variants","adjustVariantInventory","productStockFields","delta","entries","received","markReturnRefunded","refundedAtMs","max","round","check","restockCheck","resolution","restocked","some","resolvedAtMs","uid","resolvedBy","callRefundRoute","req","body","idempotencyKey","payload","res","code","json","send","error","setHeader","end","method","headers","authorization","sendReturnEmail","to","tokens","fallback","designed","org","subject","text","html","fromName","resolveBrandingProfile","sendingIdentity","audience","context","owedFor","console","tellStoreOfRequest","items","type","title","link","encodeURIComponent","skipOwnerEmail","ownerUid","owner","record","email","tellBuyer","statusUrl","filter","refundTotal","buyerMayActFor","token","session","memberEmail","member","returnRequestHandler","input","query","JSON","parse","o","t","returns","endsAt","returnWindowEndsAtMs","enabled","windowEndsAtMs","windowOpen","returnableLines","reasons","RETURN_REASONS","Array","isArray","ok","MERCHANT_ACTIONS","returnsHandler","idToken","startsWith","hostSnapshot","decoded","auth","verifyIdToken","role","notify","already","returnSnapshot","suggested","returnRefundCents","amountCents","isFinite","wholeLines","returnWholeLineIds","index","orderLineRefunded","namedWorth","orderLineRefundCents","refund","lineItemIds","marked"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/returns.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn/server'\nimport { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport type { PluginApiHandler, PluginApiRequest, PluginApiResponse } from '@aglyn/aglyn/server'\nimport {\n findUserByUidAcrossPools,\n firebaseAdmin,\n getOrgForHost,\n hostSendingIdentity,\n meterHostEmail,\n notifyHostManagers,\n renderHostEmailWithTokens,\n} from '@aglyn/tenant-data-admin'\nimport { hostConsoleUrl } from '@aglyn/tenant-data-admin/server/host-console-link'\nimport { isEmailConfigured, sendEmail } from '@aglyn/shared-util-email'\nimport * as CommerceModel from '../model'\nimport {\n RETURN_APPROVED_EVENT,\n RETURN_DECLINED_EVENT,\n RETURN_RECEIVED_EVENT,\n RETURN_REFUNDED_EVENT,\n RETURN_REQUESTED_EVENT,\n} from '../model/order-events'\nimport { raiseOrderEvent, stageOrderEvent } from './order-events'\nimport { orderStatusUrl, verifyOrderStatusToken } from './order-status-token'\nimport { readActiveMemberSession } from './membership'\nimport { resolveTrackedRestockLines } from './restock-flag'\nimport { refundHandler } from './refund'\n\n/**\n * Returns (RMA, AGL-3611): the buyer's door, the merchant's door, and the\n * writes behind both. The rules — what is returnable, the window, the state\n * machine, what a refund is worth — are the model's (`commerce-returns.ts`);\n * this is where they are re-asked under the write.\n *\n * EVERY WRITE IS A TRANSACTION that reads the return, the order and, when it\n * opens one, every return already on the order — so two requests for the last\n * unit cannot both be granted, and a stale console cannot approve a return a\n * colleague declined a moment ago.\n *\n * THE MONEY MOVES THROUGH THE ORDER'S REFUND ROUTE, never here. A return's\n * refund calls `refund.ts` with the merchant's own credentials and a key\n * derived from the return, so its gates (an admin of the whole workspace,\n * the over-refund cap, the open-dispute block, Stripe's idempotency) are the\n * ones every refund passes, and asking twice refunds once.\n *\n * STOCK COMES BACK WHEN THE PARCEL DOES. Receiving a return puts the units\n * the merchant chose back on the shelf, at the location they chose, with an\n * inventory adjustment row — the products hub's history shows it beside the\n * sale. A refund then answers the order's restock question with what the\n * return already did, so nobody is asked to restock the same units twice.\n */\n\ntype Firestore = FirebaseFirestore.Firestore\n\nconst hostRefFor = (firestore: Firestore, hostId: string) => firestore.collection('hosts').doc(hostId)\n\nconst isId = (value: string) => Boolean(value) && value.length <= 200 && !/^__.*__$/.test(value) && !value.includes('/')\n\n/** The store's settings document and what the return emails need from the host. */\nasync function readStore(firestore: Firestore, hostId: string) {\n const hostRef = hostRefFor(firestore, hostId)\n const [host, store] = await Promise.all([\n hostRef.get().catch(() => null),\n hostRef.collection('settings').doc('store').get().catch(() => null),\n ])\n const settings = (store?.data() ?? {}) as Record<string, unknown>\n return {\n host: (host?.data() ?? {}) as Record<string, unknown>,\n returnSettings: CommerceModel.readReturnSettings(settings['returns']),\n currency: String(settings['currency'] ?? 'USD').toUpperCase(),\n }\n}\n\nfunction money(cents: number, currency: string): string {\n try {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(cents / 100)\n } catch {\n return `$${(cents / 100).toFixed(2)}`\n }\n}\n\n/** The return as an event carries it. */\nfunction returnEventView(id: string, entry: CommerceModel.HostReturn) {\n return {\n id,\n status: entry.status,\n lines: entry.lines.map((line) => ({ ...line })),\n refundCents: entry.refundCents ?? null,\n restock: entry.restock ? entry.restock.lines.map((line) => ({ ...line })) : null,\n }\n}\n\n/** \"1× House Blend — Arrived damaged\", one per line. */\nfunction returnItemsText(order: CommerceModel.HostOrder, entry: Pick<CommerceModel.HostReturn, 'lines'>): string {\n return entry.lines\n .map(\n (line) =>\n `${line.quantity}× ${order.lineItems?.[line.lineItemId]?.name ?? `line ${line.lineItemId}`} — ${\n CommerceModel.RETURN_REASON_LABELS[line.reason] ?? line.reason\n }`,\n )\n .join('\\n')\n}\n\nexport type OpenReturnOutcome =\n | { outcome: 'created'; returnId: string; entry: CommerceModel.HostReturn; order: CommerceModel.HostOrder }\n | { outcome: 'refused'; message: string }\n | { outcome: 'no_such_order' }\n\n/**\n * Opens a return. A buyer's starts `requested`; a merchant's starts\n * `approved`, since the merchant asking is the approval.\n */\nexport async function openReturn(request: {\n hostId: string\n orderId: string\n lines: ReadonlyArray<{ lineItemId: unknown; quantity: unknown; reason: unknown }>\n note?: string\n by: 'buyer' | 'merchant'\n now?: number\n}): Promise<OpenReturnOutcome> {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = hostRefFor(firestore, request.hostId)\n const orderRef = hostRef.collection('orders').doc(request.orderId)\n const { returnSettings } = await readStore(firestore, request.hostId)\n const now = request.now ?? Date.now()\n const note = String(request.note ?? '').trim().slice(0, CommerceModel.RETURN_NOTE_MAX)\n return firestore.runTransaction(async (transaction): Promise<OpenReturnOutcome> => {\n const orderSnapshot = await transaction.get(orderRef)\n if (!orderSnapshot.exists) return { outcome: 'no_such_order' }\n const existing = await transaction.get(\n hostRef.collection('returns').where('orderId', '==', request.orderId),\n )\n const order = CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never)\n const verdict = CommerceModel.validateReturnRequest({\n order,\n existing: existing.docs.map((entry) => entry.data() as CommerceModel.HostReturn),\n settings: returnSettings,\n lines: request.lines,\n by: request.by,\n now,\n })\n if (!('lines' in verdict)) {\n return { outcome: 'refused', message: CommerceModel.describeReturnRequestProblem(verdict) }\n }\n const status: CommerceModel.ReturnStatus = request.by === 'merchant' ? 'approved' : 'requested'\n const entry: CommerceModel.HostReturn = {\n orderId: request.orderId,\n orderNumber: CommerceModel.returnOrderNumber(order, request.orderId),\n customerEmail: order.customerEmail ?? null,\n customerName: order.customerName ?? null,\n lines: verdict.lines.map((line) => ({\n ...line,\n name: String(order.lineItems?.[line.lineItemId]?.name ?? '').slice(0, 200),\n })),\n status,\n requestedBy: request.by,\n ...(note ? (request.by === 'buyer' ? { customerNote: note } : { merchantNote: note }) : {}),\n timeline: [\n {\n atMs: now,\n event: status,\n detail: `${request.by === 'buyer' ? 'Requested by the buyer' : 'Opened by the store'}: ${CommerceModel.describeReturnLines(order, verdict.lines)}`,\n },\n ],\n createdAtMs: now,\n updatedAtMs: now,\n }\n const returnRef = hostRef.collection('returns').doc(createResourceUid())\n transaction.create(returnRef, entry)\n const orderPatch = {\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'return-requested',\n CommerceModel.describeReturnLines(order, verdict.lines),\n now,\n ),\n }\n transaction.update(orderRef, orderPatch)\n stageOrderEvent(transaction, RETURN_REQUESTED_EVENT, {\n hostId: request.hostId,\n orderId: request.orderId,\n key: `return:${returnRef.id}`,\n order: { ...orderSnapshot.data(), ...orderPatch },\n extra: { return: returnEventView(returnRef.id, entry) },\n })\n // The store opening a return is its approval.\n if (status === 'approved') {\n stageOrderEvent(transaction, RETURN_APPROVED_EVENT, {\n hostId: request.hostId,\n orderId: request.orderId,\n key: `return-approved:${returnRef.id}`,\n order: { ...orderSnapshot.data(), ...orderPatch },\n extra: { return: returnEventView(returnRef.id, entry) },\n })\n }\n return { outcome: 'created', returnId: returnRef.id, entry, order }\n })\n}\n\nexport type ReturnAction = 'approve' | 'decline' | 'close' | 'note' | 'attach-label'\n\nexport type ChangeReturnOutcome =\n | { outcome: 'changed'; entry: CommerceModel.HostReturn; order: CommerceModel.HostOrder | null }\n | { outcome: 'already'; entry: CommerceModel.HostReturn }\n | { outcome: 'refused'; message: string }\n | { outcome: 'no_such_return' }\n\nconst ACTION_TARGET: Partial<Record<ReturnAction, CommerceModel.ReturnStatus>> = {\n approve: 'approved',\n decline: 'declined',\n close: 'closed',\n}\n\n/**\n * Approve, decline, close, a note, or a return label — the writes that move\n * no stock and no money. The transition is re-asked under the write.\n */\nexport async function changeReturn(request: {\n hostId: string\n returnId: string\n action: ReturnAction\n merchantNote?: string\n label?: { carrier: string; trackingNumber: string; labelUrl: string; trackingUrl?: string }\n now?: number\n}): Promise<ChangeReturnOutcome> {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = hostRefFor(firestore, request.hostId)\n const returnRef = hostRef.collection('returns').doc(request.returnId)\n const now = request.now ?? Date.now()\n const note = request.merchantNote === undefined ? undefined : String(request.merchantNote).trim().slice(0, CommerceModel.RETURN_NOTE_MAX)\n return firestore.runTransaction(async (transaction): Promise<ChangeReturnOutcome> => {\n const snapshot = await transaction.get(returnRef)\n if (!snapshot.exists) return { outcome: 'no_such_return' }\n const entry = snapshot.data() as CommerceModel.HostReturn\n const orderSnapshot = await transaction.get(hostRef.collection('orders').doc(entry.orderId))\n const order = orderSnapshot.exists ? CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never) : null\n const target = ACTION_TARGET[request.action]\n let patch: Partial<CommerceModel.HostReturn>\n if (target) {\n if (entry.status === target) return { outcome: 'already', entry }\n if (!CommerceModel.canTransitionReturn(entry.status, target)) {\n return {\n outcome: 'refused',\n message: `A return that is ${CommerceModel.RETURN_STATUS_LABELS[entry.status].toLowerCase()} cannot be ${CommerceModel.RETURN_STATUS_LABELS[target].toLowerCase()}`,\n }\n }\n patch = {\n status: target,\n ...(note !== undefined && note ? { merchantNote: note } : {}),\n timeline: CommerceModel.appendReturnEvent(entry, target, note || undefined, now),\n }\n } else if (request.action === 'attach-label') {\n const label = request.label\n if (!label?.labelUrl || !/^https:\\/\\//i.test(label.labelUrl)) {\n return { outcome: 'refused', message: 'A return label needs an https link' }\n }\n if (!CommerceModel.returnIsOpen(entry) || entry.status === 'refunded') {\n return { outcome: 'refused', message: 'This return is finished; a label can no longer be attached' }\n }\n const carrier = String(label.carrier ?? '').trim().slice(0, 40)\n const trackingNumber = String(label.trackingNumber ?? '').trim().slice(0, 60)\n const trackingUrl =\n (label.trackingUrl && /^https:\\/\\//i.test(label.trackingUrl) ? label.trackingUrl : null) ??\n CommerceModel.trackingUrlFor(carrier, trackingNumber)\n patch = {\n returnLabel: {\n carrier,\n trackingNumber,\n labelUrl: String(label.labelUrl).slice(0, 2048),\n ...(trackingUrl ? { trackingUrl } : {}),\n attachedAtMs: now,\n },\n timeline: CommerceModel.appendReturnEvent(entry, 'label', `${carrier} ${trackingNumber}`.trim() || 'Return label attached', now),\n }\n } else {\n patch = {\n merchantNote: note ?? '',\n timeline: CommerceModel.appendReturnEvent(entry, 'note', note || 'Note cleared', now),\n }\n }\n transaction.update(returnRef, { ...patch, updatedAtMs: now })\n const changed = { ...entry, ...patch, updatedAtMs: now }\n const event = target === 'approved' ? RETURN_APPROVED_EVENT : target === 'declined' ? RETURN_DECLINED_EVENT : null\n if (event && orderSnapshot.exists) {\n stageOrderEvent(transaction, event, {\n hostId: request.hostId,\n orderId: entry.orderId,\n key: `return-${target}:${request.returnId}`,\n order: orderSnapshot.data() ?? {},\n extra: { return: returnEventView(request.returnId, changed) },\n })\n }\n return { outcome: 'changed', entry: changed, order }\n })\n}\n\n/**\n * The parcel arrived: the return is `received`, and the units the merchant\n * chose go back on the shelf, at the location they chose. A unit the sale\n * never took off a tracked count (an untracked variant, a deleted product)\n * has nothing to go back to and is left out, as a cancellation leaves it.\n */\nexport async function receiveReturn(request: {\n hostId: string\n returnId: string\n restock: ReadonlyArray<{ lineItemId: unknown; quantity: unknown }>\n locationId?: string\n now?: number\n}): Promise<ChangeReturnOutcome & { units?: number }> {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = hostRefFor(firestore, request.hostId)\n const returnRef = hostRef.collection('returns').doc(request.returnId)\n const now = request.now ?? Date.now()\n const locationId = String(request.locationId ?? '').trim().slice(0, 100)\n return firestore.runTransaction(async (transaction) => {\n const snapshot = await transaction.get(returnRef)\n if (!snapshot.exists) return { outcome: 'no_such_return' as const }\n const entry = snapshot.data() as CommerceModel.HostReturn\n if (entry.status === 'received' || entry.restock) return { outcome: 'already' as const, entry }\n if (!CommerceModel.canTransitionReturn(entry.status, 'received')) {\n return {\n outcome: 'refused' as const,\n message: `A return that is ${CommerceModel.RETURN_STATUS_LABELS[entry.status].toLowerCase()} cannot be received`,\n }\n }\n // What may go back: at most what the return covers, per line.\n const covered = new Map(entry.lines.map((line) => [line.lineItemId, line.quantity]))\n const wanted = new Map<number, number>()\n for (const line of request.restock) {\n const lineItemId = Number(line?.lineItemId)\n const quantity = Number(line?.quantity)\n if (!covered.has(lineItemId)) {\n return { outcome: 'refused' as const, message: `Line ${lineItemId} is not part of this return` }\n }\n if (!Number.isInteger(quantity) || quantity < 0) {\n return { outcome: 'refused' as const, message: 'Restock quantities must be whole numbers' }\n }\n const total = (wanted.get(lineItemId) ?? 0) + quantity\n if (total > (covered.get(lineItemId) ?? 0)) {\n return { outcome: 'refused' as const, message: `Only ${covered.get(lineItemId)} of line ${lineItemId} came back` }\n }\n if (quantity > 0) wanted.set(lineItemId, total)\n }\n if (locationId && wanted.size > 0) {\n const location = await transaction.get(hostRef.collection('locations').doc(locationId))\n if (!location.exists) return { outcome: 'refused' as const, message: 'That stock location no longer exists' }\n }\n const orderRef = hostRef.collection('orders').doc(entry.orderId)\n const orderSnapshot = await transaction.get(orderRef)\n const order = orderSnapshot.exists ? CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never) : null\n // Every read before any write, as a transaction requires.\n const tracked =\n order && wanted.size > 0\n ? await resolveTrackedRestockLines(hostRef, order, (ref) => transaction.get(ref))\n : { lines: [], products: new Map<string, CommerceModel.HostProduct>() }\n const byProduct = new Map<string, Array<{ variantId: string; quantity: number }>>()\n for (const line of tracked.lines) {\n const quantity = Math.min(line.quantity, wanted.get(line.lineIndex ?? -1) ?? 0)\n if (quantity <= 0) continue\n byProduct.set(line.productId, [...(byProduct.get(line.productId) ?? []), { variantId: line.variantId, quantity }])\n }\n let units = 0\n for (const [productId, lines] of byProduct) {\n const product = tracked.products.get(productId)\n if (!product) continue\n let variants = product.variants\n for (const line of lines) {\n variants = CommerceModel.adjustVariantInventory({ variants }, line.variantId, line.quantity, locationId || undefined)\n }\n transaction.update(hostRef.collection('products').doc(productId), {\n variants,\n ...CommerceModel.productStockFields({ ...product, variants }),\n updatedAtMs: now,\n })\n for (const line of lines) {\n units += line.quantity\n transaction.create(hostRef.collection('inventoryAdjustments').doc(createResourceUid()), {\n productId,\n variantId: line.variantId,\n delta: line.quantity,\n reason: 'restock',\n orderId: entry.orderId,\n ...(locationId ? { locationId } : {}),\n atMs: now,\n } satisfies CommerceModel.InventoryAdjustment)\n }\n }\n const restock: CommerceModel.ReturnRestock = {\n lines: [...wanted.entries()].map(([lineItemId, quantity]) => ({ lineItemId, quantity })),\n ...(locationId ? { locationId } : {}),\n atMs: now,\n }\n const patch = {\n status: 'received' as const,\n restock,\n timeline: CommerceModel.appendReturnEvent(\n entry,\n 'received',\n units > 0 ? `${units} ${units === 1 ? 'unit' : 'units'} back in stock` : 'Nothing restocked',\n now,\n ),\n updatedAtMs: now,\n }\n transaction.update(returnRef, patch)\n const received = { ...entry, ...patch }\n if (order) {\n const orderPatch = {\n timeline: CommerceModel.appendOrderEvent(order, 'return-received', units > 0 ? `${units} restocked` : undefined, now),\n }\n transaction.update(orderRef, orderPatch)\n stageOrderEvent(transaction, RETURN_RECEIVED_EVENT, {\n hostId: request.hostId,\n orderId: entry.orderId,\n key: `return-received:${request.returnId}`,\n order: { ...orderSnapshot.data(), ...orderPatch },\n extra: { return: returnEventView(request.returnId, received) },\n })\n }\n return { outcome: 'changed' as const, entry: received, order, units }\n })\n}\n\n/**\n * Records a refund that went through the order's refund route against the\n * return, and answers the order's restock question with what the return\n * already did, so the merchant is not asked to restock the same units again.\n */\nexport async function markReturnRefunded(request: {\n hostId: string\n returnId: string\n refundCents: number\n uid: string\n now?: number\n}): Promise<ChangeReturnOutcome> {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = hostRefFor(firestore, request.hostId)\n const returnRef = hostRef.collection('returns').doc(request.returnId)\n const now = request.now ?? Date.now()\n return firestore.runTransaction(async (transaction): Promise<ChangeReturnOutcome> => {\n const snapshot = await transaction.get(returnRef)\n if (!snapshot.exists) return { outcome: 'no_such_return' }\n const entry = snapshot.data() as CommerceModel.HostReturn\n if (entry.status === 'refunded' || entry.refundedAtMs) return { outcome: 'already', entry }\n const orderRef = hostRef.collection('orders').doc(entry.orderId)\n const orderSnapshot = await transaction.get(orderRef)\n const order = orderSnapshot.exists ? CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never) : null\n const patch = {\n status: 'refunded' as const,\n refundedAtMs: now,\n refundCents: Math.max(0, Math.round(request.refundCents)),\n timeline: CommerceModel.appendReturnEvent(entry, 'refunded', undefined, now),\n updatedAtMs: now,\n }\n transaction.update(returnRef, patch)\n const check = order?.restockCheck\n if (order && check && !check.resolution && entry.restock) {\n const restocked = entry.restock.lines.some((line) => line.quantity > 0)\n transaction.update(orderRef, {\n restockCheck: {\n ...check,\n resolution: restocked ? 'restocked' : 'dismissed',\n resolvedAtMs: now,\n ...(request.uid ? { resolvedBy: request.uid } : {}),\n } satisfies CommerceModel.OrderRestockCheck,\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'restock-check',\n restocked ? 'answered by the return — restocked' : 'answered by the return — no restock',\n now,\n ),\n })\n }\n return { outcome: 'changed', entry: { ...entry, ...patch }, order }\n })\n}\n\n/** Calls the order's own refund route in-process, with the caller's credentials. */\nasync function callRefundRoute(\n req: PluginApiRequest,\n body: Record<string, unknown>,\n idempotencyKey: string,\n): Promise<{ status: number; body: Record<string, any> }> {\n let status = 200\n let payload: Record<string, any> = {}\n const res = {\n status(code: number) {\n status = code\n return res\n },\n json(value: unknown) {\n payload = (value ?? {}) as Record<string, any>\n return res\n },\n send(value: unknown) {\n payload = { error: String(value ?? '') }\n return res\n },\n setHeader() {\n return res\n },\n end() {\n return res\n },\n } as unknown as PluginApiResponse\n await refundHandler(\n {\n ...req,\n method: 'POST',\n headers: { authorization: String(req.headers.authorization ?? ''), 'idempotency-key': idempotencyKey },\n body,\n } as PluginApiRequest,\n res,\n )\n return { status, body: payload }\n}\n\n// ---------------------------------------------------------------------------\n// Emails\n// ---------------------------------------------------------------------------\n\ntype ReturnEmailKey = 'return-requested' | 'return-approved' | 'return-declined' | 'return-refunded'\n\nasync function sendReturnEmail(\n hostId: string,\n key: ReturnEmailKey,\n to: string,\n tokens: Record<string, string>,\n fallback: { subject: string; text: string },\n): Promise<void> {\n if (!to || !isEmailConfigured()) return\n try {\n const firestore = firebaseAdmin.app().firestore()\n const designed = await renderHostEmailWithTokens(firestore, hostId, key, tokens)\n const org = await getOrgForHost(hostId).catch(() => null)\n await sendEmail({\n to,\n subject: designed?.subject ?? fallback.subject,\n text: designed?.text || fallback.text,\n ...(designed?.html ? { html: designed.html } : {}),\n fromName: Aglyn.resolveBrandingProfile(org?.org as never).fromName,\n sendingIdentity: await hostSendingIdentity(hostId),\n audience: 'tenant',\n context: key,\n // Owed to the recipient by their own order (AGL-3356).\n owedFor: 'order',\n })\n await meterHostEmail(hostId)\n } catch (error) {\n // A return that is recorded is not undone because its email failed.\n console.error(`[returns] ${key} not sent`, hostId, error)\n }\n}\n\n/** Tells the store a buyer asked, in the console and by email to the owner. */\nasync function tellStoreOfRequest(hostId: string, returnId: string, entry: CommerceModel.HostReturn, order: CommerceModel.HostOrder) {\n const items = returnItemsText(order, entry)\n await notifyHostManagers(\n hostId,\n {\n type: 'content.order',\n title: `Return requested for order ${entry.orderNumber}`,\n body: `${entry.customerEmail ?? 'A buyer'} wants to return ${CommerceModel.describeReturnLines(order, entry.lines)} from order ${entry.orderNumber} on {site}.`,\n link: `/${hostId}/products/returns?return=${encodeURIComponent(returnId)}`,\n },\n { skipOwnerEmail: true },\n ).catch(() => undefined)\n const ownerUid = (await getOrgForHost(hostId).catch(() => null))?.org?.ownerUid\n const owner = ownerUid ? (await findUserByUidAcrossPools(ownerUid).catch(() => null))?.record : null\n if (!owner?.email) return\n await sendReturnEmail(\n hostId,\n 'return-requested',\n owner.email,\n {\n 'order.number': entry.orderNumber,\n 'return.items': items,\n 'buyer.email': String(entry.customerEmail ?? ''),\n 'return.customerNote': String(entry.customerNote ?? ''),\n 'return.url': await hostConsoleUrl(\n hostId,\n `/${hostId}/products/returns?return=${encodeURIComponent(returnId)}`,\n ),\n },\n {\n subject: `Return requested for order ${entry.orderNumber}`,\n text:\n `${entry.customerEmail ?? 'A buyer'} wants to return items from order ${entry.orderNumber}.\\n\\n${items}` +\n (entry.customerNote ? `\\n\\n\"${entry.customerNote}\"` : '') +\n `\\n\\nApprove or decline it under Products → Returns.`,\n },\n )\n}\n\n/** Tells the buyer what happened to their return. */\nasync function tellBuyer(\n hostId: string,\n key: Exclude<ReturnEmailKey, 'return-requested'>,\n entry: CommerceModel.HostReturn,\n order: CommerceModel.HostOrder | null,\n): Promise<void> {\n const to = String(entry.customerEmail ?? order?.customerEmail ?? '').trim()\n if (!to || !order) return\n const firestore = firebaseAdmin.app().firestore()\n const store = await readStore(firestore, hostId)\n const statusUrl = orderStatusUrl(store.host as never, hostId, entry.orderId) ?? ''\n const items = returnItemsText(order, entry)\n const label = entry.returnLabel\n ? `Print your return label: ${entry.returnLabel.labelUrl}` +\n (entry.returnLabel.trackingNumber ? ` (${[entry.returnLabel.carrier, entry.returnLabel.trackingNumber].filter(Boolean).join(' ')})` : '')\n : ''\n const refundTotal = money(entry.refundCents ?? 0, store.currency)\n const tokens: Record<string, string> = {\n 'order.number': entry.orderNumber,\n 'return.items': items,\n 'return.note': String(entry.merchantNote ?? ''),\n 'return.label': label,\n 'return.refundTotal': refundTotal,\n 'order.statusUrl': statusUrl,\n }\n const fallback =\n key === 'return-approved'\n ? {\n subject: `Your return for order ${entry.orderNumber} is approved`,\n text: `Your return is approved:\\n\\n${items}` + (entry.merchantNote ? `\\n\\n${entry.merchantNote}` : '') + (label ? `\\n\\n${label}` : ''),\n }\n : key === 'return-declined'\n ? {\n subject: `About your return for order ${entry.orderNumber}`,\n text: `We could not accept the return of:\\n\\n${items}` + (entry.merchantNote ? `\\n\\n${entry.merchantNote}` : ''),\n }\n : {\n subject: `Your refund for order ${entry.orderNumber}`,\n text: `We received your return and refunded ${refundTotal}.\\n\\n${items}`,\n }\n if (statusUrl) fallback.text += `\\n\\nView your order: ${statusUrl}`\n await sendReturnEmail(hostId, key, to, tokens, fallback)\n}\n\n// ---------------------------------------------------------------------------\n// The buyer's door (tenant)\n// ---------------------------------------------------------------------------\n\n/**\n * Whether this request may act for the buyer of this order: the signed-in\n * site member whose email the order carries, or the holder of the order's\n * signed status link. Neither reveals whether the order exists to anyone\n * else — both refusals read the same.\n */\nasync function buyerMayActFor(\n req: PluginApiRequest,\n hostId: string,\n orderId: string,\n token: string,\n order: CommerceModel.HostOrder,\n): Promise<boolean> {\n if (token && verifyOrderStatusToken(hostId, orderId, token)) return true\n const session = await readActiveMemberSession(req, hostId)\n if (session.status !== 'active') return false\n const memberEmail = String(session.member.get('email') ?? '').trim().toLowerCase()\n return Boolean(memberEmail) && memberEmail === String(order.customerEmail ?? '').trim().toLowerCase()\n}\n\n/**\n * `GET /api/commerce/return-request?hostId&orderId&t` — what the buyer may\n * send back and until when, and the returns already open.\n * `POST` with `{ hostId, orderId, t?, lines: [{ lineItemId, quantity, reason }], note? }`\n * opens a return.\n */\nexport const returnRequestHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'GET' && req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const input = (req.method === 'GET' ? req.query : typeof req.body === 'string' ? JSON.parse(req.body) : req.body) ?? {}\n const hostId = String(input.hostId ?? '')\n const orderId = String(input.orderId ?? input.o ?? '')\n const token = String(input.t ?? input.token ?? '').slice(0, 100)\n if (!isId(hostId) || !isId(orderId)) return res.status(400).json({ error: 'Missing hostId or orderId' })\n try {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = hostRefFor(firestore, hostId)\n const orderSnapshot = await hostRef.collection('orders').doc(orderId).get()\n const order = orderSnapshot.exists ? CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never) : null\n if (!order || !(await buyerMayActFor(req, hostId, orderId, token, order))) {\n return res.status(404).json({ error: 'We could not find that order' })\n }\n if (req.method === 'GET') {\n const [{ returnSettings }, existing] = await Promise.all([\n readStore(firestore, hostId),\n hostRef.collection('returns').where('orderId', '==', orderId).get(),\n ])\n const returns = existing.docs.map((entry) => ({ id: entry.id, ...(entry.data() as CommerceModel.HostReturn) }))\n const endsAt = CommerceModel.returnWindowEndsAtMs(order, returnSettings)\n return res.status(200).json({\n enabled: returnSettings.enabled,\n windowEndsAtMs: endsAt,\n windowOpen: endsAt === null || Date.now() <= endsAt,\n lines: CommerceModel.returnableLines(order, returns, returnSettings),\n reasons: CommerceModel.RETURN_REASONS.map((reason) => ({ value: reason, label: CommerceModel.RETURN_REASON_LABELS[reason] })),\n returns: returns.map((entry) => ({\n id: entry.id,\n status: entry.status,\n lines: entry.lines,\n createdAtMs: entry.createdAtMs,\n ...(entry.returnLabel ? { returnLabel: { labelUrl: entry.returnLabel.labelUrl, carrier: entry.returnLabel.carrier, trackingNumber: entry.returnLabel.trackingNumber } } : {}),\n ...(entry.status === 'declined' && entry.merchantNote ? { merchantNote: entry.merchantNote } : {}),\n })),\n })\n }\n const outcome = await openReturn({\n hostId,\n orderId,\n lines: Array.isArray(input.lines) ? (input.lines as unknown[]).slice(0, 100) as never : [],\n note: String(input.note ?? ''),\n by: 'buyer',\n })\n if (outcome.outcome === 'no_such_order') return res.status(404).json({ error: 'We could not find that order' })\n if (outcome.outcome === 'refused') return res.status(409).json({ error: outcome.message })\n await tellStoreOfRequest(hostId, outcome.returnId, outcome.entry, outcome.order)\n return res.status(200).json({ ok: true, returnId: outcome.returnId, status: outcome.entry.status })\n } catch (error) {\n console.error('return request failed', error)\n return res.status(500).json({ error: 'Your return could not be requested. Please try again.' })\n }\n}\n\n// ---------------------------------------------------------------------------\n// The merchant's door (console)\n// ---------------------------------------------------------------------------\n\nconst MERCHANT_ACTIONS = ['create', 'approve', 'decline', 'close', 'note', 'attach-label', 'receive', 'refund'] as const\ntype MerchantAction = (typeof MERCHANT_ACTIONS)[number]\n\n/**\n * `POST /api/commerce/returns` with `{ hostId, action, … }`. Admins and\n * editors run the return; the refund goes through the order's refund route,\n * which asks for an admin of the whole workspace on its own.\n */\nexport const returnsHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const authorization = String(req.headers.authorization ?? '')\n const idToken = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : undefined\n if (!idToken) return res.status(401).json({ error: 'Unauthenticated' })\n const body = (typeof req.body === 'string' ? JSON.parse(req.body) : req.body) ?? {}\n const hostId = String(body.hostId ?? '')\n const action = String(body.action ?? '') as MerchantAction\n const returnId = String(body.returnId ?? '')\n if (!isId(hostId)) return res.status(400).json({ error: 'Missing hostId' })\n if (!MERCHANT_ACTIONS.includes(action)) return res.status(400).json({ error: 'Unknown action' })\n if (action !== 'create' && !isId(returnId)) return res.status(400).json({ error: 'Missing returnId' })\n try {\n const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n const firestore = firebaseAdmin.app().firestore()\n const hostSnapshot = await hostRefFor(firestore, hostId).get()\n if (!hostSnapshot.exists) return res.status(404).json({ error: 'Unknown site' })\n const role = (hostSnapshot.get('memberRoles') ?? {})[decoded.uid]\n if (role !== 'admin' && role !== 'editor') return res.status(403).json({ error: 'Not permitted' })\n\n if (action === 'create') {\n const orderId = String(body.orderId ?? '')\n if (!isId(orderId)) return res.status(400).json({ error: 'Missing orderId' })\n const outcome = await openReturn({\n hostId,\n orderId,\n lines: Array.isArray(body.lines) ? (body.lines as unknown[]).slice(0, 100) as never : [],\n note: String(body.note ?? ''),\n by: 'merchant',\n })\n if (outcome.outcome === 'no_such_order') return res.status(404).json({ error: 'Unknown order' })\n if (outcome.outcome === 'refused') return res.status(409).json({ error: outcome.message })\n if (body.notify !== false) await tellBuyer(hostId, 'return-approved', outcome.entry, outcome.order)\n return res.status(200).json({ ok: true, returnId: outcome.returnId, status: outcome.entry.status })\n }\n\n if (action === 'receive') {\n const outcome = await receiveReturn({\n hostId,\n returnId,\n restock: Array.isArray(body.restock) ? (body.restock as unknown[]).slice(0, 100) as never : [],\n locationId: body.locationId ? String(body.locationId) : undefined,\n })\n if (outcome.outcome === 'no_such_return') return res.status(404).json({ error: 'Unknown return' })\n if (outcome.outcome === 'refused') return res.status(409).json({ error: outcome.message })\n return res.status(200).json({\n ok: true,\n ...(outcome.outcome === 'already' ? { already: true } : { units: outcome.units ?? 0 }),\n status: outcome.entry.status,\n })\n }\n\n if (action === 'refund') {\n const returnSnapshot = await hostRefFor(firestore, hostId).collection('returns').doc(returnId).get()\n if (!returnSnapshot.exists) return res.status(404).json({ error: 'Unknown return' })\n const entry = returnSnapshot.data() as CommerceModel.HostReturn\n if (entry.status === 'refunded' || entry.refundedAtMs) {\n return res.status(200).json({ ok: true, already: true, status: entry.status })\n }\n if (!CommerceModel.canTransitionReturn(entry.status, 'refunded')) {\n return res.status(409).json({ error: `A return that is ${CommerceModel.RETURN_STATUS_LABELS[entry.status].toLowerCase()} cannot be refunded` })\n }\n const orderSnapshot = await hostRefFor(firestore, hostId).collection('orders').doc(entry.orderId).get()\n if (!orderSnapshot.exists) return res.status(404).json({ error: 'The order for this return is gone' })\n const order = CommerceModel.liftLegacyOrder((orderSnapshot.data() ?? {}) as never)\n const suggested = CommerceModel.returnRefundCents(order, entry.lines)\n const amountCents = body.amountCents == null ? suggested : Math.round(Number(body.amountCents))\n if (!Number.isFinite(amountCents) || amountCents <= 0) {\n return res.status(400).json({ error: 'The refund amount must be above zero' })\n }\n const wholeLines = CommerceModel.returnWholeLineIds(order, entry.lines).filter(\n (index) => !CommerceModel.orderLineRefunded(order, index),\n )\n const namedWorth = CommerceModel.orderLineRefundCents(order, wholeLines)\n // Lines are named only when the amount covers them in full, which is\n // what the refund route requires before it withdraws a line's\n // entitlements; a smaller amount refunds by amount alone.\n const refund = await callRefundRoute(\n req,\n {\n hostId,\n orderId: entry.orderId,\n amountCents,\n ...(wholeLines.length > 0 && amountCents >= namedWorth ? { lineItemIds: wholeLines } : {}),\n },\n // One refund per return: asking again replays rather than pays twice.\n `return:${hostId}:${returnId}`,\n )\n if (refund.status !== 200) {\n return res.status(refund.status).json({ error: refund.body?.error ?? 'Refund failed' })\n }\n const marked = await markReturnRefunded({ hostId, returnId, refundCents: amountCents, uid: decoded.uid })\n if (marked.outcome === 'changed') {\n await raiseOrderEvent(RETURN_REFUNDED_EVENT, {\n hostId,\n orderId: entry.orderId,\n key: `return-refunded:${returnId}`,\n extra: { return: returnEventView(returnId, marked.entry) },\n })\n await tellBuyer(hostId, 'return-refunded', marked.entry, marked.order)\n }\n return res.status(200).json({ ok: true, refundCents: amountCents, status: 'refunded' })\n }\n\n const outcome = await changeReturn({\n hostId,\n returnId,\n action: action as ReturnAction,\n ...(body.merchantNote !== undefined ? { merchantNote: String(body.merchantNote) } : {}),\n ...(action === 'attach-label' ? { label: body.label } : {}),\n })\n if (outcome.outcome === 'no_such_return') return res.status(404).json({ error: 'Unknown return' })\n if (outcome.outcome === 'refused') return res.status(409).json({ error: outcome.message })\n if (outcome.outcome === 'changed' && body.notify !== false) {\n if (action === 'approve') await tellBuyer(hostId, 'return-approved', outcome.entry, outcome.order)\n if (action === 'decline') await tellBuyer(hostId, 'return-declined', outcome.entry, outcome.order)\n // A label attached after the approval reaches the buyer the same way,\n // in the approval email, which carries it.\n if (action === 'attach-label' && outcome.entry.status === 'approved') {\n await tellBuyer(hostId, 'return-approved', outcome.entry, outcome.order)\n }\n }\n return res.status(200).json({\n ok: true,\n ...(outcome.outcome === 'already' ? { already: true } : {}),\n status: outcome.entry.status,\n })\n } catch (error) {\n console.error('returns action failed', action, error)\n // Every write here is a transaction or keyed (the refund), so asking\n // again lands once.\n return res.status(500).json({ error: 'The return could not be updated. Retrying is safe.' })\n }\n}\n"],"names":["Aglyn","createResourceUid","findUserByUidAcrossPools","firebaseAdmin","getOrgForHost","hostSendingIdentity","meterHostEmail","notifyHostManagers","renderHostEmailWithTokens","hostConsoleUrl","isEmailConfigured","sendEmail","CommerceModel","RETURN_APPROVED_EVENT","RETURN_DECLINED_EVENT","RETURN_RECEIVED_EVENT","RETURN_REFUNDED_EVENT","RETURN_REQUESTED_EVENT","raiseOrderEvent","stageOrderEvent","orderStatusUrl","verifyOrderStatusToken","readActiveMemberSession","resolveTrackedRestockLines","refundHandler","hostRefFor","firestore","hostId","collection","doc","isId","value","Boolean","length","test","includes","readStore","settings","hostRef","host","store","Promise","all","get","catch","data","returnSettings","readReturnSettings","currency","String","toUpperCase","money","cents","Intl","NumberFormat","style","format","toFixed","returnEventView","id","entry","status","lines","map","line","refundCents","restock","returnItemsText","order","quantity","lineItems","lineItemId","name","RETURN_REASON_LABELS","reason","join","openReturn","request","app","orderRef","orderId","now","Date","note","trim","slice","RETURN_NOTE_MAX","runTransaction","transaction","orderSnapshot","exists","outcome","existing","where","liftLegacyOrder","verdict","validateReturnRequest","docs","by","message","describeReturnRequestProblem","orderNumber","returnOrderNumber","customerEmail","customerName","requestedBy","customerNote","merchantNote","timeline","atMs","event","detail","describeReturnLines","createdAtMs","updatedAtMs","returnRef","create","orderPatch","appendOrderEvent","update","key","extra","return","returnId","ACTION_TARGET","approve","decline","close","changeReturn","undefined","snapshot","target","action","patch","canTransitionReturn","RETURN_STATUS_LABELS","toLowerCase","appendReturnEvent","label","labelUrl","returnIsOpen","carrier","trackingNumber","trackingUrl","trackingUrlFor","returnLabel","attachedAtMs","changed","receiveReturn","locationId","covered","Map","wanted","Number","has","isInteger","total","set","size","location","tracked","ref","products","byProduct","Math","min","lineIndex","productId","variantId","units","product","variants","adjustVariantInventory","productStockFields","delta","entries","received","markReturnRefunded","refundedAtMs","max","round","check","restockCheck","resolution","restocked","some","resolvedAtMs","uid","resolvedBy","callRefundRoute","req","body","idempotencyKey","payload","res","code","json","send","error","setHeader","end","method","headers","authorization","sendReturnEmail","to","tokens","fallback","designed","org","subject","text","html","fromName","resolveBrandingProfile","sendingIdentity","audience","context","owedFor","console","tellStoreOfRequest","items","type","title","link","encodeURIComponent","skipOwnerEmail","ownerUid","owner","record","email","tellBuyer","statusUrl","filter","refundTotal","buyerMayActFor","token","session","memberEmail","member","returnRequestHandler","input","query","JSON","parse","o","t","returns","endsAt","returnWindowEndsAtMs","enabled","windowEndsAtMs","windowOpen","returnableLines","reasons","RETURN_REASONS","Array","isArray","ok","MERCHANT_ACTIONS","returnsHandler","idToken","startsWith","hostSnapshot","decoded","auth","verifyIdToken","role","notify","already","returnSnapshot","suggested","returnRefundCents","amountCents","isFinite","wholeLines","returnWholeLineIds","index","orderLineRefunded","namedWorth","orderLineRefundCents","refund","lineItemIds","marked"],"mappings":"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"}
|