Files
teatea-pension/modules/billing/lib/presentation-data.ts

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,
}));
}