94d2a88581
CI / verify (pull_request) Has been cancelled
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
448 lines
14 KiB
TypeScript
448 lines
14 KiB
TypeScript
/**
|
|
* 财务四账单 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();
|
|
});
|