feat(settlement): redesign factory/partner/store statement bills
CI / verify (pull_request) Has been cancelled

Add WineryBill/StoreBill tables, partner review-send-confirm flow, daily/monthly cron, and admin multi-select confirm with status filters.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-22 17:25:49 +08:00
parent b534a569f8
commit b392c28787
22 changed files with 1549 additions and 543 deletions
+10 -2
View File
@@ -1,11 +1,19 @@
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { BullModule } from '@nestjs/bullmq';
import { TradeModule } from '../modules/trade/trade.module';
import { SettlementModule } from '../modules/settlement/settlement.module';
import { DeliveryProcessor } from './delivery.processor';
import { SettlementScheduler } from './settlement.scheduler';
import { DELIVERY_QUEUE } from './jobs.constants';
@Module({
imports: [BullModule.registerQueue({ name: DELIVERY_QUEUE }), TradeModule],
providers: [DeliveryProcessor],
imports: [
ScheduleModule.forRoot(),
BullModule.registerQueue({ name: DELIVERY_QUEUE }),
TradeModule,
SettlementModule,
],
providers: [DeliveryProcessor, SettlementScheduler],
})
export class JobsModule {}
@@ -0,0 +1,45 @@
import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { SettlementService } from '../modules/settlement/settlement.service';
/**
* 财务对账单定时任务(Asia/Shanghai
* - 每日 08:00:酒厂日账单 + 门店日账单(统计昨日 00:00~今日 00:00
* - 每月 1 日 08:00:合伙人上一自然月账单
*/
@Injectable()
export class SettlementScheduler {
private readonly logger = new Logger(SettlementScheduler.name);
constructor(private readonly settlementService: SettlementService) {}
@Cron('0 8 * * *', { timeZone: 'Asia/Shanghai' })
async handleDailyBills() {
this.logger.log('Daily settlement bills job start');
try {
const winery = await this.settlementService.generateWineryBillForDay();
this.logger.log(`Winery bill: ${JSON.stringify(winery)}`);
} catch (e) {
this.logger.error('Winery bill job failed', e instanceof Error ? e.stack : e);
}
try {
const store = await this.settlementService.generateStoreBillsForDay();
this.logger.log(`Store bills: ${JSON.stringify(store)}`);
} catch (e) {
this.logger.error('Store bill job failed', e instanceof Error ? e.stack : e);
}
}
@Cron('0 8 1 * *', { timeZone: 'Asia/Shanghai' })
async handleMonthlyPartnerBills() {
this.logger.log('Monthly partner bills job start');
try {
const result = await this.settlementService.generatePreviousMonthPartnerBills();
this.logger.log(
`Partner bills: total=${result.total} success=${result.success} failed=${result.failed}`,
);
} catch (e) {
this.logger.error('Partner bill job failed', e instanceof Error ? e.stack : e);
}
}
}