Jelajahi Sumber

feat: 付款手续费 3-12

max 4 bulan lalu
induk
melakukan
4583cbd573

+ 6 - 0
src/modules/api/entity/open_payment_order.ts

@@ -50,6 +50,12 @@ export class OpenPaymentOrderEntity extends BaseEntity {
 
   @Column({ comment: '手续费', type: 'decimal', precision: 20, scale: 6, default: 0 })
   fee?: number;
+  
+  @Column({ comment: '渠道手续费', type: 'decimal', precision: 20, scale: 6, default: 0 })
+  currency_fee?: number;
+
+  @Column({ comment: '汇率', type: 'decimal', precision: 20, scale: 6, default: 0 })
+  exchange_rate?: number;
 
   @Column({ length: 100, comment: 'credit or debit', default: '' })
   type?: string;

+ 56 - 108
src/modules/api/service/webhook.ts

@@ -17,6 +17,8 @@ import { EasyPayAdapter } from '../../payment/adapter/easypay.adapter';
 import * as md5 from 'md5';
 import { OpenUserEntity } from '../entity/open_user';
 import { applicationsService } from './admin/applications';
+import { PaymentSuccessService } from './webhook_utils/payment_success';
+import { WebHookCommonService } from './webhook_utils/common';
 
 /**
  * 描述
@@ -47,12 +49,18 @@ export class OpenApiWebhookService extends BaseService {
   @Inject()
   applicationsService: applicationsService;
 
+  @Inject()
+  webHookCommonService: WebHookCommonService;
+
   @Inject()
   sunPayAdapter: SunPayAdapter;
 
   @Inject()
   easyPayAdapter: EasyPayAdapter;
 
+  @Inject()
+  paymentSuccessService: PaymentSuccessService;
+
   @Inject()
   ctx;
 
@@ -125,6 +133,7 @@ export class OpenApiWebhookService extends BaseService {
           return this.exchange_success(params);
         case 'payment_success':
           // 付款成功       payment_success
+          return this.paymentSuccessService.run(params);
           // 如果付款成功,则收取手续费
           /*
           params
@@ -160,7 +169,7 @@ export class OpenApiWebhookService extends BaseService {
           break;
         case 'transfer_success':
           // 转账延迟2.2秒处理
-          await this.waitByTime(2200);
+          await this.webHookCommonService.waitByTime(2200);
           // 转账成功       transfer_success
           // 如果付款成功,则收取手续费
           /*
@@ -193,21 +202,12 @@ export class OpenApiWebhookService extends BaseService {
       );
     }
     // 转账延迟4秒处理
-    await this.waitByTime(4000);
+    await this.webHookCommonService.waitByTime(4000);
     this.ctx.status = 400;
     this.ctx.body = {};
     return;
   }
 
-  // 定时器
-  waitByTime(settime = 100) {
-    return new Promise((resolve: any) => {
-      setTimeout(() => {
-        resolve();
-      }, settime);
-    });
-  }
-
   // 入账成功 的手续费处理
   async deposit_success(params) {
     // 获取回调用户的详情
@@ -245,33 +245,37 @@ export class OpenApiWebhookService extends BaseService {
     }
     */
       // 获取回调用户的详情
-      accountInfo = await this.getAccountInfo(params.data.account_id);
+      accountInfo = await this.webHookCommonService.getAccountInfo(
+        params.data.account_id
+      );
       if (!accountInfo) {
         // TODO 如果不存在的话,则为白标用户
         // 转账延迟4秒处理
-        await this.waitByTime(4000);
+        await this.webHookCommonService.waitByTime(4000);
         this.ctx.status = 400;
         this.ctx.body = {};
         return;
       }
 
       // 获取费率信息
-      withdrawChannelFee = await this.getWithdrawChannelFee({
-        account_id: params.data.account_id,
-        currency: params.data.currency,
-        order_type: 'DEPOSIT',
-        channel: 'EASYPAY',
-        amount: params.data.amount,
-        mch_id: accountInfo.mch_id,
-      });
-      // 查询用户的资金
+      withdrawChannelFee =
+        await this.webHookCommonService.getWithdrawChannelFee({
+          account_id: params.data.account_id,
+          currency: params.data.currency,
+          order_type: OrderType.DEPOSIT,
+          channel: 'EASYPAY',
+          amount: params.data.amount,
+          mch_id: accountInfo.mch_id,
+        });
 
       // 获取余额
-      const { before_balance, balance } = await this.getBalanceDiffByCurrency({
-        account_id: params.data.account_id,
-        currency: params.data.currency,
-        amount: params.data.amount,
-      });
+      const { before_balance, balance } =
+        await this.webHookCommonService.getBalanceDiffByCurrency({
+          account_id: params.data.account_id,
+          currency: params.data.currency,
+          amount: params.data.amount,
+          order_type: OrderType.DEPOSIT,
+        });
       // 记录入账流水
       const openPaymentOrderParams = {
         mch_id: accountInfo.mch_id,
@@ -294,11 +298,9 @@ export class OpenApiWebhookService extends BaseService {
       this.logger.info(
         `记录入账流水, ${JSON.stringify(openPaymentOrderParams)}`
       );
-      this.ctx.status = 200;
-      this.ctx.body = {};
       // 通知上游之后,间隔10秒执行利润截取操作
       Promise.resolve().then(async () => {
-        await this.waitByTime(10000);
+        await this.webHookCommonService.waitByTime(10000);
         let accountInfo = null;
         // 获取回调用户的详情
         let withdrawChannelFee = null;
@@ -342,6 +344,8 @@ export class OpenApiWebhookService extends BaseService {
           });
         }
       });
+      this.ctx.status = 200;
+      this.ctx.body = {};
       return;
     } catch (error) {
       this.logger.error(`记录入账流水失败, ${JSON.stringify(params)}`);
@@ -381,32 +385,37 @@ export class OpenApiWebhookService extends BaseService {
       */
 
       // 获取回调用户的详情
-      const accountInfo = await this.getAccountInfo(params.data.account_id);
+      const accountInfo = await this.webHookCommonService.getAccountInfo(
+        params.data.account_id
+      );
       if (!accountInfo) {
         // TODO 如果不存在的话,暂时不处理
         // 转账延迟4秒处理
-        await this.waitByTime(4000);
+        await this.webHookCommonService.waitByTime(4000);
         this.ctx.status = 400;
         this.ctx.body = {};
         return;
       }
 
       // 获取费率信息
-      const withdrawChannelFee = await this.getWithdrawChannelFee({
-        account_id: params.data.account_id,
-        currency: params.data.buy_currency,
-        order_type: 'EXCHANGE',
-        channel: 'EASYPAY',
-        amount: params.data.buy_amount,
-        mch_id: accountInfo.mch_id,
-      });
+      const withdrawChannelFee =
+        await this.webHookCommonService.getWithdrawChannelFee({
+          account_id: params.data.account_id,
+          currency: params.data.buy_currency,
+          order_type: OrderType.EXCHANGE,
+          channel: 'EASYPAY',
+          amount: params.data.buy_amount,
+          mch_id: accountInfo.mch_id,
+        });
 
       // 获取余额
-      const { before_balance, balance } = await this.getBalanceDiffByCurrency({
-        account_id: params.data.account_id,
-        currency: params.data.buy_currency,
-        amount: params.data.buy_amount,
-      });
+      const { before_balance, balance } =
+        await this.webHookCommonService.getBalanceDiffByCurrency({
+          account_id: params.data.account_id,
+          currency: params.data.buy_currency,
+          amount: params.data.buy_amount,
+          order_type: OrderType.EXCHANGE,
+        });
 
       // 记录入账流水
       const openPaymentOrderParams = {
@@ -434,7 +443,7 @@ export class OpenApiWebhookService extends BaseService {
       );
       // 通知上游之后,间隔10秒执行利润截取操作
       Promise.resolve().then(async () => {
-        await this.waitByTime(10000);
+        await this.webHookCommonService.waitByTime(10000);
         //  收取手续费: 换汇
         // /v1/transfers
         const transfers_params = {
@@ -472,7 +481,7 @@ export class OpenApiWebhookService extends BaseService {
           fee: 0,
           additional_info: {},
         });
-      })
+      });
       this.ctx.status = 200;
       this.ctx.body = {};
       return;
@@ -481,65 +490,4 @@ export class OpenApiWebhookService extends BaseService {
       this.logger.error(error);
     }
   }
-
-  // 如果查询都是空的延迟处理
-  async getAccountInfo(account_id) {
-    const openAccount = await this.openAccountEntity.findOne({
-      where: {
-        account_id,
-      },
-    });
-    if (openAccount) {
-      return openAccount;
-    }
-    const openUser = await this.openUserEntity.findOne({
-      where: {
-        account_id,
-      },
-    });
-    if (openUser) {
-      return openUser;
-    }
-    return null;
-  }
-
-  async getWithdrawChannelFee({
-    account_id,
-    currency,
-    order_type,
-    channel,
-    amount,
-    mch_id,
-  }) {
-    const withdrawChannel = await this.withdrawChannelEntity.findOne({
-      where: {
-        // account_id: account_id,
-        channel,
-        mch_id: mch_id,
-        order_type,
-        currency: currency,
-        status: 1,
-      },
-    });
-    // 费率
-    const fee = (Number.parseInt(withdrawChannel.rate) / 100) * (amount / 100); // 费率费用
-    // 单笔固定费用
-    const basicFee = withdrawChannel.basicFee;
-    // 单笔最低费用
-    const feeMin = withdrawChannel.feeMin;
-    return Math.max(fee, basicFee, feeMin); // 取最大值
-  }
-  // 获取流水记录前后的余额差异
-
-  async getBalanceDiffByCurrency({ account_id, currency, amount }) {
-    const userBalance =
-      await this.applicationsService.getAccountsBalancesByCurrency(
-        account_id,
-        currency
-      );
-    return {
-      before_balance: userBalance,
-      balance: userBalance + amount,
-    };
-  }
 }

+ 105 - 0
src/modules/api/service/webhook_utils/common.ts

@@ -0,0 +1,105 @@
+import { BaseService } from '@cool-midway/core';
+import { Inject, Provide } from '@midwayjs/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { OpenAccountEntity } from '../../entity/open_account';
+import { Repository } from 'typeorm';
+import { OpenUserEntity } from '../../entity/open_user';
+import { WithdrawChannelEntity } from '../../entity/withdrawChannel';
+import { applicationsService } from '../admin/applications';
+import { OrderType } from '../../entity/open_payment_order';
+
+/**
+ * webhook的公共方法
+ */
+@Provide()
+export class WebHookCommonService extends BaseService {
+  @InjectEntityModel(OpenAccountEntity)
+  openAccountEntity: Repository<OpenAccountEntity>;
+
+  @InjectEntityModel(OpenUserEntity)
+  openUserEntity: Repository<OpenUserEntity>;
+
+  @InjectEntityModel(WithdrawChannelEntity)
+  withdrawChannelEntity: Repository<WithdrawChannelEntity>;
+
+  @Inject()
+  applicationsService: applicationsService;
+
+  // 如果查询都是空的延迟处理
+  async getAccountInfo(account_id) {
+    const openAccount = await this.openAccountEntity.findOne({
+      where: {
+        account_id,
+      },
+    });
+    if (openAccount) {
+      return openAccount;
+    }
+    const openUser = await this.openUserEntity.findOne({
+      where: {
+        account_id,
+      },
+    });
+    if (openUser) {
+      return openUser;
+    }
+    return null;
+  }
+
+  async getWithdrawChannelFee({
+    account_id,
+    currency,
+    order_type,
+    channel,
+    amount,
+    mch_id,
+  }) {
+    // 注意 分 和 元 的处理
+    const withdrawChannel = await this.withdrawChannelEntity.findOne({
+      where: {
+        // account_id: account_id,
+        channel,
+        mch_id: mch_id,
+        order_type,
+        currency: currency,
+        status: 1,
+      },
+    });
+    // 费率
+    const fee = (Number.parseInt(withdrawChannel.rate) / 100) * (amount / 100); // 费率费用
+    // 单笔固定费用
+    const basicFee = withdrawChannel.basicFee;
+    // 单笔最低费用
+    const feeMin = withdrawChannel.feeMin;
+    return Math.max(fee, basicFee, feeMin); // 取最大值
+  }
+
+  // 获取流水记录前后的余额差异
+  async getBalanceDiffByCurrency({ account_id, currency, amount, order_type }) {
+    const userBalance =
+      await this.applicationsService.getAccountsBalancesByCurrency(
+        account_id,
+        currency
+      );
+     let balance = 0;
+     // 付款和转账的余额是减少的
+     if(order_type === OrderType.PAYMENT || order_type === OrderType.TRANSFER ) {
+        balance = userBalance - amount
+     } else {
+        balance = userBalance + amount
+     }
+    return {
+      before_balance: userBalance,
+      balance: balance,
+    };
+  }
+
+  // 定时器
+  waitByTime(settime = 100) {
+    return new Promise((resolve: any) => {
+      setTimeout(() => {
+        resolve();
+      }, settime);
+    });
+  }
+}

+ 179 - 0
src/modules/api/service/webhook_utils/payment_success.ts

@@ -0,0 +1,179 @@
+import { BaseService } from '@cool-midway/core';
+import { ILogger, Inject, Provide } from '@midwayjs/core';
+import { WebHookCommonService } from './common';
+import {
+  OpenPaymentOrderEntity,
+  OrderType,
+} from '../../entity/open_payment_order';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { EasyPayAdapter } from '../../../payment/adapter/easypay.adapter';
+import * as md5 from 'md5';
+
+/**
+ * 付款成功
+ */
+@Provide()
+export class PaymentSuccessService extends BaseService {
+  @Inject()
+  webHookCommonService: WebHookCommonService;
+
+  @InjectEntityModel(OpenPaymentOrderEntity)
+  openPaymentOrderEntity: Repository<OpenPaymentOrderEntity>;
+
+  @Inject()
+  ctx;
+
+  @Inject()
+  logger: ILogger;
+
+  @Inject()
+  easyPayAdapter: EasyPayAdapter;
+
+  async run(params) {
+    // 获取回调用户的详情
+    let accountInfo = null;
+    // 获取回调用户的详情
+    let withdrawChannelFee = null;
+    // 如果付款成功,则收取手续费
+    /*
+          params
+          {
+            "type": "string",
+            "data": {
+                "id": "string",
+                "order_no": "string",
+                "request_id": "string",
+                "reference": "string",
+                "account_id": "string",
+                "currency": "string",
+                "amount": 0,
+                "payer": {},
+                "beneficiary": {},
+                "exchange_rate": 0,
+                "fee": 0,
+                "fee_currency": "string",
+                "outward_currency": "string",
+                "outward_amount": 0,
+                "comment": "string",
+                "purpose": "string",
+                "status": "PENDING",
+                "reason": "string",
+                "source_of_funds ": "INVESTMENT",
+                "create_time": "string",
+                "update_time": "string",
+                "completed_time": "string"
+            }
+          }
+          */
+    try {
+      // 获取回调用户的详情
+      accountInfo = await this.webHookCommonService.getAccountInfo(
+        params.data.account_id
+      );
+      if (!accountInfo) {
+        // TODO 如果不存在的话,则为白标用户
+        // 转账延迟4秒处理
+        await this.webHookCommonService.waitByTime(4000);
+        this.ctx.status = 400;
+        this.ctx.body = {};
+        return;
+      }
+      // 获取费率信息
+      withdrawChannelFee =
+        await this.webHookCommonService.getWithdrawChannelFee({
+          account_id: params.data.account_id,
+          currency: params.data.currency,
+          order_type: OrderType.PAYMENT,
+          channel: 'EASYPAY',
+          amount: params.data.amount,
+          mch_id: accountInfo.mch_id,
+        });
+
+      // 获取余额
+      const { before_balance, balance } =
+        await this.webHookCommonService.getBalanceDiffByCurrency({
+          account_id: params.data.account_id,
+          currency: params.data.currency,
+          amount: params.data.amount,
+          order_type: OrderType.PAYMENT,
+        });
+
+      // 记录付款流水
+      const openPaymentOrderParams = {
+        mch_id: accountInfo.mch_id,
+        amount: params.data.amount / 100,
+        account_id: params.data.account_id,
+        from_account_id: params.data.account_id,
+        to_account_id: params.data.account_id,
+        event_id: params.data.id,
+        currency: params.data.currency,
+        status: params.data.status,
+        order_type: OrderType.PAYMENT,
+        payment_type: params.data.payment_type,
+        order_id: params.data.order_no,
+        fee: withdrawChannelFee,
+        additional_info: {},
+        before_balance: before_balance / 100,
+        balance: balance / 100,
+        currency_fee: params.data.fee, // 渠道手续费
+        exchange_rate: params.data.exchange_rate, // 交易时的汇率
+      };
+      await this.openPaymentOrderEntity.insert(openPaymentOrderParams);
+      this.logger.info(
+        `记录付款流水, ${JSON.stringify(openPaymentOrderParams)}`
+      );
+      // 通知上游之后,间隔10秒执行利润截取操作
+      Promise.resolve().then(async () => {
+        await this.webHookCommonService.waitByTime(10000);
+        let accountInfo = null;
+        // 获取回调用户的详情
+        let withdrawChannelFee = null;
+        if (accountInfo && withdrawChannelFee) {
+          // 收取手续费: 转账
+          // /v1/transfers
+          const transfers_params = {
+            // ...openOrderObj,
+            request_id: md5(`${accountInfo.mch_id}_${params.data.id}`),
+            from_account_id: params.data.account_id,
+            to_account_id: this.easyPayAdapter.baseInfo.account_id,
+            currency: params.data.currency,
+            amount: withdrawChannelFee * 100,
+            purpose: '收取手续费用',
+          };
+          this.logger.info(
+            `记录入账流水的费率, ${JSON.stringify(transfers_params)}`
+          );
+          // 截取流水的转账
+          const res = await this.easyPayAdapter.request(
+            'POST',
+            '/v1/transfers',
+            transfers_params
+          );
+          // 记录入账手续费的流水
+          await this.openPaymentOrderEntity.insert({
+            request_id: transfers_params.request_id,
+            mch_id: accountInfo.mch_id,
+            amount: withdrawChannelFee,
+            account_id: params.data.account_id,
+            from_account_id: params.data.account_id,
+            to_account_id: this.easyPayAdapter.baseInfo.account_id,
+            event_id: params.data.id,
+            currency: params.data.currency,
+            status: params.data.status,
+            order_type: OrderType.TRANSACTION_FEE_ORDER,
+            payment_type: params.data.payment_type,
+            order_id: res.data.order_no, // 这里是转账的订单编号
+            fee: 0,
+            additional_info: {},
+          });
+        }
+      });
+      this.ctx.status = 200;
+      this.ctx.body = {};
+      return;
+    } catch (error) {}
+
+    return params;
+  }
+}