Browse Source

支付修改完成

test 10 months ago
parent
commit
6b75faa3fb

+ 10 - 0
src/modules/dj/controller/admin/order.ts

@@ -28,4 +28,14 @@ export class OrdertController extends BaseController {
   async notify(@Body('id') id) {
     return this.ok(await this.orderService.notify(id));
   }
+
+  @Post('/code', { summary: '获取订单通道编码' })
+  async code(@Body('id') id) {
+    return this.ok(id);
+  }
+
+  @Post('/mch', { summary: '获取订单商户编码' })
+  async mch(@Body('id') id) {
+    return this.ok(id);
+  }
 }

+ 3 - 1
src/modules/dj/entity/mchChannel.ts

@@ -8,7 +8,6 @@ import { Column, Entity, Index } from 'typeorm';
 export class MchChannelEntity extends BaseEntity {
   @Column({ comment: '商户号' })
   mchId: string;
-  @Index({ unique: true })
 
   @Column({ comment: '支付方式' })
   payType: string;
@@ -16,6 +15,9 @@ export class MchChannelEntity extends BaseEntity {
   @Column({ comment: '通道编码' })
   code: string;
 
+  @Column({ comment: '权重' })
+  weight: number;
+
   @Column({ comment: '状态 0-未启用 1 启用', type: 'tinyint', default: 1 })
   status: number;
 }

+ 3 - 0
src/modules/dj/entity/order.ts

@@ -17,6 +17,9 @@ export class OrderEntity extends BaseEntity {
   @Column({ comment: '交易号', nullable: true })
   traceNo: string;
 
+  @Column({ comment: '支付方式' })
+  payType: string;
+
   @Column({ comment: '通道码' })
   code: string;
 

+ 4 - 4
src/modules/dj/service/channel.ts

@@ -1,7 +1,7 @@
 import { Provide } from '@midwayjs/decorator';
 import { BaseService } from '@cool-midway/core';
 import { InjectEntityModel } from '@midwayjs/typeorm';
-import { Repository } from 'typeorm';
+import { In, Repository } from 'typeorm';
 import * as _ from 'lodash';
 import { ChannelEntity } from '../entity/channel';
 
@@ -19,10 +19,10 @@ export class ChannelService extends BaseService {
     })
   }
 
-  async getOne(code) {
-    return await this.channelEntity.findOneBy({
+  async getByCodes(codes) {
+    return await this.channelEntity.findBy({
       status: 1,
-      code,
+      code: In(codes)
     });
   }
 

+ 8 - 0
src/modules/dj/service/mchChannel.ts

@@ -9,4 +9,12 @@ import { MchChannelEntity } from '../entity/mchChannel';
 export class MchChannelService extends BaseService {
   @InjectEntityModel(MchChannelEntity)
   mchChannelEntity: Repository<MchChannelEntity>;
+
+  async getByMchIdAndType(mchId, payType) {
+    return await this.mchChannelEntity.findBy({
+      mchId,
+      payType,
+      status: 1
+    })
+  }
 }

+ 6 - 10
src/modules/dj/service/order.ts

@@ -110,6 +110,7 @@ export class OrderService extends BaseService {
       mchId: order.mchId,
       type: 1,
       amount: +order.amount - +order.charge,
+      currency: order.currency
     });
     if (notify) {
       // 发起通知
@@ -153,16 +154,7 @@ export class OrderService extends BaseService {
       moment().format('YYYY-MM-DD') + ' 00:00:00',
       moment().format('YYYY-MM-DD') + ' 23:59:59',
     ];
-    // const yestodayTime = [
-    //   moment().subtract(1, 'day').format('YYYY-MM-DD') + ' 00:00:00',
-    //   moment().subtract(1, 'day').format('YYYY-MM-DD') + ' 23:59:59',
-    // ];
-    // const monthTime = [
-    //   moment().startOf('month').format('YYYY-MM-DD') + ' 00:00:00',
-    //   moment().endOf('month').format('YYYY-MM-DD') + ' 23:59:59',
-    // ];
     const data = await Promise.all(
-      // [todayTime, yestodayTime, monthTime].map(item => {
       [todayTime].map(item => {
         return this.nativeQuery(
           `SELECT 
@@ -251,6 +243,7 @@ export class OrderService extends BaseService {
       outOrderNo = '',
       traceNo = '',
       mchId = '',
+      payType = '',
       code = '',
       status = '',
       notifyStatus = '',
@@ -302,6 +295,7 @@ export class OrderService extends BaseService {
           ? this.setSql(mchId, 'and a.mchId = ?', [`${mchId}`])
           : this.setSql(mchId, 'and a.mchId like ?', [`%${mchId}%`])
       }
+      ${this.setSql(payType, 'and a.payType = ?', [payType])}
       ${this.setSql(code, 'and a.code = ?', [code])}
       ${this.setSql(status, 'and a.status = ?', [status])}
       ${this.setSql(notifyStatus, 'and a.notifyStatus = ?', [notifyStatus])}
@@ -320,6 +314,7 @@ export class OrderService extends BaseService {
       outOrderNo = '',
       traceNo = '',
       mchId = '',
+      payType = '',
       code = '',
       status = '',
       notifyStatus = '',
@@ -340,7 +335,7 @@ export class OrderService extends BaseService {
         mchId = '-1';
       }
     }
-    const sql = `SELECT a.id, a.orderNo, a.outOrderNo, a.payUrl, a.traceNo, a.mchId,  a.code, a.amount,${
+    const sql = `SELECT a.id, a.orderNo, a.outOrderNo, a.payUrl, a.traceNo, a.mchId,  a.code, a.payType, a.amount,${
       this.utils.isMerchant(roleIds) ? '' : 'a.channelCharge,'
     } a.charge, a.status, a.notifyStatus, a.userId, a.userIp, a.currency, a.date, a.notifyUrl, a.returnUrl, a.remark, a.createTime, a.updateTime FROM dj_order a WHERE 1=1
       ${this.setSql(orderNo, 'and a.orderNo like ?', [`%${orderNo}%`])}
@@ -351,6 +346,7 @@ export class OrderService extends BaseService {
           ? this.setSql(mchId, 'and a.mchId = ?', [`${mchId}`])
           : this.setSql(mchId, 'and a.mchId like ?', [`%${mchId}%`])
       }
+      ${this.setSql(payType, 'and a.payType = ?', [payType])}
       ${this.setSql(code, 'and a.code = ?', [code])}
       ${this.setSql(status, 'and a.status = ?', [status])}
       ${this.setSql(notifyStatus, 'and a.notifyStatus = ?', [notifyStatus])}

+ 79 - 18
src/modules/dj/service/pay.ts

@@ -10,6 +10,8 @@ import { DispatchService } from './channels/dispatch';
 import { Utils } from '../../../comm/utils';
 import * as md5 from 'md5';
 import { OrderService } from './order';
+import { RateService } from './rate';
+import { MchChannelService } from './mchChannel';
 
 @Provide()
 export class PayService extends BaseService {
@@ -19,6 +21,9 @@ export class PayService extends BaseService {
   @Inject()
   channelService: ChannelService;
 
+  @Inject()
+  mchChannelService: MchChannelService;
+
   @Inject()
   merchantService: MerchantService;
 
@@ -28,6 +33,9 @@ export class PayService extends BaseService {
   @Inject()
   dispatchService: DispatchService;
 
+  @Inject()
+  rateService: RateService;
+
   @Logger()
   logger: ILogger;
 
@@ -38,7 +46,7 @@ export class PayService extends BaseService {
     try {
       this.logger.info('代收查询', JSON.stringify(payload));
       await this.validQueryParam(payload);
-      const merchant = await this.validMerchant(payload);
+      const merchant = await this.validMerchant(payload.mchId);
       await this.validSign(payload, merchant);
       const order = await this.orderService.findByOutOrderNo(
         payload.outOrderNo
@@ -76,19 +84,29 @@ export class PayService extends BaseService {
     try {
       this.logger.info('代收下单', JSON.stringify(payload));
       await this.validParam(payload);
-      const channel = await this.validPayWay(payload);
-      const merchant = await this.validMerchant(payload);
+      const merchant = await this.validMerchant(payload.mchId);
+      const rate = await this.validRate(payload.mchId, payload.payType, payload.currency);
+      const channel = await this.validPayWay(payload.mchId, payload.payType, payload.amount);
       await this.validSign(payload, merchant);
       await this.validOutOrderNo(payload);
+      let channelCharge = (+payload.amount * +channel.rate) / 100 + +channel.basicFee;
+      if(channelCharge < channel.feeMin) {
+        channelCharge = channel.feeMin;
+      }
+      let charge = (+payload.amount * +rate.rate) / 100 + +rate.basicFee;
+      if(charge < rate.feeMin) {
+        charge = rate.feeMin;
+      }
       order = {
         orderNo: this.utils.createOrderNo('DS'),
         outOrderNo: payload.outOrderNo,
         traceNo: '',
+        payType: payload.payType,
         code: channel.code,
         mchId: merchant.mchId,
         amount: payload.amount,
-        channelCharge: (+payload.amount * +channel.rate) / 100,
-        charge: (+payload.amount * +merchant.rate) / 100,
+        channelCharge,
+        charge,
         date: null,
         notifyUrl: payload.notifyUrl,
         returnUrl: payload.returnUrl,
@@ -104,7 +122,7 @@ export class PayService extends BaseService {
         order,
         channel
       );
-      if(isDone) {
+      if (isDone) {
         order.payUrl = payUrl;
         order.traceNo = traceNo;
         await this.orderService.create(order);
@@ -154,28 +172,71 @@ export class PayService extends BaseService {
     //   throw new Error('支付金额【amount】必须为整数');
     // }
     if (_.isEmpty(payload.payType)) {
-      throw new Error('通道码【payType】不能为空');
+      throw new Error('支付方式【payType】不能为空');
     }
     if (_.isEmpty(payload.sign)) {
       throw new Error('签名【sign】不能为空');
     }
   }
 
-  async validPayWay(payload) {
-    const channel = await this.channelService.getOne(payload.payType);
-    if (!channel) {
-      throw new Error('当前通道码不可用');
+  async validRate(mchId, payType, currency) {
+    const rate = await this.rateService.getOne({
+      mchId,
+      payType,
+      currency,
+      type: 1
+    });
+    if (!rate) {
+      throw new Error('商户该支付方式未开通');
+    }
+    return rate;
+  }
+
+  async validPayWay(mchId, payType, amount) {
+    const mchChannels = await this.mchChannelService.getByMchIdAndType(mchId, payType);
+    if (mchChannels.length === 0) {
+      throw new Error('暂无可用支付路由');
     }
-    let max = channel.max || 0;
-    let min = channel.min || 0;
-    if (+payload.amount > +max || +payload.amount < +min) {
-      throw new Error(`单笔最大限额【${+min}, ${+max}】`);
+    let channels = await this.channelService.getByCodes(mchChannels.map(item => item.code));
+    if (channels.length === 0) {
+      throw new Error('暂无可用支付路由');
+    }
+    // 筛选出金额范围符合的,并且计算出所有可用通道的最大金额和最小金额
+    let allMax = 0;
+    let allMin = 0;
+    channels = channels.filter(item => {
+      let max = item.max || 0;
+      let min = item.min || 0;
+      if (item.max > allMax) {
+        allMax = item.max;
+      }
+      if (item.min < allMin) {
+        allMin = 0;
+      }
+      const mchChannel = mchChannels.find(i => i.code === item.code);
+      item['weight'] = mchChannel.weight || 0;
+      return +amount >= +min && +amount <= max
+    })
+    if (channels.length === 0) {
+      throw new Error(`单笔最大限额【${+allMin}, ${+allMax}】`);
+    }
+    let weight = 0;
+    channels.forEach(item => {
+      weight += item['weight']
+    });
+    const ramdon = Math.floor(Math.random() * weight);
+    let totalWeight = 0;
+    for (let i = 0; i < channels.length; i++) {
+      const item = channels[i];
+      totalWeight += item['weight']
+      if (ramdon < totalWeight) {
+        return item;
+      }
     }
-    return channel;
   }
 
-  async validMerchant(payload) {
-    const merchant = await this.merchantService.getByMchId(payload.mchId);
+  async validMerchant(mchId) {
+    const merchant = await this.merchantService.getByMchId(mchId);
     if (!merchant) {
       throw new Error('商户不存在');
     }

+ 13 - 0
src/modules/dj/service/rate.ts

@@ -15,8 +15,21 @@ export class RateService extends BaseService {
   walletService: WalletService;
 
   async add(param) {
+    const data = await this.rateEntity.findOneBy({
+      mchId: param.mchId,
+      payType: param.payType,
+      type: param.type,
+      currency: param.currency
+    })
+    if (data) {
+      throw new Error('已存在相同的费率配置');
+    }
     await this.rateEntity.save(param);
     await this.walletService.createWallet(param.mchId, param.currency)
     return param.id;
   }
+
+  async getOne(where) {
+    return await this.rateEntity.findOneBy(where);
+  }
 }