import type { Context } from '@netlify/functions' import { guardMethod } from '../utils/method.js' import { fail, ok } from '../utils/http.js' import { readJson } from '../utils/request.js' import { prisma } from '../utils/prisma.js' import { withErrorBoundary } from '../utils/handler.js' type CheckoutGoods = { id?: string | number sku?: string count?: number number?: number price?: string | number name?: string image?: string imageUrl?: string picInfo?: string[] taxRate?: number } type OrderCreateRequest = { supplierId?: string token?: string userId?: string orderNo?: string orderNumberId?: string amount?: number goods?: CheckoutGoods[] } type BridgeOrderResponse = { resultCode?: number message?: string } const normalizeBase = (base: string) => base.replace(/\/$/, '') const nowText = () => { const now = new Date() const pad = (value: number) => String(value).padStart(2, '0') return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}` } const createOrderNumberId = () => { const now = new Date() const pad = (value: number, size = 2) => String(value).padStart(size, '0') return `TR${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}${pad(now.getMilliseconds(), 3)}` } const toYuan = (centAmount?: number) => Number(((Number(centAmount || 0)) / 100).toFixed(2)) const toOrderProducts = (goods: CheckoutGoods[]) => goods.map((item, index) => { const image = item.image || item.imageUrl || item.picInfo?.[0] || '' return { sku: String(item.sku || item.id || `SKU_${index + 1}`), number: Number(item.count || item.number || 1), price: Number(item.price || 0), name: String(item.name || ''), taxRate: Number(item.taxRate || 0.13), picInfo: item.picInfo?.length ? item.picInfo : image ? [image] : [], fileId: image || null, filePath: image || null } }) export default withErrorBoundary(async (request: Request, _context: Context) => { const methodResponse = guardMethod(request, ['POST']) if (methodResponse) return methodResponse const body = await readJson(request) const supplierId = String(body.supplierId || '').trim() const token = String(body.token || '').trim() const userId = String(body.userId || '').trim() const orderId = String(body.orderNo || '').trim() const amount = toYuan(body.amount) const goods = Array.isArray(body.goods) ? body.goods : [] if (!supplierId || !token || !userId || !orderId) { return fail('供应商、用户、授权或订单信息不能为空') } if (amount <= 0) { return fail('订单金额必须大于0') } const apiBase = normalizeBase(process.env.POINTS_MALL_OPEN_API_BASE || '') if (!apiBase) { return fail('平台积分商城接口地址未配置', 500, 'OPEN_API_BASE_MISSING') } const orderNumberId = String(body.orderNumberId || createOrderNumberId()) const subOrderId = `${orderId}_001` const subOrderNumberId = `${orderNumberId}_001` const orderTime = nowText() const orderProInfos = toOrderProducts(goods) const orderInfo = { orderId, orderNumberId, supplierId, aplName: '积分商城', createTime: orderTime, updateTime: orderTime, deliveryTime: null, orderFinishTime: null, completeTime: null, deliveryStatus: '0', freightCost: 0, wPayOrAPayFreightCost: 0, refund: 0, wPayOrAPayRefund: 0, logisticsOrderId: null, crrgBsnNm: null, orderState: 1, totalPrice: amount, wPayOrAPay: 0, pointsPrice: amount, invoiceCode: null, orderProInfos } await prisma.$transaction(async tx => { await tx.supplierOrderMain.upsert({ where: { orderId }, update: { orderNumberId, supplierId, userId, aplName: orderInfo.aplName, updateTime: new Date(), deliveryStatus: orderInfo.deliveryStatus, freightCost: orderInfo.freightCost, wPayOrAPayFreightCost: orderInfo.wPayOrAPayFreightCost, refund: orderInfo.refund, wPayOrAPayRefund: orderInfo.wPayOrAPayRefund, orderState: orderInfo.orderState, totalPrice: orderInfo.totalPrice, wPayOrAPay: orderInfo.wPayOrAPay, pointsPrice: orderInfo.pointsPrice, invoiceCode: orderInfo.invoiceCode, deleted: 0 }, create: { orderId, orderNumberId, supplierId, userId, aplName: orderInfo.aplName, createTime: new Date(), updateTime: new Date(), deliveryStatus: orderInfo.deliveryStatus, freightCost: orderInfo.freightCost, wPayOrAPayFreightCost: orderInfo.wPayOrAPayFreightCost, refund: orderInfo.refund, wPayOrAPayRefund: orderInfo.wPayOrAPayRefund, orderState: orderInfo.orderState, totalPrice: orderInfo.totalPrice, wPayOrAPay: orderInfo.wPayOrAPay, pointsPrice: orderInfo.pointsPrice, invoiceCode: orderInfo.invoiceCode } }) await tx.supplierOrderSub.upsert({ where: { orderId: subOrderId }, update: { orderNumberId: subOrderNumberId, mainOrderId: orderId, supplierId, token, userId, aplName: orderInfo.aplName, updateTime: new Date(), deliveryStatus: orderInfo.deliveryStatus, freightCost: orderInfo.freightCost, wPayOrAPayFreightCost: orderInfo.wPayOrAPayFreightCost, refund: orderInfo.refund, wPayOrAPayRefund: orderInfo.wPayOrAPayRefund, orderState: orderInfo.orderState, totalPrice: orderInfo.totalPrice, wPayOrAPay: orderInfo.wPayOrAPay, pointsPrice: orderInfo.pointsPrice, invoiceCode: orderInfo.invoiceCode, deleted: 0 }, create: { orderId: subOrderId, orderNumberId: subOrderNumberId, mainOrderId: orderId, supplierId, token, userId, aplName: orderInfo.aplName, createTime: new Date(), updateTime: new Date(), deliveryStatus: orderInfo.deliveryStatus, freightCost: orderInfo.freightCost, wPayOrAPayFreightCost: orderInfo.wPayOrAPayFreightCost, refund: orderInfo.refund, wPayOrAPayRefund: orderInfo.wPayOrAPayRefund, orderState: orderInfo.orderState, totalPrice: orderInfo.totalPrice, wPayOrAPay: orderInfo.wPayOrAPay, pointsPrice: orderInfo.pointsPrice, invoiceCode: orderInfo.invoiceCode } }) await tx.supplierOrderProduct.deleteMany({ where: { subOrderId } }) if (orderProInfos.length) { await tx.supplierOrderProduct.createMany({ data: orderProInfos.map(item => ({ subOrderId, sku: item.sku, number: item.number, price: item.price, name: item.name, taxRate: item.taxRate, productImgUrl: item.picInfo[0] || null, fileId: item.fileId, filePath: item.filePath, picInfo: item.picInfo })) }) } }) const bridgeResponse = await fetch(`${apiBase}/pointOrder/pendingOrderInfo`, { method: 'POST', headers: { 'Content-Type': 'application/json', token }, body: JSON.stringify({ supplierId, userId, orderInfo, token }) }) const bridgePayload = (await bridgeResponse.json().catch(() => ({}))) as BridgeOrderResponse if (!bridgeResponse.ok || bridgePayload.resultCode !== 0) { return fail(bridgePayload.message || '提交待支付订单失败', 502, 'BRIDGE_PENDING_ORDER_FAILED') } return ok({ orderId, orderNumberId, subOrderId, orderInfo }) })