Jelajahi Sumber

feat: 转账手续费 3-12

max 4 bulan lalu
induk
melakukan
52652d384e

+ 12 - 386
src/modules/api/service/webhook.ts

@@ -1,65 +1,31 @@
 import { BaseService } from '@cool-midway/core';
 import { ILogger, Provide } from '@midwayjs/core';
 import { Inject } from '@midwayjs/decorator';
-import { InjectEntityModel } from '@midwayjs/typeorm';
-import { Repository } from 'typeorm';
-import { CustomerEntity } from '../../payment/entity/customer';
-import { PaymentService } from '../../payment/service/payment';
-import { PayeeEntity } from '../../payment/entity/payee';
-import { SunPayAdapter } from '../../payment/adapter/sunpay.adapter';
-import {
-  OpenPaymentOrderEntity,
-  OrderType,
-} from '../entity/open_payment_order';
-import { WithdrawChannelEntity } from '../entity/withdrawChannel';
-import { OpenAccountEntity } from '../entity/open_account';
-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';
+import { DepositSuccessService } from './webhook_utils/deposit_success';
+import { ExchangeSuccessService } from './webhook_utils/exchange_success';
+import { TransferSuccessService } from './webhook_utils/transfer_success';
 
 /**
  * 描述
  */
 @Provide()
 export class OpenApiWebhookService extends BaseService {
-  @InjectEntityModel(PayeeEntity)
-  payeeEntity: Repository<PayeeEntity>;
-
-  @InjectEntityModel(OpenUserEntity)
-  openUserEntity: Repository<OpenUserEntity>;
-
-  @InjectEntityModel(CustomerEntity)
-  customerEntity: Repository<CustomerEntity>;
-
-  @InjectEntityModel(OpenPaymentOrderEntity)
-  openPaymentOrderEntity: Repository<OpenPaymentOrderEntity>;
-
-  @InjectEntityModel(WithdrawChannelEntity)
-  withdrawChannelEntity: Repository<WithdrawChannelEntity>;
-
-  @InjectEntityModel(OpenAccountEntity)
-  openAccountEntity: Repository<OpenAccountEntity>;
-
-  @Inject()
-  paymentService: PaymentService;
-
   @Inject()
-  applicationsService: applicationsService;
+  webHookCommonService: WebHookCommonService;
 
   @Inject()
-  webHookCommonService: WebHookCommonService;
+  paymentSuccessService: PaymentSuccessService;
 
   @Inject()
-  sunPayAdapter: SunPayAdapter;
+  depositSuccessService: DepositSuccessService;
 
   @Inject()
-  easyPayAdapter: EasyPayAdapter;
+  exchangeSuccessService: ExchangeSuccessService;
 
   @Inject()
-  paymentSuccessService: PaymentSuccessService;
+  transferSuccessService: TransferSuccessService;
 
   @Inject()
   ctx;
@@ -126,75 +92,18 @@ export class OpenApiWebhookService extends BaseService {
           break;
         case 'deposit_success':
           // 入账成功       deposit_success
-          return this.deposit_success(params);
+          return await this.depositSuccessService.run(params);
         case 'exchange_success':
           // 换汇成功       exchange_success
           // 如果换汇成功,则收取手续费
-          return this.exchange_success(params);
+          return await this.exchangeSuccessService.run(params);
         case 'payment_success':
           // 付款成功       payment_success
-          return this.paymentSuccessService.run(params);
-          // 如果付款成功,则收取手续费
-          /*
-          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"
-            }
-          }
-          */
-
-          break;
+          return await this.paymentSuccessService.run(params);
         case 'transfer_success':
           // 转账延迟2.2秒处理
           await this.webHookCommonService.waitByTime(2200);
-          // 转账成功       transfer_success
-          // 如果付款成功,则收取手续费
-          /*
-          params
-          {
-            "type": "string",
-            "data": {
-                "id": "string",
-                "order_no": "string",
-                "request_id": "string",
-                "reference": "string",
-                "from_account_id": "string",
-                "to_account_id": "string",
-                "amount": 0,
-                "currency": "string",
-                "purpose": "string",
-                "status": "PENDING",
-                "reason": "string",
-                "create_time": "string",
-                "update_time": "string",
-                "completed_time": "string"
-            }
-          }
-          */
-          break;
+          return await this.transferSuccessService.run(params);
       }
     } catch (err) {
       this.logger.error(
@@ -207,287 +116,4 @@ export class OpenApiWebhookService extends BaseService {
     this.ctx.body = {};
     return;
   }
-
-  // 入账成功 的手续费处理
-  async deposit_success(params) {
-    // 获取回调用户的详情
-    let accountInfo = null;
-    // 获取回调用户的详情
-    let withdrawChannelFee = null;
-    try {
-      /*
-    2025-03-11 16:58:09.069 INFO 113849 [-/::ffff:127.0.0.1/-/1ms POST /api/open/easypay-webhook/notification] easypay的webhook_notification: params{"type":"deposit_success","data":{"id":"85a2e73b90d94354b14b925c8e23b876","bank_account_id":"7021a5e645574004b5678213f94df8a5","order_no":"20250311165807046795","account_id":"590f080eb299590385c7aa628274e73c","bic_number":null,"account_number":"79765000168","inward_amount":90000,"fee":0,"amount":90000,"currency":"EUR","payer":"付款信息 格式:{sender.name};{sender.address};{sender.country};{sender.account_number} or {sender.iban};{sender.bic};{sender.routing_code};附言","comment":"附言","payment_type":"SWIFT","order_type":"DEPOSIT","payment_id":null,"clearing_system":null,"status":"SUCCESS","create_time":"2025-03-11T16:58:08+08:00","update_time":"2025-03-11T16:58:08+08:00","completed_time":"2025-03-11T16:58:08+08:00"}}
-
-    {
-      "type": "deposit_success",
-      "data": {
-          "id": "29091e03092c42a681f0921118925e84",
-          "bank_account_id": "262874c798b1452682acd96fb0317bae",
-          "order_no": "20250310155503589841",
-          "account_id": "2bd64372841a54bf8b41f879ff07884b",
-          "bic_number": null,
-          "account_number": "79765000155",
-          "inward_amount": 1000,
-          "fee": 0,
-          "amount": 1000,
-          "currency": "GBP",
-          "payer": "付款信息 格式:{sender.name};{sender.address};{sender.country};{sender.account_number} or {sender.iban};{sender.bic};{sender.routing_code};附言",
-          "comment": "附言",
-          "payment_type": "SWIFT",
-          "order_type": "DEPOSIT",
-          "payment_id": null,
-          "clearing_system": null,
-          "status": "SUCCESS",
-          "create_time": "2025-03-10T15:55:04+08:00",
-          "update_time": "2025-03-10T15:55:04+08:00",
-          "completed_time": "2025-03-10T15:55:03+08:00"
-      }
-    }
-    */
-      // 获取回调用户的详情
-      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.DEPOSIT,
-          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.DEPOSIT,
-        });
-      // 记录入账流水
-      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.DEPOSIT,
-        payment_type: params.data.payment_type,
-        order_id: params.data.order_no,
-        fee: withdrawChannelFee,
-        additional_info: {},
-        before_balance: before_balance / 100,
-        balance: balance / 100,
-      };
-      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) {
-      this.logger.error(`记录入账流水失败, ${JSON.stringify(params)}`);
-      this.logger.error(error);
-    }
-  }
-
-  // 换汇成功的回调
-  async exchange_success(params) {
-    try {
-      /*
-        params
-        {
-          "type": "exchange_success",
-          "data": {
-              "id": "13ea4d84b92a4070b55dfafadcafcca3",
-              "order_no": "20250310161942842514",
-              "request_id": null,
-              "reference": null,
-              "account_id": "2bd64372841a54bf8b41f879ff07884b",
-              "sell_currency": "USD",
-              "sell_amount": 2577,
-              "exchange_rate": 0.776169,
-              "buy_amount": 2000,
-              "buy_currency": "GBP",
-              "reason": null,
-              "create_time": "2025-03-10T16:19:42+08:00",
-              "update_time": "2025-03-10T16:20:11+08:00",
-              "completed_time": "2025-03-10T16:20:11+08:00",
-              "status": "SUCCESS",
-              "details_url": null,
-              "detail_status": null,
-              "details_reason": [
-              ]
-          }
-        }
-      */
-
-      // 获取回调用户的详情
-      const 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;
-      }
-
-      // 获取费率信息
-      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.webHookCommonService.getBalanceDiffByCurrency({
-          account_id: params.data.account_id,
-          currency: params.data.buy_currency,
-          amount: params.data.buy_amount,
-          order_type: OrderType.EXCHANGE,
-        });
-
-      // 记录入账流水
-      const openPaymentOrderParams = {
-        mch_id: accountInfo.mch_id,
-        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.sell_currency,
-        amount: params.data.sell_amount / 100,
-        target_currency: params.data.buy_currency,
-        target_amount: params.data.buy_amount / 100,
-        status: params.data.status,
-        order_type: OrderType.EXCHANGE,
-        payment_type: params.data.payment_type,
-        order_id: params.data.order_no,
-        fee: withdrawChannelFee,
-        additional_info: {},
-        before_balance: before_balance / 100,
-        balance: balance / 100,
-      };
-      await this.openPaymentOrderEntity.insert(openPaymentOrderParams);
-      this.logger.info(
-        `记录换汇流水, ${JSON.stringify(openPaymentOrderParams)}`
-      );
-      // 通知上游之后,间隔10秒执行利润截取操作
-      Promise.resolve().then(async () => {
-        await this.webHookCommonService.waitByTime(10000);
-        //  收取手续费: 换汇
-        // /v1/transfers
-        const transfers_params = {
-          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.buy_currency, // 收取买入的币种费用
-          target_amount: params.data.buy_amount / 100,
-          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: transfers_params.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) {
-      this.logger.error(`记录换汇流水失败, ${JSON.stringify(params)}`);
-      this.logger.error(error);
-    }
-  }
 }

+ 176 - 0
src/modules/api/service/webhook_utils/deposit_success.ts

@@ -0,0 +1,176 @@
+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 DepositSuccessService 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;
+    try {
+      /*
+        2025-03-11 16:58:09.069 INFO 113849 [-/::ffff:127.0.0.1/-/1ms POST /api/open/easypay-webhook/notification] easypay的webhook_notification: params{"type":"deposit_success","data":{"id":"85a2e73b90d94354b14b925c8e23b876","bank_account_id":"7021a5e645574004b5678213f94df8a5","order_no":"20250311165807046795","account_id":"590f080eb299590385c7aa628274e73c","bic_number":null,"account_number":"79765000168","inward_amount":90000,"fee":0,"amount":90000,"currency":"EUR","payer":"付款信息 格式:{sender.name};{sender.address};{sender.country};{sender.account_number} or {sender.iban};{sender.bic};{sender.routing_code};附言","comment":"附言","payment_type":"SWIFT","order_type":"DEPOSIT","payment_id":null,"clearing_system":null,"status":"SUCCESS","create_time":"2025-03-11T16:58:08+08:00","update_time":"2025-03-11T16:58:08+08:00","completed_time":"2025-03-11T16:58:08+08:00"}}
+    
+        {
+          "type": "deposit_success",
+          "data": {
+              "id": "29091e03092c42a681f0921118925e84",
+              "bank_account_id": "262874c798b1452682acd96fb0317bae",
+              "order_no": "20250310155503589841",
+              "account_id": "2bd64372841a54bf8b41f879ff07884b",
+              "bic_number": null,
+              "account_number": "79765000155",
+              "inward_amount": 1000,
+              "fee": 0,
+              "amount": 1000,
+              "currency": "GBP",
+              "payer": "付款信息 格式:{sender.name};{sender.address};{sender.country};{sender.account_number} or {sender.iban};{sender.bic};{sender.routing_code};附言",
+              "comment": "附言",
+              "payment_type": "SWIFT",
+              "order_type": "DEPOSIT",
+              "payment_id": null,
+              "clearing_system": null,
+              "status": "SUCCESS",
+              "create_time": "2025-03-10T15:55:04+08:00",
+              "update_time": "2025-03-10T15:55:04+08:00",
+              "completed_time": "2025-03-10T15:55:03+08:00"
+          }
+        }
+        */
+      // 获取回调用户的详情
+      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.DEPOSIT,
+          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.DEPOSIT,
+        });
+      // 记录入账流水
+      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.DEPOSIT,
+        payment_type: params.data.payment_type,
+        order_id: params.data.order_no,
+        fee: withdrawChannelFee,
+        additional_info: {},
+        before_balance: before_balance / 100,
+        balance: balance / 100,
+      };
+      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) {
+      this.logger.error(`记录入账流水失败, ${JSON.stringify(params)}`);
+      this.logger.error(error);
+    }
+  }
+}

+ 169 - 0
src/modules/api/service/webhook_utils/exchange_success.ts

@@ -0,0 +1,169 @@
+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 ExchangeSuccessService extends BaseService {
+  @Inject()
+  webHookCommonService: WebHookCommonService;
+
+  @InjectEntityModel(OpenPaymentOrderEntity)
+  openPaymentOrderEntity: Repository<OpenPaymentOrderEntity>;
+
+  @Inject()
+  ctx;
+
+  @Inject()
+  logger: ILogger;
+
+  @Inject()
+  easyPayAdapter: EasyPayAdapter;
+
+  async run(params) {
+    try {
+      /*
+        params
+        {
+          "type": "exchange_success",
+          "data": {
+              "id": "13ea4d84b92a4070b55dfafadcafcca3",
+              "order_no": "20250310161942842514",
+              "request_id": null,
+              "reference": null,
+              "account_id": "2bd64372841a54bf8b41f879ff07884b",
+              "sell_currency": "USD",
+              "sell_amount": 2577,
+              "exchange_rate": 0.776169,
+              "buy_amount": 2000,
+              "buy_currency": "GBP",
+              "reason": null,
+              "create_time": "2025-03-10T16:19:42+08:00",
+              "update_time": "2025-03-10T16:20:11+08:00",
+              "completed_time": "2025-03-10T16:20:11+08:00",
+              "status": "SUCCESS",
+              "details_url": null,
+              "detail_status": null,
+              "details_reason": [
+              ]
+          }
+        }
+      */
+
+      // 获取回调用户的详情
+      const 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;
+      }
+
+      // 获取费率信息
+      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.webHookCommonService.getBalanceDiffByCurrency({
+          account_id: params.data.account_id,
+          currency: params.data.buy_currency,
+          amount: params.data.buy_amount,
+          order_type: OrderType.EXCHANGE,
+        });
+
+      // 记录入账流水
+      const openPaymentOrderParams = {
+        mch_id: accountInfo.mch_id,
+        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.sell_currency,
+        amount: params.data.sell_amount / 100,
+        target_currency: params.data.buy_currency,
+        target_amount: params.data.buy_amount / 100,
+        status: params.data.status,
+        order_type: OrderType.EXCHANGE,
+        payment_type: params.data.payment_type,
+        order_id: params.data.order_no,
+        fee: withdrawChannelFee,
+        additional_info: {},
+        before_balance: before_balance / 100,
+        balance: balance / 100,
+      };
+      await this.openPaymentOrderEntity.insert(openPaymentOrderParams);
+      this.logger.info(
+        `记录换汇流水, ${JSON.stringify(openPaymentOrderParams)}`
+      );
+      // 通知上游之后,间隔10秒执行利润截取操作
+      Promise.resolve().then(async () => {
+        await this.webHookCommonService.waitByTime(10000);
+        //  收取手续费: 换汇
+        // /v1/transfers
+        const transfers_params = {
+          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.buy_currency, // 收取买入的币种费用
+          target_amount: params.data.buy_amount / 100,
+          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: transfers_params.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) {
+      this.logger.error(`记录换汇流水失败, ${JSON.stringify(params)}`);
+      this.logger.error(error);
+    }
+  }
+}

+ 196 - 0
src/modules/api/service/webhook_utils/transfer_success.ts

@@ -0,0 +1,196 @@
+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 TransferSuccessService 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;
+    try {
+      /*
+        2025-03-11 16:58:09.069 INFO 113849 [-/::ffff:127.0.0.1/-/1ms POST /api/open/easypay-webhook/notification] easypay的webhook_notification: params{"type":"deposit_success","data":{"id":"85a2e73b90d94354b14b925c8e23b876","bank_account_id":"7021a5e645574004b5678213f94df8a5","order_no":"20250311165807046795","account_id":"590f080eb299590385c7aa628274e73c","bic_number":null,"account_number":"79765000168","inward_amount":90000,"fee":0,"amount":90000,"currency":"EUR","payer":"付款信息 格式:{sender.name};{sender.address};{sender.country};{sender.account_number} or {sender.iban};{sender.bic};{sender.routing_code};附言","comment":"附言","payment_type":"SWIFT","order_type":"DEPOSIT","payment_id":null,"clearing_system":null,"status":"SUCCESS","create_time":"2025-03-11T16:58:08+08:00","update_time":"2025-03-11T16:58:08+08:00","completed_time":"2025-03-11T16:58:08+08:00"}}
+    
+       // 转账成功       transfer_success
+          // 如果付款成功,则收取手续费
+          /*
+          params
+          {
+            "type": "string",
+            "data": {
+                "id": "string",
+                "order_no": "string",
+                "request_id": "string",
+                "reference": "string",
+                "from_account_id": "string",
+                "to_account_id": "string",
+                "amount": 0,
+                "currency": "string",
+                "purpose": "string",
+                "status": "PENDING",
+                "reason": "string",
+                "create_time": "string",
+                "update_time": "string",
+                "completed_time": "string"
+            }
+          }
+        */
+      // 获取回调用户的详情
+      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.TRANSFER,
+          channel: 'EASYPAY',
+          amount: params.data.amount,
+          mch_id: accountInfo.mch_id,
+        });
+
+      // 注意避免重复截取利润, 如果是手续费直接忽略,只需更新订单谢谢即可
+      const isDuplicateOrder = this.isDuplicateOrder(params.data.id);
+      if(isDuplicateOrder) {
+        const res = await this.openPaymentOrderEntity.save({
+          where: {
+            
+          },
+        });
+        this.ctx.status = 200;
+        this.ctx.body = {};
+        return;
+      }
+      // 获取余额
+      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.TRANSFER,
+        });
+
+      // 记录入账流水
+      const openPaymentOrderParams = {
+        mch_id: accountInfo.mch_id,
+        amount: params.data.amount / 100,
+        account_id: params.data.account_id,
+        from_account_id: params.data.from_account_id,
+        to_account_id: params.data.to_account_id,
+        event_id: params.data.id,
+        currency: params.data.currency,
+        status: params.data.status,
+        order_type: OrderType.TRANSFER,
+        payment_type: params.data.payment_type,
+        order_id: params.data.order_no,
+        fee: withdrawChannelFee,
+        additional_info: {},
+        before_balance: before_balance / 100,
+        balance: balance / 100,
+      };
+      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) {
+      this.logger.error(`记录入账流水失败, ${JSON.stringify(params)}`);
+      this.logger.error(error);
+    }
+  }
+  // 根据 event_id 判断是否有重复订单
+  async isDuplicateOrder(event_id) {
+    const res = await this.openPaymentOrderEntity.findOne({
+      where: {
+        event_id,
+      },
+    });
+    return res
+  }
+}