import { parseServiceAuth } from "@/lib/api/auth-context"; import { fail, ok } from "@/lib/response"; import { AuthError } from "@/modules/auth/errors"; import { createBusinessCustomer, updateBusinessCustomer, listBusinessCustomers, } from "@/modules/customer/business-customer-service"; import { upsertBusinessCustomerUsers } from "@/modules/customer/business-customer-user-service"; import { upsertMarkupConfig } from "@/modules/pricing/markup-service"; import { ValidationError } from "@/modules/quote/types"; import { prisma } from "@/lib/prisma"; import { z } from "zod"; const customerItemSchema = z.object({ business_customer_id: z.string().min(1), name: z.string().min(1), external_code: z.string().nullable().optional(), remark: z.string().nullable().optional(), markup_percent: z.number().min(0).max(30).optional(), }); const userItemSchema = z.object({ business_customer_id: z.string().min(1), external_user_id: z.string().min(1), account: z.string().min(1), display_name: z.string().nullable().optional(), email: z.string().nullable().optional(), mobile: z.string().nullable().optional(), main_external_user_id: z.string().nullable().optional(), status: z.enum(["active", "inactive"]).optional(), }); const bodySchema = z.object({ customers: z.array(customerItemSchema).default([]), users: z.array(userItemSchema).default([]), }); /** * 宿主推送:同步业务客户(代码/简称)+ 下属登录账号 * Authorization: Bearer * X-Customer-Id: CUST_004 */ export async function POST(request: Request) { let auth; try { auth = await parseServiceAuth(request); } catch (error) { if (error instanceof AuthError) { return fail(error.code, error.message, error.httpStatus); } throw error; } let body: unknown; try { body = await request.json(); } catch { return fail("VALIDATION_FAILED", "请求体格式无效", 400); } const parsed = bodySchema.safeParse(body); if (!parsed.success) { return fail( "VALIDATION_FAILED", parsed.error.issues[0]?.message ?? "参数无效", 400, ); } const tenantId = auth.customerId; let customerCreated = 0; let customerUpdated = 0; try { for (const row of parsed.data.customers) { const existing = await prisma.businessCustomer.findFirst({ where: { customerId: tenantId, businessCustomerId: row.business_customer_id, isDeleted: false, }, }); if (existing) { await updateBusinessCustomer(tenantId, row.business_customer_id, { name: row.name, externalCode: row.external_code ?? null, remark: row.remark ?? null, status: "active", }); customerUpdated += 1; } else { await createBusinessCustomer({ customerId: tenantId, businessCustomerId: row.business_customer_id, name: row.name, externalCode: row.external_code ?? null, remark: row.remark ?? null, }); customerCreated += 1; } if (typeof row.markup_percent === "number") { await upsertMarkupConfig( tenantId, row.business_customer_id, { markupType: "percent", markupPercent: row.markup_percent, markupFixedAmount: null, }, "host-customers-sync", "宿主同步加价", ); } } const userResult = await upsertBusinessCustomerUsers( tenantId, parsed.data.users.map((u) => ({ businessCustomerId: u.business_customer_id, externalUserId: u.external_user_id, account: u.account, displayName: u.display_name, email: u.email, mobile: u.mobile, mainExternalUserId: u.main_external_user_id, status: u.status, })), ); const customers = await listBusinessCustomers(tenantId); return ok({ customer_id: tenantId, customers: { created: customerCreated, updated: customerUpdated, total: parsed.data.customers.length, }, users: userResult, business_customer_count: customers.length, }); } catch (error) { if (error instanceof ValidationError) { return fail("VALIDATION_FAILED", error.message, 400); } throw error; } }