You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
chajia/modules/customer/business-customer-service.ts

161 lines
4.1 KiB

import { prisma } from "@/lib/prisma";
import type {
BusinessCustomerDto,
BusinessCustomerStatus,
} from "@/modules/customer/types";
import { ValidationError } from "@/modules/quote/types";
function serializeBusinessCustomer(row: {
customerId: string;
businessCustomerId: string;
name: string;
externalCode: string | null;
status: string;
remark: string | null;
createdAt: Date;
updatedAt: Date;
}): BusinessCustomerDto {
return {
customer_id: row.customerId,
business_customer_id: row.businessCustomerId,
name: row.name,
external_code: row.externalCode,
status: row.status as BusinessCustomerStatus,
remark: row.remark,
created_at: row.createdAt.toISOString(),
updated_at: row.updatedAt.toISOString(),
};
}
export async function listBusinessCustomers(customerId: string): Promise<BusinessCustomerDto[]> {
const rows = await prisma.businessCustomer.findMany({
where: { customerId, isDeleted: false },
orderBy: { createdAt: "desc" },
include: {
_count: {
select: {
users: {
where: { isDeleted: false, status: "active" },
},
},
},
},
});
return rows.map((row) => ({
...serializeBusinessCustomer(row),
user_count: row._count.users,
}));
}
export async function createBusinessCustomer(input: {
customerId: string;
businessCustomerId: string;
name: string;
externalCode?: string | null;
remark?: string | null;
}): Promise<BusinessCustomerDto> {
const customerId = input.customerId.trim();
const businessCustomerId = input.businessCustomerId.trim();
const name = input.name.trim();
if (!customerId) {
throw new Error("租户标识不能为空");
}
if (!businessCustomerId) {
throw new Error("客户标识不能为空");
}
if (!name) {
throw new Error("客户名称不能为空");
}
const created = await prisma.businessCustomer.create({
data: {
customerId,
businessCustomerId,
name,
externalCode: input.externalCode?.trim() || null,
remark: input.remark?.trim() || null,
status: "active",
},
});
return serializeBusinessCustomer(created);
}
export async function updateBusinessCustomer(
customerId: string,
businessCustomerId: string,
input: {
name?: string;
externalCode?: string | null;
status?: BusinessCustomerStatus;
remark?: string | null;
},
): Promise<BusinessCustomerDto> {
const existing = await prisma.businessCustomer.findFirst({
where: { customerId, businessCustomerId, isDeleted: false },
});
if (!existing) {
throw new Error("客户不存在");
}
const data: {
name?: string;
externalCode?: string | null;
status?: BusinessCustomerStatus;
remark?: string | null;
} = {};
if (input.name !== undefined) {
const name = input.name.trim();
if (!name) {
throw new Error("客户名称不能为空");
}
data.name = name;
}
if (input.externalCode !== undefined) {
data.externalCode = input.externalCode?.trim() || null;
}
if (input.status !== undefined) {
data.status = input.status;
}
if (input.remark !== undefined) {
data.remark = input.remark?.trim() || null;
}
const updated = await prisma.businessCustomer.update({
where: {
customerId_businessCustomerId: {
customerId,
businessCustomerId,
},
},
data,
});
return serializeBusinessCustomer(updated);
}
export async function getBusinessCustomer(
customerId: string,
businessCustomerId: string,
): Promise<BusinessCustomerDto | null> {
const row = await prisma.businessCustomer.findFirst({
where: { customerId, businessCustomerId, isDeleted: false },
});
return row ? serializeBusinessCustomer(row) : null;
}
export async function assertBusinessCustomerBelongsToTenant(
customerId: string,
businessCustomerId?: string | null,
): Promise<void> {
if (!businessCustomerId) {
return;
}
const exists = await prisma.businessCustomer.count({
where: {
customerId,
businessCustomerId,
isDeleted: false,
status: "active",
},
});
if (!exists) {
throw new ValidationError("客户不存在或已停用");
}
}