auto-settlement.service.ts 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. import { Injectable, signal, computed, inject } from '@angular/core';
  2. import { BehaviorSubject, Observable, of, timer, interval, forkJoin } from 'rxjs';
  3. import { map, switchMap, catchError } from 'rxjs/operators';
  4. import { Settlement } from '../models/project.model';
  5. import { ProjectService } from './project.service';
  6. import { PaymentVoucherRecognitionService, PaymentVoucherRecognitionResult } from './payment-voucher-recognition.service';
  7. import { MiniprogramPaymentService, MiniprogramPaymentResult } from './miniprogram-payment.service';
  8. import { NotificationService, NotificationType, NotificationChannel } from './notification.service';
  9. export interface AutoSettlementRule {
  10. id: string;
  11. name: string;
  12. enabled: boolean;
  13. conditions: SettlementCondition[];
  14. actions: SettlementAction[];
  15. priority: number;
  16. description?: string;
  17. }
  18. export interface SettlementCondition {
  19. type: 'projectType' | 'amountRange' | 'customerTier' | 'overdueDays' | 'paymentMethod';
  20. operator: 'equals' | 'greaterThan' | 'lessThan' | 'between' | 'contains';
  21. value: any;
  22. }
  23. export interface SettlementAction {
  24. type: 'sendReminder' | 'applyDiscount' | 'extendDueDate' | 'autoConfirm' | 'notifyManager';
  25. params: any;
  26. }
  27. export interface SettlementReminder {
  28. id: string;
  29. settlementId: string;
  30. type: 'email' | 'sms' | 'wechat' | 'system';
  31. content: string;
  32. sentAt: Date;
  33. status: 'pending' | 'sent' | 'failed';
  34. }
  35. @Injectable({
  36. providedIn: 'root'
  37. })
  38. export class AutoSettlementService {
  39. private scheduledProcesses = new Map<string, any>();
  40. private paymentRecognitionService = inject(PaymentVoucherRecognitionService);
  41. private miniprogramPaymentService = inject(MiniprogramPaymentService);
  42. private notificationService = inject(NotificationService);
  43. constructor(private projectService: ProjectService) {
  44. // 启动小程序支付自动化监听
  45. this.initializeMiniprogramPaymentAutomation();
  46. }
  47. private rules = signal<AutoSettlementRule[]>([
  48. {
  49. id: 'rule-1',
  50. name: '小额自动确认',
  51. enabled: true,
  52. priority: 1,
  53. conditions: [
  54. { type: 'amountRange', operator: 'lessThan', value: 5000 }
  55. ],
  56. actions: [
  57. { type: 'autoConfirm', params: { immediate: true } }
  58. ],
  59. description: '金额小于5000元时自动确认结算'
  60. },
  61. {
  62. id: 'rule-2',
  63. name: '逾期提醒',
  64. enabled: true,
  65. priority: 2,
  66. conditions: [
  67. { type: 'overdueDays', operator: 'greaterThan', value: 7 }
  68. ],
  69. actions: [
  70. { type: 'sendReminder', params: { channels: ['wechat', 'sms'], frequency: 'daily' } }
  71. ],
  72. description: '逾期7天以上时每天发送提醒'
  73. },
  74. {
  75. id: 'rule-3',
  76. name: 'VIP客户优惠',
  77. enabled: true,
  78. priority: 3,
  79. conditions: [
  80. { type: 'customerTier', operator: 'equals', value: 'vip' },
  81. { type: 'overdueDays', operator: 'greaterThan', value: 15 }
  82. ],
  83. actions: [
  84. { type: 'applyDiscount', params: { percentage: 5, maxAmount: 1000 } }
  85. ],
  86. description: 'VIP客户逾期15天以上时提供5%折扣'
  87. }
  88. ]);
  89. private reminders = signal<SettlementReminder[]>([]);
  90. private isProcessing = signal(false);
  91. // 获取所有规则
  92. getRules(): Observable<AutoSettlementRule[]> {
  93. return of(this.rules());
  94. }
  95. // 添加新规则
  96. addRule(rule: AutoSettlementRule): void {
  97. this.rules.update(rules => [...rules, rule]);
  98. }
  99. // 更新规则
  100. updateRule(ruleId: string, updates: Partial<AutoSettlementRule>): void {
  101. this.rules.update(rules =>
  102. rules.map(rule => rule.id === ruleId ? { ...rule, ...updates } : rule)
  103. );
  104. }
  105. // 删除规则
  106. deleteRule(ruleId: string): void {
  107. this.rules.update(rules => rules.filter(rule => rule.id !== ruleId));
  108. }
  109. // 处理结算自动化
  110. processSettlementAutomation(settlement: Settlement): Observable<boolean> {
  111. this.isProcessing.set(true);
  112. return of(this.rules())
  113. .pipe(
  114. map(rules => rules.filter(rule => rule.enabled)),
  115. map(enabledRules => {
  116. let processed = false;
  117. // 按优先级排序处理规则
  118. enabledRules.sort((a, b) => a.priority - b.priority);
  119. for (const rule of enabledRules) {
  120. if (this.checkConditions(rule.conditions, settlement)) {
  121. this.executeActions(rule.actions, settlement);
  122. processed = true;
  123. // 高优先级规则可能中断后续规则执行
  124. if (rule.priority >= 10) {
  125. break;
  126. }
  127. }
  128. }
  129. return processed;
  130. }),
  131. switchMap(processed => {
  132. this.isProcessing.set(false);
  133. return of(processed);
  134. })
  135. );
  136. }
  137. // 检查条件是否满足
  138. private checkConditions(conditions: SettlementCondition[], settlement: Settlement): boolean {
  139. return conditions.every(condition => {
  140. switch (condition.type) {
  141. case 'amountRange':
  142. return this.checkAmountCondition(condition, settlement.amount || 0);
  143. case 'overdueDays':
  144. const overdueDays = this.calculateOverdueDays(settlement);
  145. return this.checkNumericCondition(condition, overdueDays);
  146. case 'customerTier':
  147. // 简化实现,实际中需要从客户服务获取层级信息
  148. return condition.operator === 'equals' && condition.value === 'vip';
  149. default:
  150. return false;
  151. }
  152. });
  153. }
  154. // 执行动作
  155. private executeActions(actions: SettlementAction[], settlement: Settlement): void {
  156. actions.forEach(action => {
  157. switch (action.type) {
  158. case 'sendReminder':
  159. this.sendReminder(settlement, action.params);
  160. break;
  161. case 'applyDiscount':
  162. this.applyDiscount(settlement, action.params);
  163. break;
  164. case 'autoConfirm':
  165. this.autoConfirmSettlement(settlement, action.params);
  166. break;
  167. case 'notifyManager':
  168. this.notifyManager(settlement, action.params);
  169. break;
  170. }
  171. });
  172. }
  173. // 发送提醒
  174. private sendReminder(settlement: Settlement, params: any): void {
  175. const reminder: SettlementReminder = {
  176. id: `reminder-${Date.now()}`,
  177. settlementId: settlement.id,
  178. type: 'system',
  179. content: `结算提醒:项目 ${settlement.projectName} 的 ${settlement.amount} 元结算${this.calculateOverdueDays(settlement) > 0 ? '已逾期' : '待处理'}`,
  180. sentAt: new Date(),
  181. status: 'sent'
  182. };
  183. this.reminders.update(reminders => [...reminders, reminder]);
  184. // 实际实现中这里会调用消息服务发送到不同渠道
  185. console.log('发送结算提醒:', reminder);
  186. }
  187. // 应用折扣
  188. private applyDiscount(settlement: Settlement, params: any): void {
  189. const discountAmount = Math.min(
  190. (settlement.amount || 0) * (params.percentage / 100),
  191. params.maxAmount || 0
  192. );
  193. console.log(`为结算 ${settlement.id} 应用折扣: ${discountAmount}元`);
  194. // 实际实现中需要更新结算金额
  195. }
  196. // 自动确认结算
  197. private autoConfirmSettlement(settlement: Settlement, params: any): void {
  198. console.log(`自动确认结算: ${settlement.id}`);
  199. // 实际实现中需要调用结算服务确认结算
  200. }
  201. // 通知经理
  202. private notifyManager(settlement: Settlement, params: any): void {
  203. console.log(`通知经理处理大额结算: ${settlement.id}, 金额: ${settlement.amount}`);
  204. }
  205. // 计算逾期天数
  206. private calculateOverdueDays(settlement: Settlement): number {
  207. if (settlement.status === '已结算') return 0;
  208. const dueDate = settlement.dueDate || new Date(settlement.createdAt.getTime() + 30 * 24 * 60 * 60 * 1000);
  209. const today = new Date();
  210. const diffTime = today.getTime() - dueDate.getTime();
  211. return Math.max(0, Math.ceil(diffTime / (1000 * 60 * 60 * 24)));
  212. }
  213. // 检查金额条件
  214. private checkAmountCondition(condition: SettlementCondition, amount: number): boolean {
  215. return this.checkNumericCondition(condition, amount);
  216. }
  217. // 检查数值条件
  218. private checkNumericCondition(condition: SettlementCondition, value: number): boolean {
  219. switch (condition.operator) {
  220. case 'equals':
  221. return value === condition.value;
  222. case 'greaterThan':
  223. return value > condition.value;
  224. case 'lessThan':
  225. return value < condition.value;
  226. case 'between':
  227. return value >= condition.value[0] && value <= condition.value[1];
  228. default:
  229. return false;
  230. }
  231. }
  232. // 获取处理状态
  233. getProcessingStatus() {
  234. return this.isProcessing();
  235. }
  236. // 获取提醒记录
  237. getReminders(): Observable<SettlementReminder[]> {
  238. return of(this.reminders());
  239. }
  240. // 启动定时任务
  241. startScheduledProcessing(): void {
  242. // 清理现有的定时任务
  243. this.stopAllScheduledProcessing();
  244. // 每30分钟检查一次逾期结算
  245. this.scheduledProcesses.set('overdueCheck',
  246. timer(0, 30 * 60 * 1000).subscribe(() => {
  247. this.processOverdueSettlements();
  248. })
  249. );
  250. // 每天早上9点发送每日提醒
  251. this.scheduledProcesses.set('dailyReminder',
  252. this.scheduleDailyTask(9, 0, () => {
  253. this.sendDailyReminders();
  254. })
  255. );
  256. // 每周一早上10点发送周报
  257. this.scheduledProcesses.set('weeklyReport',
  258. this.scheduleWeeklyTask(1, 10, 0, () => {
  259. this.sendWeeklySettlementReport();
  260. })
  261. );
  262. // 每小时检查高优先级规则
  263. this.scheduledProcesses.set('hourlyCheck',
  264. timer(0, 60 * 60 * 1000).subscribe(() => {
  265. this.processHighPrioritySettlements();
  266. })
  267. );
  268. console.log('自动化结算定时任务已启动');
  269. }
  270. // 停止所有定时任务
  271. stopAllScheduledProcessing(): void {
  272. this.scheduledProcesses.forEach((subscription, key) => {
  273. subscription.unsubscribe();
  274. });
  275. this.scheduledProcesses.clear();
  276. }
  277. // 安排每日定时任务
  278. private scheduleDailyTask(hour: number, minute: number, task: () => void): any {
  279. const now = new Date();
  280. const targetTime = new Date();
  281. targetTime.setHours(hour, minute, 0, 0);
  282. let initialDelay = targetTime.getTime() - now.getTime();
  283. if (initialDelay < 0) {
  284. initialDelay += 24 * 60 * 60 * 1000; // 第二天同一时间
  285. }
  286. return timer(initialDelay, 24 * 60 * 60 * 1000).subscribe(() => {
  287. task();
  288. });
  289. }
  290. // 安排每周定时任务
  291. private scheduleWeeklyTask(dayOfWeek: number, hour: number, minute: number, task: () => void): any {
  292. const now = new Date();
  293. const targetTime = new Date();
  294. // 计算下一个指定星期几
  295. const daysUntilTarget = (dayOfWeek - now.getDay() + 7) % 7;
  296. targetTime.setDate(now.getDate() + daysUntilTarget);
  297. targetTime.setHours(hour, minute, 0, 0);
  298. let initialDelay = targetTime.getTime() - now.getTime();
  299. if (initialDelay < 0) {
  300. initialDelay += 7 * 24 * 60 * 60 * 1000; // 下一周同一时间
  301. }
  302. return timer(initialDelay, 7 * 24 * 60 * 60 * 1000).subscribe(() => {
  303. task();
  304. });
  305. }
  306. // 处理逾期结算
  307. private processOverdueSettlements(): void {
  308. console.log('执行定时逾期结算检查');
  309. // 获取所有待结算的记录
  310. this.projectService.getSettlements().pipe(
  311. map(settlements => settlements.filter(s => s.status === '待结算')),
  312. switchMap(pendingSettlements => {
  313. const overdueSettlements = pendingSettlements.filter(settlement =>
  314. this.calculateOverdueDays(settlement) > 0
  315. );
  316. // 对每个逾期结算应用自动化规则
  317. const processingObservables = overdueSettlements.map(settlement =>
  318. this.processSettlementAutomation(settlement).pipe(
  319. catchError(error => {
  320. console.error(`处理结算 ${settlement.id} 时出错:`, error);
  321. return of(false);
  322. })
  323. )
  324. );
  325. return processingObservables.length > 0
  326. ? forkJoin(processingObservables)
  327. : of([]);
  328. })
  329. ).subscribe(results => {
  330. const successful = results.filter(result => result).length;
  331. console.log(`逾期结算处理完成,成功处理 ${successful} 个结算`);
  332. });
  333. }
  334. // 处理高优先级结算
  335. private processHighPrioritySettlements(): void {
  336. this.projectService.getSettlements().pipe(
  337. map(settlements => settlements.filter(s => s.status === '待结算')),
  338. map(pendingSettlements => {
  339. // 筛选需要立即处理的高优先级结算(大金额或特定客户)
  340. return pendingSettlements.filter(settlement =>
  341. (settlement.amount || 0) > 10000 || // 大金额
  342. settlement.projectName?.includes('VIP') // VIP客户
  343. );
  344. }),
  345. switchMap(highPrioritySettlements => {
  346. const processingObservables = highPrioritySettlements.map(settlement =>
  347. this.processSettlementAutomation(settlement).pipe(
  348. catchError(error => {
  349. console.error(`处理高优先级结算 ${settlement.id} 时出错:`, error);
  350. return of(false);
  351. })
  352. )
  353. );
  354. return processingObservables.length > 0
  355. ? forkJoin(processingObservables)
  356. : of([]);
  357. })
  358. ).subscribe(results => {
  359. const successful = results.filter(result => result).length;
  360. if (successful > 0) {
  361. console.log(`高优先级结算处理完成,成功处理 ${successful} 个结算`);
  362. }
  363. });
  364. }
  365. // 发送每日提醒
  366. private sendDailyReminders(): void {
  367. this.projectService.getSettlements().pipe(
  368. map(settlements => settlements.filter(s => s.status === '待结算')),
  369. map(pendingSettlements => {
  370. const today = new Date();
  371. return pendingSettlements.filter(settlement => {
  372. const dueDate = settlement.dueDate || new Date(settlement.createdAt.getTime() + 30 * 24 * 60 * 60 * 1000);
  373. const daysUntilDue = Math.ceil((dueDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));
  374. // 发送即将到期(3天内)和已逾期的提醒
  375. return daysUntilDue <= 3 || this.calculateOverdueDays(settlement) > 0;
  376. });
  377. })
  378. ).subscribe(settlementsToRemind => {
  379. settlementsToRemind.forEach(settlement => {
  380. this.sendReminder(settlement, {
  381. channels: ['system', 'email'],
  382. frequency: 'daily',
  383. type: 'dueDateReminder'
  384. });
  385. });
  386. console.log(`每日提醒发送完成,共发送 ${settlementsToRemind.length} 个提醒`);
  387. });
  388. }
  389. // 发送周报
  390. private sendWeeklySettlementReport(): void {
  391. this.projectService.getSettlements().subscribe(allSettlements => {
  392. const pendingCount = allSettlements.filter(s => s.status === '待结算').length;
  393. const overdueCount = allSettlements.filter(s =>
  394. s.status === '待结算' && this.calculateOverdueDays(s) > 0
  395. ).length;
  396. const completedThisWeek = allSettlements.filter(s =>
  397. s.status === '已结算' &&
  398. s.settledAt &&
  399. new Date(s.settledAt).getTime() > Date.now() - 7 * 24 * 60 * 60 * 1000
  400. ).length;
  401. const report = {
  402. totalPending: pendingCount,
  403. totalOverdue: overdueCount,
  404. completedThisWeek: completedThisWeek,
  405. generatedAt: new Date()
  406. };
  407. console.log('周度结算报告:', report);
  408. // 这里可以添加发送邮件或系统通知的逻辑
  409. this.sendManagerNotification('weeklyReport', report);
  410. });
  411. }
  412. // 发送经理通知
  413. private sendManagerNotification(type: string, data: any): void {
  414. const notification = {
  415. id: `notification-${Date.now()}`,
  416. type: type,
  417. data: data,
  418. timestamp: new Date(),
  419. read: false
  420. };
  421. console.log('发送经理通知:', notification);
  422. // 实际实现中会调用通知服务
  423. }
  424. // 获取定时任务状态
  425. getScheduledTasksStatus(): { [key: string]: boolean } {
  426. const status: { [key: string]: boolean } = {};
  427. this.scheduledProcesses.forEach((subscription, key) => {
  428. status[key] = !subscription.closed;
  429. });
  430. return status;
  431. }
  432. // 支付凭证识别相关方法
  433. /**
  434. * 处理支付凭证上传并自动识别
  435. */
  436. async processPaymentVoucherUpload(file: File, settlementId: string): Promise<PaymentVoucherRecognitionResult> {
  437. try {
  438. const result = await this.paymentRecognitionService.recognizePaymentVoucher(file).toPromise();
  439. if (result && result.success) {
  440. // 识别成功,更新结算状态
  441. await this.updateSettlementWithPaymentInfo(settlementId, result);
  442. // 检查是否需要自动确认结算
  443. if (this.shouldAutoConfirmAfterPayment(result)) {
  444. await this.autoConfirmSettlementAfterPayment(settlementId, result);
  445. }
  446. }
  447. return result || {
  448. success: false,
  449. confidence: 0,
  450. error: '支付凭证处理失败'
  451. };
  452. } catch (error) {
  453. console.error('支付凭证处理失败:', error);
  454. return {
  455. success: false,
  456. confidence: 0,
  457. error: '支付凭证处理失败'
  458. };
  459. }
  460. }
  461. /**
  462. * 批量处理支付凭证
  463. */
  464. async processBatchPaymentVouchers(files: File[], settlementId: string): Promise<PaymentVoucherRecognitionResult[]> {
  465. const results: PaymentVoucherRecognitionResult[] = [];
  466. for (const file of files) {
  467. try {
  468. const result = await this.processPaymentVoucherUpload(file, settlementId);
  469. results.push(result);
  470. } catch (error) {
  471. results.push({
  472. success: false,
  473. confidence: 0,
  474. error: `文件 ${file.name} 处理失败`
  475. });
  476. }
  477. }
  478. return results;
  479. }
  480. /**
  481. * 使用支付信息更新结算记录
  482. */
  483. private async updateSettlementWithPaymentInfo(settlementId: string, paymentInfo: PaymentVoucherRecognitionResult): Promise<void> {
  484. // 这里需要实现更新结算记录的逻辑
  485. // 实际实现中会调用项目服务更新结算信息
  486. console.log(`更新结算 ${settlementId} 的支付信息:`, paymentInfo);
  487. // 模拟更新操作
  488. const settlements = await this.projectService.getSettlements().toPromise();
  489. const settlement = settlements?.find(s => s.id === settlementId);
  490. if (settlement) {
  491. // 更新结算记录的支付相关信息
  492. console.log('结算记录已更新支付信息');
  493. }
  494. }
  495. /**
  496. * 检查支付后是否需要自动确认结算
  497. */
  498. private shouldAutoConfirmAfterPayment(paymentInfo: PaymentVoucherRecognitionResult): boolean {
  499. // 根据支付金额、支付方式等条件判断是否需要自动确认
  500. const hasAmount = paymentInfo.amount !== undefined && paymentInfo.amount > 0;
  501. const highConfidence = paymentInfo.confidence > 0.8; // 识别置信度大于80%
  502. const trustedPaymentMethod = ['alipay', 'wechat', 'bank_transfer'].includes(paymentInfo.paymentMethod || '');
  503. return hasAmount && highConfidence && trustedPaymentMethod;
  504. }
  505. /**
  506. * 支付后自动确认结算
  507. */
  508. private async autoConfirmSettlementAfterPayment(settlementId: string, paymentInfo: PaymentVoucherRecognitionResult): Promise<void> {
  509. console.log(`支付凭证验证通过,自动确认结算 ${settlementId}`);
  510. // 获取结算记录
  511. const settlements = await this.projectService.getSettlements().toPromise();
  512. const settlement = settlements?.find(s => s.id === settlementId);
  513. if (settlement) {
  514. // 调用自动确认逻辑
  515. this.autoConfirmSettlement(settlement, {
  516. immediate: true,
  517. paymentVerified: true,
  518. paymentAmount: paymentInfo.amount,
  519. paymentMethod: paymentInfo.paymentMethod
  520. });
  521. console.log('结算已自动确认');
  522. }
  523. }
  524. /**
  525. * 获取支持的支付凭证类型
  526. */
  527. getSupportedPaymentVoucherTypes(): { extensions: string[], description: string } {
  528. const supportedTypes = this.paymentRecognitionService.getSupportedFileTypes();
  529. return {
  530. extensions: supportedTypes,
  531. description: this.paymentRecognitionService.getSupportedFileTypesDescription()
  532. };
  533. }
  534. /**
  535. * 验证支付凭证文件
  536. */
  537. validatePaymentVoucherFile(file: File): { valid: boolean, error?: string } {
  538. const result = this.paymentRecognitionService.validateFile(file);
  539. return {
  540. valid: result.isValid,
  541. error: result.error
  542. };
  543. }
  544. /**
  545. * 初始化小程序支付自动化流程
  546. */
  547. private initializeMiniprogramPaymentAutomation(): void {
  548. console.log('初始化小程序支付自动化流程...');
  549. // 监听小程序支付完成事件
  550. this.miniprogramPaymentService.onPaymentCompleted().subscribe({
  551. next: (paymentResult: MiniprogramPaymentResult) => {
  552. console.log('检测到小程序支付完成:', paymentResult);
  553. this.handleMiniprogramPaymentCompleted(paymentResult);
  554. },
  555. error: (error) => {
  556. console.error('小程序支付监听出错:', error);
  557. }
  558. });
  559. // 启动小程序支付自动化监听
  560. this.miniprogramPaymentService.startAutomationListener();
  561. }
  562. /**
  563. * 处理小程序支付完成事件
  564. */
  565. private handleMiniprogramPaymentCompleted(paymentResult: MiniprogramPaymentResult): void {
  566. if (!paymentResult.success) {
  567. console.error('支付失败,跳过自动化处理');
  568. return;
  569. }
  570. console.log(`开始处理小程序支付自动化流程: ${paymentResult.transactionId}`);
  571. // 处理支付完成后的自动化流程
  572. this.miniprogramPaymentService.processPaymentCompletedFlow(paymentResult).subscribe({
  573. next: (success) => {
  574. if (success) {
  575. console.log('小程序支付自动化流程处理成功');
  576. this.createAutomationLog(paymentResult.settlementId, 'miniprogram_payment_success', {
  577. transactionId: paymentResult.transactionId,
  578. amount: paymentResult.amount,
  579. processedAt: new Date()
  580. });
  581. // 发送支付完成通知
  582. this.sendPaymentCompletedNotifications(paymentResult);
  583. } else {
  584. console.error('小程序支付自动化流程处理失败');
  585. this.createAutomationLog(paymentResult.settlementId, 'miniprogram_payment_failed', {
  586. transactionId: paymentResult.transactionId,
  587. error: '自动化流程处理失败'
  588. });
  589. }
  590. },
  591. error: (error) => {
  592. console.error('小程序支付自动化流程出错:', error);
  593. this.createAutomationLog(paymentResult.settlementId, 'miniprogram_payment_error', {
  594. transactionId: paymentResult.transactionId,
  595. error: error.message
  596. });
  597. }
  598. });
  599. }
  600. /**
  601. * 发送支付完成通知
  602. */
  603. private sendPaymentCompletedNotifications(paymentResult: MiniprogramPaymentResult): void {
  604. console.log('发送支付完成通知...');
  605. // 获取客户信息(模拟)
  606. const customerInfo = this.getCustomerInfo(paymentResult.settlementId);
  607. // 发送支付完成通知
  608. this.notificationService.sendPaymentCompletedNotification({
  609. recipient: customerInfo.phone,
  610. paymentMethod: '小程序支付', // 使用固定值而不是paymentResult.paymentMethod
  611. amount: paymentResult.amount,
  612. customerName: customerInfo.name,
  613. projectName: customerInfo.projectName,
  614. channels: [NotificationChannel.SMS, NotificationChannel.WECHAT, NotificationChannel.IN_APP]
  615. }).subscribe({
  616. next: (result) => {
  617. if (result.success) {
  618. console.log('支付完成通知发送成功:', result);
  619. // 发送大图解锁通知
  620. this.sendImageUnlockedNotifications(paymentResult, customerInfo);
  621. } else {
  622. console.error('支付完成通知发送失败:', result.error);
  623. }
  624. },
  625. error: (error) => {
  626. console.error('支付完成通知发送出错:', error);
  627. }
  628. });
  629. }
  630. /**
  631. * 发送大图解锁通知
  632. */
  633. private sendImageUnlockedNotifications(paymentResult: MiniprogramPaymentResult, customerInfo: any): void {
  634. console.log('发送大图解锁通知...');
  635. this.notificationService.sendImageUnlockedNotification({
  636. recipient: customerInfo.phone,
  637. customerName: customerInfo.name,
  638. projectName: customerInfo.projectName,
  639. imageCount: customerInfo.imageCount || 8,
  640. resolution: '4K高清',
  641. validUntil: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toLocaleDateString(), // 30天有效期
  642. downloadLink: `https://download.yinsanse.com/project/${paymentResult.settlementId}`,
  643. channels: [NotificationChannel.SMS, NotificationChannel.EMAIL, NotificationChannel.IN_APP]
  644. }).subscribe({
  645. next: (result) => {
  646. if (result.success) {
  647. console.log('大图解锁通知发送成功:', result);
  648. } else {
  649. console.error('大图解锁通知发送失败:', result.error);
  650. }
  651. },
  652. error: (error) => {
  653. console.error('大图解锁通知发送出错:', error);
  654. }
  655. });
  656. }
  657. /**
  658. * 获取客户信息(模拟)
  659. */
  660. private getCustomerInfo(settlementId: string): {
  661. name: string;
  662. phone: string;
  663. email: string;
  664. projectName: string;
  665. imageCount: number;
  666. } {
  667. // 模拟客户信息
  668. return {
  669. name: '张先生',
  670. phone: '138****8888',
  671. email: 'customer@example.com',
  672. projectName: '现代简约三居室设计',
  673. imageCount: 8
  674. };
  675. }
  676. /**
  677. * 创建自动化日志
  678. */
  679. private createAutomationLog(settlementId: string, type: string, data: any): void {
  680. const log = {
  681. id: `log_${Date.now()}`,
  682. settlementId,
  683. type,
  684. data,
  685. timestamp: new Date()
  686. };
  687. console.log('创建自动化日志:', log);
  688. // 实际实现中会保存到数据库或日志系统
  689. }
  690. /**
  691. * 手动触发小程序支付测试流程
  692. */
  693. triggerMiniprogramPaymentTest(settlementId: string, amount: number): Observable<boolean> {
  694. console.log(`触发小程序支付测试流程: ${settlementId}, 金额: ${amount}`);
  695. return this.miniprogramPaymentService.triggerTestPaymentFlow(settlementId, amount);
  696. }
  697. /**
  698. * 获取小程序支付自动化状态
  699. */
  700. getMiniprogramPaymentAutomationStatus(): {
  701. isProcessing: boolean;
  702. processingQueue: string[];
  703. supportedMethods: string[];
  704. } {
  705. return {
  706. isProcessing: this.miniprogramPaymentService.getProcessingStatus(),
  707. processingQueue: this.miniprogramPaymentService.getProcessingQueue(),
  708. supportedMethods: this.miniprogramPaymentService.getSupportedPaymentMethods()
  709. };
  710. }
  711. /**
  712. * 停止小程序支付自动化监听
  713. */
  714. stopMiniprogramPaymentAutomation(): void {
  715. console.log('停止小程序支付自动化监听');
  716. this.miniprogramPaymentService.stopAutomationListener();
  717. }
  718. }