EOF Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
"prisma:migrate": "prisma migrate dev",
|
||||
"prisma:validate": "prisma validate",
|
||||
"prisma:seed": "ts-node --transpile-only prisma/seed-v31.ts",
|
||||
"prisma:seed-finance": "ts-node --transpile-only prisma/seed-finance-mock.ts",
|
||||
"prisma:migrate-city-partner": "ts-node --transpile-only prisma/migrate-city-partner.ts",
|
||||
"prisma:seed-legacy": "ts-node --transpile-only prisma/seed-prev1.ts",
|
||||
"prisma:upsert-super-admin": "ts-node --transpile-only scripts/upsert-super-admin.ts",
|
||||
|
||||
@@ -0,0 +1,447 @@
|
||||
/**
|
||||
* 财务四账单 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();
|
||||
});
|
||||
Reference in New Issue
Block a user