|
@@ -0,0 +1,207 @@
|
|
|
+import { Inject, Logger, Provide } from '@midwayjs/decorator';
|
|
|
+import { BaseService, CoolCommException } from '@cool-midway/core';
|
|
|
+import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
|
+import { Repository } from 'typeorm';
|
|
|
+import * as _ from 'lodash';
|
|
|
+import { KycEntity } from '../entity/kyc';
|
|
|
+import { SunPayService } from './channels/sunpay';
|
|
|
+import { ILogger } from '@midwayjs/logger';
|
|
|
+import { PayService } from './pay';
|
|
|
+import * as moment from 'moment';
|
|
|
+import * as md5 from 'md5';
|
|
|
+
|
|
|
+@Provide()
|
|
|
+export class KycOpenService extends BaseService {
|
|
|
+ @InjectEntityModel(KycEntity)
|
|
|
+ kycEntity: Repository<KycEntity>;
|
|
|
+
|
|
|
+ @Inject()
|
|
|
+ sunPayService: SunPayService
|
|
|
+
|
|
|
+ @Inject()
|
|
|
+ payService: PayService
|
|
|
+
|
|
|
+ @Logger()
|
|
|
+ logger: ILogger;
|
|
|
+
|
|
|
+ async validPremiumParam(payload, files) {
|
|
|
+ if (_.isEmpty(payload.mchId)) {
|
|
|
+ throw new Error('商户编号【mchId】不能为空');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.kycUserId)) {
|
|
|
+ throw new Error('KYC用户ID【kycUserId】不能为空');
|
|
|
+ }
|
|
|
+ if (!files.residentialAddress) {
|
|
|
+ throw new Error('居住地址证明文件【residentialAddress】不能为空');
|
|
|
+ }
|
|
|
+ if (!files.income) {
|
|
|
+ throw new Error('收入证明文件【income】不能为空');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.sign)) {
|
|
|
+ throw new Error('签名【sign】不能为空');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async createOpenPremium(payload, files) {
|
|
|
+ try {
|
|
|
+ this.logger.info('KYC高级认证', JSON.stringify(payload));
|
|
|
+ if(!files) {
|
|
|
+ throw new Error('参数错误,请提交正确参数');
|
|
|
+ }
|
|
|
+ const fileObj = {};
|
|
|
+ files.forEach(item => {
|
|
|
+ fileObj[item.fieldName] = item
|
|
|
+ })
|
|
|
+ await this.validPremiumParam(payload, fileObj);
|
|
|
+ const merchant = await this.payService.validMerchant(payload.mchId);
|
|
|
+ await this.payService.validSign(payload, merchant);
|
|
|
+ const kyc = await this.kycEntity.findOneBy({ kycUserId: payload.kycUserId });
|
|
|
+ if (!kyc.customerId || !kyc) {
|
|
|
+ throw new CoolCommException('KYC user does not exist');
|
|
|
+ }
|
|
|
+ const data = await this.sunPayService.createPremium({
|
|
|
+ customerId: kyc.customerId,
|
|
|
+ }, fileObj);
|
|
|
+ await this.kycEntity.update(kyc.id, { level: '3' });
|
|
|
+ return { kycUserId: payload.kycUserId }
|
|
|
+ } catch (err) {
|
|
|
+ this.logger.error('KYC高级认证提交失败', JSON.stringify(payload), err.message);
|
|
|
+ throw new CoolCommException(err.message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async validAdvanced(payload, files) {
|
|
|
+ if (_.isEmpty(payload.mchId)) {
|
|
|
+ throw new Error('商户编号【mchId】不能为空');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.kycUserId)) {
|
|
|
+ throw new Error('KYC用户ID【kycUserId】不能为空');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.documentType)) {
|
|
|
+ throw new Error('证件类型【documentType】不能为空');
|
|
|
+ }
|
|
|
+ if (+payload.documentType < 0 || +payload.documentType > 2) {
|
|
|
+ throw new Error('证件类型【documentType】取值错误');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.documentNumber)) {
|
|
|
+ throw new Error('证件号码【documentNumber】不能为空');
|
|
|
+ }
|
|
|
+ if (!files.frontSideDocument) {
|
|
|
+ throw new Error('证件正面图片【frontSideDocument】不能为空');
|
|
|
+ }
|
|
|
+ if (!files.backSideDocument) {
|
|
|
+ throw new Error('证件背面图片【backSideDocument】不能为空');
|
|
|
+ }
|
|
|
+ if (!files.customerPhoto) {
|
|
|
+ throw new Error('客户人像图片【customerPhoto】不能为空');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.sign)) {
|
|
|
+ throw new Error('签名【sign】不能为空');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async createOpenAdvanced(payload, files) {
|
|
|
+ try {
|
|
|
+ this.logger.info('KYC进阶认证', JSON.stringify(payload));
|
|
|
+ if(!files) {
|
|
|
+ throw new Error('参数错误,请提交正确参数');
|
|
|
+ }
|
|
|
+ const fileObj = {};
|
|
|
+ files.forEach(item => {
|
|
|
+ fileObj[item.fieldName] = item
|
|
|
+ })
|
|
|
+ await this.validAdvanced(payload, fileObj);
|
|
|
+ const merchant = await this.payService.validMerchant(payload.mchId);
|
|
|
+ await this.payService.validSign(payload, merchant);
|
|
|
+
|
|
|
+ const kyc = await this.kycEntity.findOneBy({ kycUserId: payload.kycUserId });
|
|
|
+ if (!kyc.customerId || !kyc) {
|
|
|
+ throw new CoolCommException('KYC user does not exist');
|
|
|
+ }
|
|
|
+ const data = await this.sunPayService.createAdvanced({
|
|
|
+ customerId: kyc.customerId,
|
|
|
+ documentType: payload.documentType,
|
|
|
+ documentNumber: payload.documentNumber
|
|
|
+ }, fileObj);
|
|
|
+ await this.kycEntity.update(kyc.id, { level: '2' });
|
|
|
+ return { kycUserId: payload.kycUserId }
|
|
|
+ } catch (err) {
|
|
|
+ this.logger.error('KYC进阶认证提交失败', JSON.stringify(payload), err.message);
|
|
|
+ throw new CoolCommException(err.message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async validBasicParam(payload) {
|
|
|
+ if (_.isEmpty(payload.mchId)) {
|
|
|
+ throw new Error('商户编号【mchId】不能为空');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.userId)) {
|
|
|
+ throw new Error('商户平台用户ID【userId】不能为空');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.customerName)) {
|
|
|
+ throw new Error('客户姓名【customerName】不能为空');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.customerEmail)) {
|
|
|
+ throw new Error('客户邮箱地址【customerEmail】不能为空');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.countryCode)) {
|
|
|
+ throw new Error('国家编码【countryCode】不能为空');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.residenceCountry)) {
|
|
|
+ throw new Error('国家编码【residenceCountry】不能为空');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.birthDate)) {
|
|
|
+ throw new Error('出生日期【birthDate】不能为空');
|
|
|
+ }
|
|
|
+ if (!moment(payload.birthDate).isValid()) {
|
|
|
+ throw new Error('出生日期【birthDate】非正确日期格式');
|
|
|
+ }
|
|
|
+ if (_.isEmpty(payload.sign)) {
|
|
|
+ throw new Error('签名【sign】不能为空');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async createOpenBasic(payload) {
|
|
|
+ try {
|
|
|
+ this.logger.info('KYC基础认证', JSON.stringify(payload));
|
|
|
+ await this.validBasicParam(payload);
|
|
|
+ const merchant = await this.payService.validMerchant(payload.mchId);
|
|
|
+ await this.payService.validSign(payload, merchant);
|
|
|
+ const kyc = await this.kycEntity.findOneBy({
|
|
|
+ mchId: payload.mchId,
|
|
|
+ userId: payload.userId,
|
|
|
+ code: 'SUN_CARD',
|
|
|
+ })
|
|
|
+ if (kyc) {
|
|
|
+ throw new Error('当前客户ID已存在,请勿重复提交');
|
|
|
+ }
|
|
|
+ const outUserId = md5(payload.mchId + '_' + payload.userId + 'v2');
|
|
|
+ const { customerId } = await this.sunPayService.createBasic({
|
|
|
+ outUserId,
|
|
|
+ customerName: payload.customerName,
|
|
|
+ customerEmail: payload.customerEmail,
|
|
|
+ countryCode: payload.countryCode,
|
|
|
+ residenceCountry: payload.residenceCountry,
|
|
|
+ birthDate: payload.birthDate,
|
|
|
+ });
|
|
|
+ if (customerId) {
|
|
|
+ await this.kycEntity.insert({
|
|
|
+ userId: payload.userId,
|
|
|
+ mchId: payload.mchId,
|
|
|
+ code: 'SUN_CARD',
|
|
|
+ kycUserId: outUserId,
|
|
|
+ customerId: customerId,
|
|
|
+ level: '1',
|
|
|
+ country: payload.countryCode
|
|
|
+ })
|
|
|
+ return { kycUserId: outUserId }
|
|
|
+ } else {
|
|
|
+ throw new CoolCommException('Network exception, please try again later');
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (err) {
|
|
|
+ this.logger.error('KYC基础认证提交失败', JSON.stringify(payload), err.message);
|
|
|
+ throw new CoolCommException(err.message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|