213 lines
7.1 KiB
TypeScript
213 lines
7.1 KiB
TypeScript
import type { BillingCharge, BillingPayment, BillingStatement, PaymentMethod } from "@/modules/billing/types";
|
|
|
|
type StatementSeed = {
|
|
id: string;
|
|
elderId: string;
|
|
elderName: string;
|
|
roomLabel: string;
|
|
contactName: string;
|
|
contactPhone: string;
|
|
dueOffsetDays: number;
|
|
charges: Array<Omit<BillingCharge, "id" | "serviceDate">>;
|
|
payments: Array<{
|
|
amountCents: number;
|
|
method: PaymentMethod;
|
|
paidOffsetDays: number;
|
|
reference: string;
|
|
operator: string;
|
|
note: string;
|
|
}>;
|
|
invoiceStatus?: BillingStatement["invoiceStatus"];
|
|
invoiceNumber?: string;
|
|
receiptCount?: number;
|
|
};
|
|
|
|
const STATEMENT_SEEDS: StatementSeed[] = [
|
|
{
|
|
id: "bill-wgl",
|
|
elderId: "elder-wgl",
|
|
elderName: "王桂兰",
|
|
roomLabel: "A101-1",
|
|
contactName: "张敏",
|
|
contactPhone: "13800000001",
|
|
dueOffsetDays: 6,
|
|
charges: [
|
|
{ category: "床位服务", description: "标准护理房床位费", quantity: 1, unitPriceCents: 360000 },
|
|
{ category: "护理服务", description: "重点照护服务包", quantity: 1, unitPriceCents: 390000 },
|
|
{ category: "膳食服务", description: "低盐营养膳食", quantity: 1, unitPriceCents: 180000 },
|
|
{ category: "健康管理", description: "血压跟踪与健康复核", quantity: 1, unitPriceCents: 30000 },
|
|
],
|
|
payments: [
|
|
{
|
|
amountCents: 960000,
|
|
method: "wechat",
|
|
paidOffsetDays: -2,
|
|
reference: "WX202607090018",
|
|
operator: "前台收费组",
|
|
note: "家属线上支付",
|
|
},
|
|
],
|
|
invoiceStatus: "issued",
|
|
invoiceNumber: "FP20260709001",
|
|
receiptCount: 1,
|
|
},
|
|
{
|
|
id: "bill-ljg",
|
|
elderId: "elder-ljg",
|
|
elderName: "李建国",
|
|
roomLabel: "A102-1",
|
|
contactName: "李明",
|
|
contactPhone: "13800000002",
|
|
dueOffsetDays: 8,
|
|
charges: [
|
|
{ category: "床位服务", description: "半护理房床位费", quantity: 1, unitPriceCents: 320000 },
|
|
{ category: "护理服务", description: "半护理服务包", quantity: 1, unitPriceCents: 250000 },
|
|
{ category: "膳食服务", description: "日常营养膳食", quantity: 1, unitPriceCents: 170000 },
|
|
{ category: "活动服务", description: "康体活动与陪同", quantity: 1, unitPriceCents: 40000 },
|
|
],
|
|
payments: [
|
|
{
|
|
amountCents: 400000,
|
|
method: "bank_transfer",
|
|
paidOffsetDays: -1,
|
|
reference: "BANK20260708032",
|
|
operator: "财务值班",
|
|
note: "首笔转账已确认",
|
|
},
|
|
],
|
|
invoiceStatus: "pending",
|
|
},
|
|
{
|
|
id: "bill-zyz",
|
|
elderId: "elder-zyz",
|
|
elderName: "周玉珍",
|
|
roomLabel: "A201-1",
|
|
contactName: "周强",
|
|
contactPhone: "13800000003",
|
|
dueOffsetDays: 10,
|
|
charges: [
|
|
{ category: "床位服务", description: "记忆照护专区床位费", quantity: 1, unitPriceCents: 370000 },
|
|
{ category: "护理服务", description: "协助护理服务包", quantity: 1, unitPriceCents: 285000 },
|
|
{ category: "膳食服务", description: "糖尿病营养膳食", quantity: 1, unitPriceCents: 185000 },
|
|
],
|
|
payments: [],
|
|
},
|
|
{
|
|
id: "bill-zgh",
|
|
elderId: "elder-zgh",
|
|
elderName: "赵国华",
|
|
roomLabel: "A202-1",
|
|
contactName: "赵琳",
|
|
contactPhone: "13800000004",
|
|
dueOffsetDays: -3,
|
|
charges: [
|
|
{ category: "床位服务", description: "重点护理房床位费", quantity: 1, unitPriceCents: 380000 },
|
|
{ category: "护理服务", description: "失能照护服务包", quantity: 1, unitPriceCents: 420000 },
|
|
{ category: "膳食服务", description: "软食营养膳食", quantity: 1, unitPriceCents: 185000 },
|
|
{ category: "生活用品", description: "护理耗材包", quantity: 1, unitPriceCents: 60000 },
|
|
],
|
|
payments: [
|
|
{
|
|
amountCents: 200000,
|
|
method: "cash",
|
|
paidOffsetDays: -6,
|
|
reference: "CASH20260703009",
|
|
operator: "前台收费组",
|
|
note: "现金预缴",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: "bill-msf",
|
|
elderId: "elder-msf",
|
|
elderName: "马淑芬",
|
|
roomLabel: "A301-1",
|
|
contactName: "马晨",
|
|
contactPhone: "13800000011",
|
|
dueOffsetDays: -5,
|
|
charges: [
|
|
{ category: "床位服务", description: "失能照护区床位费", quantity: 1, unitPriceCents: 390000 },
|
|
{ category: "护理服务", description: "全护理服务包", quantity: 1, unitPriceCents: 460000 },
|
|
{ category: "膳食服务", description: "吞咽困难软食套餐", quantity: 1, unitPriceCents: 205000 },
|
|
{ category: "营养服务", description: "营养师评估与加餐", quantity: 1, unitPriceCents: 65000 },
|
|
],
|
|
payments: [],
|
|
},
|
|
{
|
|
id: "bill-qsb",
|
|
elderId: "elder-qsb",
|
|
elderName: "钱松柏",
|
|
roomLabel: "S101-1",
|
|
contactName: "钱宁",
|
|
contactPhone: "13800000014",
|
|
dueOffsetDays: 4,
|
|
charges: [
|
|
{ category: "床位服务", description: "医养观察房床位费", quantity: 1, unitPriceCents: 430000 },
|
|
{ category: "护理服务", description: "医养重点照护服务包", quantity: 1, unitPriceCents: 480000 },
|
|
{ category: "膳食服务", description: "呼吸慢病营养膳食", quantity: 1, unitPriceCents: 190000 },
|
|
{ category: "设备服务", description: "制氧与血氧监测服务", quantity: 1, unitPriceCents: 150000 },
|
|
],
|
|
payments: [
|
|
{
|
|
amountCents: 1250000,
|
|
method: "card",
|
|
paidOffsetDays: -1,
|
|
reference: "POS20260708017",
|
|
operator: "医养前台",
|
|
note: "银行卡支付",
|
|
},
|
|
],
|
|
receiptCount: 1,
|
|
},
|
|
];
|
|
|
|
function addDays(reference: Date, days: number): string {
|
|
const result = new Date(reference);
|
|
result.setDate(result.getDate() + days);
|
|
return result.toISOString();
|
|
}
|
|
|
|
function getPeriod(reference: Date): string {
|
|
const year = reference.getFullYear();
|
|
const month = String(reference.getMonth() + 1).padStart(2, "0");
|
|
return `${year}-${month}`;
|
|
}
|
|
|
|
function createCharges(seed: StatementSeed, reference: Date): BillingCharge[] {
|
|
return seed.charges.map((charge, index) => ({
|
|
...charge,
|
|
id: `${seed.id}-charge-${index + 1}`,
|
|
serviceDate: addDays(reference, -Math.max(1, 12 - index * 2)),
|
|
}));
|
|
}
|
|
|
|
function createPayments(seed: StatementSeed, reference: Date): BillingPayment[] {
|
|
return seed.payments.map((payment, index) => ({
|
|
id: `${seed.id}-payment-${index + 1}`,
|
|
amountCents: payment.amountCents,
|
|
method: payment.method,
|
|
paidAt: addDays(reference, payment.paidOffsetDays),
|
|
reference: payment.reference,
|
|
operator: payment.operator,
|
|
note: payment.note,
|
|
}));
|
|
}
|
|
|
|
export function createInitialBillingStatements(referenceDate = new Date()): BillingStatement[] {
|
|
return STATEMENT_SEEDS.map((seed) => ({
|
|
id: seed.id,
|
|
elderId: seed.elderId,
|
|
elderName: seed.elderName,
|
|
roomLabel: seed.roomLabel,
|
|
contactName: seed.contactName,
|
|
contactPhone: seed.contactPhone,
|
|
period: getPeriod(referenceDate),
|
|
dueAt: addDays(referenceDate, seed.dueOffsetDays),
|
|
charges: createCharges(seed, referenceDate),
|
|
payments: createPayments(seed, referenceDate),
|
|
invoiceStatus: seed.invoiceStatus ?? "not_requested",
|
|
invoiceNumber: seed.invoiceNumber,
|
|
receiptCount: seed.receiptCount ?? 0,
|
|
}));
|
|
}
|