Kaynağa Gözat

Merge remote-tracking branch 'origin/main'

# Conflicts:
#	src/config/config.max.ts
max 7 ay önce
ebeveyn
işleme
050597f700

+ 7 - 7
src/config/config.max.ts

@@ -9,14 +9,14 @@ export default {
     dataSource: {
       default: {
         type: 'mysql',
-        // host: '192.168.2.101',
-        // port: 6806,
-        // username: 'root',
-        // password: 'admin',
-        host: '127.0.0.1',
-        port: 3306,
+        host: '192.168.2.101',
+        port: 6806,
         username: 'root',
-        password: '12345678',
+        password: 'admin',
+        // host: '127.0.0.1',
+        // port: 3306,
+        // username: 'va',
+        // password: 'FHZ36dP527GacTty',
         database: 'va',
         // 自动建表 注意:线上部署的时候不要使用,有可能导致数据丢失
         synchronize: true,

+ 7 - 0
src/modules/api/controller/customer.ts

@@ -11,6 +11,7 @@ import {
 import { IndividualEntity } from '../../payment/entity/individual';
 import { CustomerService } from '../service/customer';
 import {SunPayAdapter} from "../../payment/adapter/sunpay.adapter";
+import {IndividualService} from "../../payment/service/individual";
 
 /**
  * 客户管理
@@ -30,6 +31,12 @@ export class CustomerController extends BaseController {
   async createCustomer(@Body() params: IndividualEntity) {
     return this.ok(await this.customerService.createCustomer(params));
   }
+
+
+  @Post('/add-individual', { summary: '创建客户' })
+  async addIndividual(@Body() params: IndividualEntity) {
+    return this.ok(await this.customerService.addIndividual(params));
+  }
   // /**
   //  * 获取创建客户必填字段
   //  */

+ 4 - 0
src/modules/api/service/customer.ts

@@ -50,4 +50,8 @@ export class CustomerService extends BaseService {
     return await this.businessService.update(params);
     // TODO 过滤sunpay返回
   }
+  async addIndividual(params) {
+    this.individualService.setIsOpenApi(true)
+    return await this.individualService.add(params);
+  }
 }

+ 14 - 14
src/modules/base/service/sys/user.ts

@@ -121,19 +121,19 @@ export class BaseSysUserService extends BaseService {
     });
 
     // 如果需要获取关联信息,可以分别查询
-    let individualInfo = null;
-    let businessInfo = null;
+    // let individualInfo = null;
+    // let businessInfo = null;
 
-    if (merchant) {
-      // 分别查询个人或企业信息
-      individualInfo = await this.individualEntity.findOne({
-        where: { merchant: { id: merchant.id } },
-      });
-
-      businessInfo = await this.businessEntity.findOne({
-        where: { merchant: { id: merchant.id } },
-      });
-    }
+    // if (merchant) {
+    //   // 分别查询个人或企业信息
+    //   individualInfo = await this.individualEntity.findOneBy({
+    //     merchantId: merchant.mchId
+    //   });
+    //
+    //   businessInfo = await this.businessEntity.findOneBy({
+    //     merchantId: merchant.mchId
+    //   });
+    // }
 
     delete info?.password;
     return {
@@ -141,8 +141,8 @@ export class BaseSysUserService extends BaseService {
       merchant: merchant
         ? {
             ...merchant,
-            individual: individualInfo,
-            business: businessInfo,
+            // individual: individualInfo,
+            // business: businessInfo,
           }
         : null,
     };

+ 4 - 1
src/modules/payment/adapter/sunpay.adapter.ts

@@ -122,12 +122,14 @@ export class SunPayAdapter implements ChannelAdapter {
       // 检查响应
       if (response.data.code !== 200) {
         console.log(response.data);
+        // TODO 移除 SunPay API Error1
         throw new Error(`SunPay API Error1: ${response.data.msg}`);
       }
       return response.data;
     } catch (error) {
       console.log(error);
       if (axios.isAxiosError(error) && error.response) {
+        // TODO 移除 SunPay API Error2
         throw new Error(`SunPay API Error2: ${error.response.data.msg}`);
       }
       throw error;
@@ -337,6 +339,7 @@ export class SunPayAdapter implements ChannelAdapter {
         channel: 'SUNPAY',
       },
     });
+    console.log(340, customer);
     let res = null;
     if (customer) {
       params.customer_id = customer.customer_id;
@@ -404,7 +407,7 @@ export class SunPayAdapter implements ChannelAdapter {
   async payOutOrder(orderNo: string) {
     return this.request('GET', `/Fiat/PayOut/${orderNo}`);
   }
-  
+
   async cancelPayOut(orderNo: string) {
     return this.request('POST', `/Fiat/PayOut/${orderNo}/Cancel`);
   }

+ 13 - 0
src/modules/payment/controller/admin/customer.ts

@@ -0,0 +1,13 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import {CustomerEntity} from "../../entity/customer";
+import {CustomerService} from "../../service/customer";
+
+/**
+ * 支付渠道管理
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: CustomerEntity,
+  service: CustomerService,
+})
+export class AdminPaymentChannelController extends BaseController {}

+ 12 - 3
src/modules/payment/controller/admin/merchant.ts

@@ -1,8 +1,7 @@
 import { MerchantEntity } from './../../entity/merchant';
-import { Body, Get, Inject, Post, Provide } from '@midwayjs/decorator';
+import {Body, Get, Inject, Param, Post, Provide} from '@midwayjs/decorator';
 import { CoolController, BaseController } from '@cool-midway/core';
 import { MerchantService } from '../../service/merchant';
-import { Utils } from '../../../../comm/utils';
 
 @Provide()
 @CoolController({
@@ -25,5 +24,15 @@ import { Utils } from '../../../../comm/utils';
 })
 export class MerchantController extends BaseController {
   @Inject()
-  utils: Utils;
+  merchantService: MerchantService;
+
+  /**
+   * 生成 apiSecret
+   */
+  @Post('/secret', { summary: '生成 apiSecret' })
+  async createSecret(@Body() params: any) {
+    // console.log(34, params)
+    // return this.ok('');
+    return this.ok(await this.merchantService.createSecret(params));
+  }
 }

+ 11 - 4
src/modules/payment/entity/business.ts

@@ -75,10 +75,17 @@ export class BusinessEntity extends BaseEntity {
   trading_country!: string;
   @Column({ comment: '拒绝原因', nullable: true })
   refused?: string;
-  @OneToOne(() => MerchantEntity, {
-    nullable: true, // 允许为空
-    onDelete: 'SET NULL',
-  })
+
+  @Column({ comment: '商户编号' })
+  merchantId!: string;
+
+  @Column({ comment: '用户编号' })
+  customer_id!: string;
+
+  // @OneToOne(() => MerchantEntity, {
+  //   nullable: true, // 允许为空
+  //   onDelete: 'SET NULL',
+  // })
   @JoinColumn()
   merchant?: MerchantEntity;
 }

+ 13 - 4
src/modules/payment/entity/individual.ts

@@ -51,10 +51,19 @@ export class IndividualEntity extends BaseEntity {
   valid_time_end!: Date;
   @Column({ comment: '拒绝原因', nullable: true })
   refused?: string;
-  @OneToOne(() => MerchantEntity, {
-    nullable: true, // 允许为空
-    onDelete: 'SET NULL',
-  })
+
+  @Column({ comment: '商户编号' })
+  merchantId!: string;
+
+  @Column({ comment: '用户编号' })
+  customer_id!: string;
+  //
+  // @OneToOne(() => MerchantEntity, {
+  //   nullable: true, // 允许为空
+  //   onDelete: 'SET NULL',
+  // })
+  // @JoinColumn()
+  // merchant?: MerchantEntity;
   @JoinColumn()
   merchant?: MerchantEntity;
 }

+ 2 - 0
src/modules/payment/entity/wallet.ts

@@ -15,6 +15,8 @@ export class WalletEntity extends BaseEntity {
   channel: string;
   @Column({ comment: '客户ID', length: 100 })
   customerId: string;
+  @Column({ comment: '回调地址'})
+  webhook_url!: string;
   @Column({ comment: '货币类型', length: 20 })
   currency: string;
   @Column({

+ 24 - 6
src/modules/payment/service/business.ts

@@ -4,11 +4,15 @@ import { BaseService } from '@cool-midway/core';
 import { InjectEntityModel } from '@midwayjs/typeorm';
 import { Repository } from 'typeorm';
 import { PaymentService } from './payment';
+import {MerchantEntity} from "../entity/merchant";
 @Provide()
 export class BusinessService extends BaseService {
   @InjectEntityModel(BusinessEntity)
   businessEntity: Repository<BusinessEntity>;
 
+  @InjectEntityModel(MerchantEntity)
+  merchantEntity: Repository<MerchantEntity>;
+
   @Inject()
   paymentService: PaymentService;
   @Inject()
@@ -29,7 +33,7 @@ export class BusinessService extends BaseService {
    * @returns
    */
   async add(param) {
-    let merchantId = this.getMerchantId(param);
+    let merchantId = await this.getMerchantId(param);
     const custom = {
       ...param,
       out_user_id: merchantId,
@@ -39,12 +43,13 @@ export class BusinessService extends BaseService {
     let res = await this.paymentService
       .setChannel('SUNPAY')
       .setCustomerInfo(custom);
-    param.merchant = {
-      id: merchantId,
-    };
+    if (merchantId) {
+      param.merchantId = param?.mch_id || param?.mchId || merchantId
+    }
     await super.add({
       ...param,
       ...param.company,
+      customer_id: res.data.customer_id,
     });
     return res;
   }
@@ -70,14 +75,20 @@ export class BusinessService extends BaseService {
     this._isOpenApi = payload
   }
 
-  getMerchantId(params) {
+  async getMerchantId(params) {
     let merchantId;
     if (this._isOpenApi) {
       merchantId = params.out_user_id;
+    } else if (params?.mch_id || params?.mchId) {
+      // const  merchantInfo = await this.merchantEntity.findOneBy({
+      //   mchId: params?.mch_id || params?.mchId
+      // })
+      merchantId = params?.mch_id || params?.mchId
     } else {
       const { merchant } = this.ctx.admin;
-      merchantId = merchant.id;
+      merchantId = merchant.mchId;
     }
+
     return merchantId
   }
 
@@ -87,4 +98,11 @@ export class BusinessService extends BaseService {
     }
     return this.config.callback.sunpay
   }
+
+
+  async page(params: any) {
+    const merchantId = await this.getMerchantId(params);
+    const query = `SELECT * FROM business WHERE merchantId = '${merchantId}' ORDER BY merchantId ASC`;
+    return this.sqlRenderPage(query, params, false);
+  }
 }

+ 31 - 1
src/modules/payment/service/customer.ts

@@ -1,6 +1,6 @@
 import { IndividualEntity } from './../entity/individual';
 import { BusinessEntity } from './../entity/business';
-import { Init, Provide } from '@midwayjs/decorator';
+import {ALL, Config, Init, Inject, Provide} from '@midwayjs/decorator';
 import { BaseService } from '@cool-midway/core';
 import { InjectEntityModel } from '@midwayjs/typeorm';
 import { Repository } from 'typeorm';
@@ -22,6 +22,10 @@ export class CustomerService extends BaseService {
     await super.init();
     this.setEntity(this.customerEntity);
   }
+  @Config(ALL)
+  config;
+  @Inject()
+  ctx;
 
   /**
    * 描述
@@ -113,6 +117,12 @@ export class CustomerService extends BaseService {
     };
   }
 
+  private _isOpenApi: boolean = false
+
+  setIsOpenApi(payload = false) {
+    this._isOpenApi = payload
+  }
+
   /**
    * 发送请求到 商户 API
    */
@@ -133,4 +143,24 @@ export class CustomerService extends BaseService {
       // throw error;
     }
   }
+
+  async list(params: any = {}) {
+    const merchantId = await this.getMerchantId(params);
+    return await this.customerEntity.findBy({
+      merchantId: `${merchantId}`
+    })
+  }
+
+  private async getMerchantId(params) {
+    let merchantId;
+    if (this._isOpenApi) {
+      merchantId = params.out_user_id;
+    } else if (params?.mch_id || params?.mchId || params?.merchantId) {
+      merchantId = params?.mch_id || params?.mchId || params?.merchantId
+    } else {
+      const { merchant } = this.ctx.admin;
+      merchantId = merchant.mchId;
+    }
+    return merchantId
+  }
 }

+ 20 - 6
src/modules/payment/service/individual.ts

@@ -6,6 +6,7 @@ import { BaseService } from '@cool-midway/core';
 import { InjectEntityModel } from '@midwayjs/typeorm';
 import { Repository } from 'typeorm';
 import { PaymentService } from './payment';
+import {MerchantEntity} from "../entity/merchant";
 @Provide()
 export class IndividualService extends BaseService {
   @InjectEntityModel(IndividualEntity)
@@ -17,6 +18,9 @@ export class IndividualService extends BaseService {
   ctx;
   @InjectEntityModel(CustomerEntity)
   customerEntity: Repository<CustomerEntity>;
+
+  @InjectEntityModel(MerchantEntity)
+  merchantEntity: Repository<MerchantEntity>;
   @Config(ALL)
   config;
   @Init()
@@ -32,7 +36,7 @@ export class IndividualService extends BaseService {
    * @returns
    */
   async add(param) {
-    let merchantId = this.getMerchantId(param);
+    let merchantId = await this.getMerchantId(param);
     const custom = {
       ...param,
       out_user_id: merchantId,
@@ -42,12 +46,11 @@ export class IndividualService extends BaseService {
     let res = await this.paymentService
       .setChannel('SUNPAY')
       .setCustomerInfo(custom);
-    param.merchant = {
-      id: merchantId,
-    };
+    param.merchantId = merchantId
     await super.add({
       ...param,
       ...param.company,
+      customer_id: res.data.customer_id,
     });
     return res;
   }
@@ -69,13 +72,24 @@ export class IndividualService extends BaseService {
     this._isOpenApi = payload
   }
 
-  getMerchantId(params) {
+  async page(params: any) {
+    const merchantId = await this.getMerchantId(params);
+    const query = `SELECT * FROM individual WHERE merchantId = '${merchantId}' ORDER BY merchantId ASC`;
+    return this.sqlRenderPage(query, params, false);
+  }
+
+  async getMerchantId(params) {
     let merchantId;
     if (this._isOpenApi) {
       merchantId = params.out_user_id;
+    } else if (params?.mch_id || params?.mchId) {
+     // const  merchantInfo = await this.merchantEntity.findOneBy({
+     //    mchId: params?.mch_id
+     //  })
+      merchantId = params?.mch_id || params?.mchId
     } else {
       const { merchant } = this.ctx.admin;
-      merchantId = merchant.id;
+      merchantId = merchant.mchId;
     }
     return merchantId
   }

+ 10 - 0
src/modules/payment/service/merchant.ts

@@ -112,4 +112,14 @@ export class MerchantService extends BaseService {
       .digest('hex')
       .toUpperCase();
   }
+
+
+  async createSecret(params: MerchantEntity) {
+    const merchant = await this.merchantEntity.findOneBy({
+      mchId: params.mchId
+    })
+    merchant.apiSecret = this.generateSignature(`${JSON.stringify(params)}`)
+    await this.merchantEntity.save(merchant)
+    return merchant
+  }
 }

+ 22 - 0
src/modules/payment/service/payee.ts

@@ -106,4 +106,26 @@ export class PayeeService extends BaseService {
     }
     return merchant
   }
+
+  async page(params: any) {
+    const merchantId = await this.getMerchantId(params);
+    const query = `SELECT * FROM payee WHERE merchantId = '${merchantId}' ORDER BY merchantId ASC`;
+    return this.sqlRenderPage(query, params, false);
+  }
+
+  async getMerchantId(params) {
+    let merchantId;
+    if (this._isOpenApi) {
+      merchantId = params.out_user_id;
+    } else if (params?.mch_id || params?.mchId) {
+      // const  merchantInfo = await this.merchantEntity.findOneBy({
+      //    mchId: params?.mch_id
+      //  })
+      merchantId = params?.mch_id || params?.mchId
+    } else {
+      const { merchant } = this.ctx.admin;
+      merchantId = merchant.mchId;
+    }
+    return merchantId
+  }
 }

+ 25 - 0
src/modules/payment/service/payee_address.ts

@@ -19,6 +19,13 @@ export class PayeeAddressService extends BaseService {
   paymentService: PaymentService;
   @Inject()
   ctx;
+
+  private _isOpenApi: boolean = false
+
+  setIsOpenApi(payload = false) {
+    this._isOpenApi = payload
+  }
+
   /**
    * 添加收款人
    * @param params
@@ -93,4 +100,22 @@ export class PayeeAddressService extends BaseService {
     });
     return res;
   }
+  async page(params: any) {
+    const merchantId = await this.getMerchantId(params);
+    const query = `SELECT * FROM payee WHERE merchantId = '${merchantId}' ORDER BY merchantId ASC`;
+    return this.sqlRenderPage(query, params, false);
+  }
+
+  async getMerchantId(params) {
+    let merchantId;
+    if (this._isOpenApi) {
+      merchantId = params.out_user_id;
+    } else if (params?.mch_id || params?.mchId) {
+      merchantId = params?.mch_id || params?.mchId
+    } else {
+      const { merchant } = this.ctx.admin;
+      merchantId = merchant.mchId;
+    }
+    return merchantId
+  }
 }

+ 2 - 3
src/modules/payment/service/payment.ts

@@ -47,18 +47,17 @@ export class PaymentService extends BaseService {
   }
   async setCustomerInfo(params: any) {
     const custom: any = {
-      out_user_id: params.merchantId,
+      out_user_id: params.out_user_id,
       webhook_url: params.webhook_url,
       customer_type: params.customer_type,
     };
     delete params.merchantId;
     delete params.webhook_url;
-    delete params.customer_type;
     custom[params.customer_type === 'COMPANY' ? 'company' : 'individual'] = {
       ...params,
     };
+    delete custom[params.customer_type === 'COMPANY' ? 'company' : 'individual'].customer_type;
     const adapter = this.getChannelAdapter(this.channel);
-
     return adapter.setCustomerInfo(custom);
   }
   async createWallet(param: any) {

+ 87 - 19
src/modules/payment/service/wallet.ts

@@ -1,11 +1,12 @@
 import { CustomerEntity } from './../entity/customer';
-import { Init, Inject, Provide } from '@midwayjs/decorator';
+import {ALL, Config, Init, Inject, Provide} from '@midwayjs/decorator';
 import { BaseService, CoolCommException } from '@cool-midway/core';
 import { InjectEntityModel } from '@midwayjs/typeorm';
 import { Repository } from 'typeorm';
 import { WalletEntity } from '../entity/wallet';
 import { PaymentService } from './payment';
 import { MerchantEntity } from '../entity/merchant';
+import axios from "axios";
 /**
  * 描述
  */
@@ -21,24 +22,14 @@ export class WalletService extends BaseService {
   paymentService: PaymentService;
   @Inject()
   ctx;
+  @Config(ALL)
+  config;
   /**
    * 描述
    */
   async add(param: any) {
-    const { userId } = this.ctx.admin;
-    const merchant = await this.merchantEntity.findOne({
-      where: {
-        userId,
-      },
-    });
-    if (!merchant) {
-      throw new CoolCommException('商户不存在');
-    }
-
-    const customer = await this.customerEntity.findOne({
-      where: {
-        merchantId: merchant.id.toString(),
-      },
+    const customer = await this.customerEntity.findOneBy({
+      customer_id: param.customerId
     });
     if (!customer) {
       throw new CoolCommException('客户不存在,请先创建认证');
@@ -51,12 +42,13 @@ export class WalletService extends BaseService {
         .createWallet({
           ...param,
           customerId: customer.customer_id,
+          webhook_url: this.getWebhook_url(param)
         });
       status = res.status;
     }
-
-    param.merchantId = merchant.id;
+    param.merchantId = customer.merchantId;
     param.customerId = customer.customer_id;
+    param.webhook_url = customer.webhook_url;
     param.status = status;
     param.config = {};
     return super.add(param);
@@ -80,12 +72,24 @@ export class WalletService extends BaseService {
       },
     });
     if (!wallet) {
+      // 获取商户的回调
+      await this.request(wallet.webhook_url, {
+        biz_status: 'FAIL',
+        biz_type: 'CREATECUSTOMER',
+        data: data
+      })
       return {
         is_success: false,
         message: '钱包不存在',
       };
     }
     if (wallet.status == 'SUCCESS') {
+      // 获取商户的回调
+      await this.request(wallet.webhook_url, {
+        biz_status: 'SUCCESS',
+        biz_type: 'CREATECUSTOMER',
+        data: data
+      })
       return {
         is_success: true,
         message: '成功',
@@ -97,6 +101,12 @@ export class WalletService extends BaseService {
     });
     wallet.config = res.data;
     await this.walletEntity.save(wallet);
+    // 获取商户的回调
+    await this.request(wallet.webhook_url, {
+      biz_status: 'SUCCESS',
+      biz_type: 'CREATECUSTOMER',
+      data: data
+    })
     return {
       is_success: true,
       message: '成功',
@@ -126,10 +136,12 @@ export class WalletService extends BaseService {
   }
 
   async list(params: any, option: any, connectionName?: any) {
-    const { merchant } = this.ctx.admin;
+    // const { merchant } = this.ctx.admin;
+    const merchantId = await this.getMerchantId(params)
+    console.log(params)
     const res = await this.walletEntity.find({
       where: {
-        merchantId: merchant.id.toString(),
+        merchantId: merchantId,
         channel: params.channel,
         status: 'ACTIVE',
       },
@@ -137,4 +149,60 @@ export class WalletService extends BaseService {
     });
     return res;
   }
+
+  async page(params: any) {
+    const merchantId = await this.getMerchantId(params);
+    console.log(params, merchantId);
+
+    // Manually quote the merchantId (only if absolutely necessary)
+    const query = `SELECT * FROM wallet WHERE merchantId = '${merchantId}' ORDER BY merchantId ASC`;
+
+    return this.sqlRenderPage(query, params, false);
+  }
+
+  private _isOpenApi = false
+
+  setIsOpenApi(payload = false) {
+    this._isOpenApi = payload
+  }
+
+  getWebhook_url(params) {
+    if (this._isOpenApi) {
+      return params.webhook_url
+    }
+    return this.config.callback.sunpay
+  }
+
+  /**
+   * 发送请求到 商户 API
+   */
+  private async request( url, data?: any) {
+    try {
+      if (url) {
+        await axios({
+          method: 'post',
+          url,
+          data
+        });
+      }
+    } catch (error) {
+      console.log(error);
+    }
+  }
+
+  async getMerchantId(params) {
+    let merchantId;
+    if (this._isOpenApi) {
+      merchantId = params.out_user_id;
+    } else if (params?.mch_id || params?.mchId) {
+      // const  merchantInfo = await this.merchantEntity.findOneBy({
+      //    mchId: params?.mch_id
+      //  })
+      merchantId = params?.mch_id || params?.mchId
+    } else {
+      const { merchant } = this.ctx.admin;
+      merchantId = merchant.mchId;
+    }
+    return merchantId
+  }
 }