/** * 财务四账单 Mock 数据(不重跑全量 seed) * 用法:cd server/dukang-api && npx ts-node --transpile-only prisma/seed-finance-mock.ts */ import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); function startOfDay(d: Date) { return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0, 0); } function billNo(prefix: string, suffix: string) { return `${prefix}MOCK${suffix}`.slice(0, 32); } async function main() { console.log('Seeding finance mock bills...'); const store = await prisma.store.findFirst({ where: { auditStatus: 'APPROVED' }, orderBy: { id: 'asc' }, }); if (!store) throw new Error('没有门店数据,请先 pnpm db:seed'); const partner = await prisma.partnerAccount.findFirst({ where: { isPrimary: 1, status: 'ACTIVE' }, orderBy: { id: 'asc' }, }); if (!partner) throw new Error('没有合伙人主账号,请先 pnpm db:seed'); let provider = await prisma.fulfillmentProvider.findFirst({ where: { code: { in: ['XFX', 'XIAOFEIXIA'] } }, }); if (!provider) { provider = await prisma.fulfillmentProvider.findFirst({ orderBy: { id: 'asc' } }); } if (!provider) throw new Error('没有仓配承运商,请先 pnpm db:seed 或在仓配管理注册'); // 确保小飞侠有对账配置,便于物流汇总页展示 if (!provider.pricingRulesJson || !provider.bankAccountName) { provider = await prisma.fulfillmentProvider.update({ where: { id: provider.id }, data: { settlementMethod: provider.settlementMethod ?? 'PREPAID', prepaidBalance: Number(provider.prepaidBalance) > 0 ? provider.prepaidBalance : 5000, bankAccountName: provider.bankAccountName || '郑州小飞侠物流有限公司', bankName: provider.bankName || '招商银行', bankBranch: provider.bankBranch || '郑州金水支行', bankAccountNo: provider.bankAccountNo || '6225880000001234', pricingRulesJson: provider.pricingRulesJson || JSON.stringify({ baseBottles: 2, baseFee: 6, extraBottleFee: 2, boxBottles: 6, boxFee: 14, }), }, }); } const today = startOfDay(new Date()); const yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1); const dayBefore = new Date(today); dayBefore.setDate(dayBefore.getDate() - 2); const thisMonthStart = new Date(today.getFullYear(), today.getMonth(), 1); const thisMonthEnd = new Date(today.getFullYear(), today.getMonth() + 1, 0, 23, 59, 59, 999); const prevMonthStart = new Date(today.getFullYear(), today.getMonth() - 1, 1); const prevMonthEnd = new Date(today.getFullYear(), today.getMonth(), 0, 23, 59, 59, 999); // 清理旧 mock(按账单号前缀) await prisma.logisticsBillItem.deleteMany({ where: { logisticsBill: { billNo: { startsWith: 'LBMOCK' } } }, }); await prisma.logisticsPrepaidLedger.deleteMany({ where: { logisticsBill: { billNo: { startsWith: 'LBMOCK' } } }, }); await prisma.logisticsBill.deleteMany({ where: { billNo: { startsWith: 'LBMOCK' } } }); await prisma.wineryBillItem.deleteMany({ where: { wineryBill: { billNo: { startsWith: 'WBMOCK' } } }, }); await prisma.wineryBill.deleteMany({ where: { billNo: { startsWith: 'WBMOCK' } } }); await prisma.storePayout.updateMany({ where: { storeBill: { billNo: { startsWith: 'SBMOCK' } } }, data: { storeBillId: null }, }); await prisma.storeBill.deleteMany({ where: { billNo: { startsWith: 'SBMOCK' } } }); await prisma.partnerBill.deleteMany({ where: { billNo: { startsWith: 'PBMOCK' } } }); // ─── 1. 门店账单(昨日未打款 + 前日已打款)─── const storeBillUnpaid = await prisma.storeBill.create({ data: { billNo: billNo('SB', `${yesterday.getTime()}U`), storeId: store.id, billDate: yesterday, redeemCount: 5, redeemAmount: 1500, settlementRate: 0.6, payoutAmount: 900, status: 'UNPAID', }, }); const storeBillPaid = await prisma.storeBill.create({ data: { billNo: billNo('SB', `${dayBefore.getTime()}P`), storeId: store.id, billDate: dayBefore, redeemCount: 3, redeemAmount: 800, settlementRate: 0.6, payoutAmount: 480, status: 'PAID', paidAt: yesterday, }, }); // ─── 2. 合伙人月账单(上月待确认 + 本月已打款样例)─── const partnerBillAwait = await prisma.partnerBill.upsert({ where: { partnerAccountId_periodStart: { partnerAccountId: partner.id, periodStart: prevMonthStart, }, }, create: { billNo: billNo('PB', `${prevMonthStart.getTime()}A`), partnerAccountId: partner.id, periodStart: prevMonthStart, periodEnd: prevMonthEnd, orderCommission: 860, redeemCommission: 420, totalAmount: 1280, status: 'AWAITING_CONFIRM', sentAt: yesterday, }, update: { billNo: billNo('PB', `${prevMonthStart.getTime()}A`), orderCommission: 860, redeemCommission: 420, totalAmount: 1280, status: 'AWAITING_CONFIRM', sentAt: yesterday, paidAt: null, rejectReason: null, }, }); // 本月另起一条若冲突则跳过(unique partner+period)— 用上上月做已打款 const olderMonthStart = new Date(today.getFullYear(), today.getMonth() - 2, 1); const olderMonthEnd = new Date(today.getFullYear(), today.getMonth() - 1, 0, 23, 59, 59, 999); const partnerBillPaid = await prisma.partnerBill.upsert({ where: { partnerAccountId_periodStart: { partnerAccountId: partner.id, periodStart: olderMonthStart, }, }, create: { billNo: billNo('PB', `${olderMonthStart.getTime()}P`), partnerAccountId: partner.id, periodStart: olderMonthStart, periodEnd: olderMonthEnd, orderCommission: 500, redeemCommission: 300, totalAmount: 800, status: 'PAID', sentAt: olderMonthEnd, confirmedAt: thisMonthStart, paidAt: thisMonthStart, }, update: { billNo: billNo('PB', `${olderMonthStart.getTime()}P`), orderCommission: 500, redeemCommission: 300, totalAmount: 800, status: 'PAID', paidAt: thisMonthStart, }, }); // ─── 3. 酒厂日账单 ─── const wineryUnpaid = await prisma.wineryBill.upsert({ where: { billDate: yesterday }, create: { billNo: billNo('WB', `${yesterday.getTime()}U`), billDate: yesterday, orderCount: 4, orderAmount: 4792, wineryRate: 0.3, wineryAmount: 1437.6, status: 'UNPAID', }, update: { billNo: billNo('WB', `${yesterday.getTime()}U`), orderCount: 4, orderAmount: 4792, wineryRate: 0.3, wineryAmount: 1437.6, status: 'UNPAID', paidAt: null, }, }); await prisma.wineryBillItem.deleteMany({ where: { wineryBillId: wineryUnpaid.id } }); // 用极大假 orderId,避免与真实订单冲突 const fakeOrderBase = BigInt('900000000000000001'); await prisma.wineryBillItem.createMany({ data: [ { wineryBillId: wineryUnpaid.id, orderId: fakeOrderBase, orderNo: 'DKMOCK-WB-001', deliveryType: 'LOCAL', payAmount: 1198, wineryAmount: 359.4, paidAt: yesterday, }, { wineryBillId: wineryUnpaid.id, orderId: fakeOrderBase + 1n, orderNo: 'DKMOCK-WB-002', deliveryType: 'LOCAL', payAmount: 1198, wineryAmount: 359.4, paidAt: yesterday, }, { wineryBillId: wineryUnpaid.id, orderId: fakeOrderBase + 2n, orderNo: 'DKMOCK-WB-003', deliveryType: 'CROSS_CITY', payAmount: 1797, wineryAmount: 539.1, paidAt: yesterday, }, { wineryBillId: wineryUnpaid.id, orderId: fakeOrderBase + 3n, orderNo: 'DKMOCK-WB-004', deliveryType: 'LOCAL', payAmount: 599, wineryAmount: 179.7, paidAt: yesterday, }, ], }); const wineryPaid = await prisma.wineryBill.upsert({ where: { billDate: dayBefore }, create: { billNo: billNo('WB', `${dayBefore.getTime()}P`), billDate: dayBefore, orderCount: 2, orderAmount: 2396, wineryRate: 0.3, wineryAmount: 718.8, status: 'PAID', paidAt: yesterday, }, update: { billNo: billNo('WB', `${dayBefore.getTime()}P`), orderCount: 2, orderAmount: 2396, wineryRate: 0.3, wineryAmount: 718.8, status: 'PAID', paidAt: yesterday, }, }); // ─── 4. 物流对账月账单(上月挂账未结 + 本月充值已扣)─── const logisticsUnpaid = await prisma.logisticsBill.upsert({ where: { fulfillmentProviderId_periodStart: { fulfillmentProviderId: provider.id, periodStart: prevMonthStart, }, }, create: { billNo: billNo('LB', `${prevMonthStart.getTime()}U`), fulfillmentProviderId: provider.id, periodStart: prevMonthStart, periodEnd: prevMonthEnd, orderCount: 3, bottleCount: 20, logisticsAmount: 46, settlementMethod: 'MONTHLY_CREDIT', pricingSnapshotJson: JSON.stringify({ baseBottles: 2, baseFee: 6, extraBottleFee: 2, boxBottles: 6, boxFee: 14, }), status: 'UNPAID', }, update: { billNo: billNo('LB', `${prevMonthStart.getTime()}U`), orderCount: 3, bottleCount: 20, logisticsAmount: 46, settlementMethod: 'MONTHLY_CREDIT', status: 'UNPAID', paidAt: null, }, }); await prisma.logisticsBillItem.deleteMany({ where: { logisticsBillId: logisticsUnpaid.id } }); await prisma.logisticsBillItem.createMany({ data: [ { logisticsBillId: logisticsUnpaid.id, orderId: fakeOrderBase + 10n, orderNo: 'DKMOCK-LB-001', quantity: 6, logisticsAmount: 14, shippedAt: new Date(prevMonthStart.getTime() + 3 * 86400000), }, { logisticsBillId: logisticsUnpaid.id, orderId: fakeOrderBase + 11n, orderNo: 'DKMOCK-LB-002', quantity: 8, logisticsAmount: 20, // 箱14 + 2瓶6 shippedAt: new Date(prevMonthStart.getTime() + 8 * 86400000), }, { logisticsBillId: logisticsUnpaid.id, orderId: fakeOrderBase + 12n, orderNo: 'DKMOCK-LB-003', quantity: 6, logisticsAmount: 14, shippedAt: new Date(prevMonthStart.getTime() + 15 * 86400000), }, ], }); // 修正合计:14+20+14=48 await prisma.logisticsBill.update({ where: { id: logisticsUnpaid.id }, data: { bottleCount: 20, logisticsAmount: 48 }, }); const logisticsPaid = await prisma.logisticsBill.upsert({ where: { fulfillmentProviderId_periodStart: { fulfillmentProviderId: provider.id, periodStart: thisMonthStart, }, }, create: { billNo: billNo('LB', `${thisMonthStart.getTime()}P`), fulfillmentProviderId: provider.id, periodStart: thisMonthStart, periodEnd: thisMonthEnd, orderCount: 2, bottleCount: 10, logisticsAmount: 22, settlementMethod: 'PREPAID', pricingSnapshotJson: JSON.stringify({ baseBottles: 2, baseFee: 6, extraBottleFee: 2, boxBottles: 6, boxFee: 14, }), status: 'PAID', paidAt: yesterday, }, update: { billNo: billNo('LB', `${thisMonthStart.getTime()}P`), orderCount: 2, bottleCount: 10, logisticsAmount: 22, settlementMethod: 'PREPAID', status: 'PAID', paidAt: yesterday, }, }); await prisma.logisticsBillItem.deleteMany({ where: { logisticsBillId: logisticsPaid.id } }); await prisma.logisticsBillItem.createMany({ data: [ { logisticsBillId: logisticsPaid.id, orderId: fakeOrderBase + 20n, orderNo: 'DKMOCK-LB-101', quantity: 4, logisticsAmount: 10, shippedAt: new Date(thisMonthStart.getTime() + 2 * 86400000), }, { logisticsBillId: logisticsPaid.id, orderId: fakeOrderBase + 21n, orderNo: 'DKMOCK-LB-102', quantity: 6, logisticsAmount: 14, shippedAt: new Date(thisMonthStart.getTime() + 5 * 86400000), }, ], }); // 充值流水样例 await prisma.logisticsPrepaidLedger.create({ data: { fulfillmentProviderId: provider.id, type: 'RECHARGE', amount: 5000, balanceAfter: 5000, remark: 'Mock 预充运费', }, }); await prisma.logisticsPrepaidLedger.create({ data: { fulfillmentProviderId: provider.id, type: 'DEDUCT', amount: 22, balanceAfter: 4978, logisticsBillId: logisticsPaid.id, remark: 'Mock 本月物流账单扣款', }, }); await prisma.fulfillmentProvider.update({ where: { id: provider.id }, data: { prepaidBalance: 4978, settlementMethod: 'PREPAID' }, }); console.log('Finance mock ready:', { store: { id: store.id.toString(), name: store.name }, partner: { id: partner.id.toString(), phone: partner.phone }, provider: { id: provider.id.toString(), code: provider.code, name: provider.name }, storeBills: [storeBillUnpaid.billNo, storeBillPaid.billNo], partnerBills: [partnerBillAwait.billNo, partnerBillPaid.billNo], wineryBills: [wineryUnpaid.billNo, wineryPaid.billNo], logisticsBills: [logisticsUnpaid.billNo, logisticsPaid.billNo], }); console.log('打开 admin:财务 → 门店/合伙人/酒厂/物流对账'); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });