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; @Inject() sunPayService: SunPayService @Inject() payService: PayService @Logger() logger: ILogger; async validGetCustomer(payload) { if (_.isEmpty(payload.mchId)) { throw new Error('商户编号【mchId】不能为空'); } if (_.isEmpty(payload.userId)) { throw new Error('商户平台用户ID【userId】不能为空'); } } async getCustomer(payload) { try { this.logger.info('获取客户信息', JSON.stringify(payload)); await this.validGetCustomer(payload); const merchant = await this.payService.validMerchant(payload.mchId); await this.payService.validSign(payload, merchant); let kyc = await this.kycEntity.findOneBy({ mchId: payload.mchId, userId: payload.userId, code: 'SUN_CARD', }) if (kyc && kyc.customerId) { return { mchId: kyc.mchId, userId: kyc.mchId, kycUserId: kyc.userId, country: kyc.country, level: kyc.level, email: kyc.email } } const outUserId = md5(payload.mchId + '_' + payload.userId + 'v2'); const data = await this.sunPayService.queryKyc(outUserId); const newKyc = { userId: payload.userId, mchId: payload.mchId, code: 'SUN_CARD', kycUserId: data.kycUserId, customerId: data.customerId, level: '1', country: data.countryCode, email: data.customerEmail } await this.kycEntity.insert(kyc) return { mchId: newKyc.mchId, userId: newKyc.mchId, kycUserId: newKyc.userId, country: newKyc.country, email: newKyc.email, level: newKyc.level } } catch (err) { this.logger.error('获取客户信息', JSON.stringify(payload), err.message); throw new CoolCommException(err.message); } } 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 || !kyc.customerId) { throw new CoolCommException('KYC用户不存在'); } 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 || !kyc.customerId) { throw new CoolCommException('KYC用户不存在'); } 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 emailKyc = await this.kycEntity.findOneBy({ email: payload.customerEmail }); if (emailKyc) { throw new CoolCommException('邮箱已被使用'); } 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, email: payload.customerEmail, 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); } } }