|
@@ -0,0 +1,261 @@
|
|
|
+import { Inject, Logger, Provide } from '@midwayjs/decorator';
|
|
|
+import { BaseService } from '@cool-midway/core';
|
|
|
+import * as _ from 'lodash';
|
|
|
+import * as moment from 'moment';
|
|
|
+import { Utils } from '../../../../comm/utils';
|
|
|
+import { HttpService } from '@midwayjs/axios';
|
|
|
+import * as md5 from 'md5';
|
|
|
+import { ILogger } from '@midwayjs/logger';
|
|
|
+import * as FormData from 'form-data';
|
|
|
+import * as fs from 'fs';
|
|
|
+
|
|
|
+const URL = 'https://sandbox-oapi.sunpay.pro/api/v3-2/Fiat/Direct/PayIn';
|
|
|
+// https://oapi.sunpay.pro/api/v3/Crypto/PayIn
|
|
|
+const BASIC_KEY_URL = 'https://sandbox-oapi.sunpay.pro/api/v3-2/Fiat/Kyc/CreateBasicUser';
|
|
|
+// https://oapi.sunpay.pro/api/v3-2/Fiat/Kyc/CreateBasicUser
|
|
|
+const ADVANCED_KEY_URL = 'https://sandbox-oapi.sunpay.pro/api/v3-2/Fiat/Kyc/CreateAdvancedUser';
|
|
|
+// https://oapi.sunpay.pro/api/v3-2/Fiat/Kyc/CreateAdvancedUser
|
|
|
+const PREMINUM_KEY_URL = 'https://sandbox-oapi.sunpay.pro/api/v3-2/Fiat/Kyc/CreatePremiumUser';
|
|
|
+// https://oapi.sunpay.pro/api/v3-2/Fiat/Kyc/CreatePremiumUser
|
|
|
+const COUNTRIES_URL = 'https://sandbox-oapi.sunpay.pro/api/v3-2/Fiat/Countries';
|
|
|
+// const COUNTRIES_URL = 'https://oapi.sunpay.pro/api/v3-2/Fiat/Countries';
|
|
|
+
|
|
|
+const API_KEY = '08dcd396-a91a-486a-8ca5-02150819d7ae';
|
|
|
+const API_SERECT = '8357086ffbd2cc610afe8a5f5359f7f8563bd887f9e6c376bc3b86b512e2e74e';
|
|
|
+const HOST = '127.0.0.1:9000';
|
|
|
+const NOTIFY_HOST = `http://${HOST}/api/admin/dj/open/`;
|
|
|
+const MER_ID = '08dcd396-a91a-486a-8ca5-02150819d7ae';
|
|
|
+
|
|
|
+@Provide()
|
|
|
+export class SunPayService extends BaseService {
|
|
|
+ @Inject()
|
|
|
+ utils: Utils;
|
|
|
+ @Inject()
|
|
|
+ httpService: HttpService;
|
|
|
+ @Logger()
|
|
|
+ logger: ILogger;
|
|
|
+
|
|
|
+ async createPremium(payload: any, files: any) {
|
|
|
+ const form = new FormData();
|
|
|
+ form.append('customer_id', payload.customerId);
|
|
|
+ form.append('residential_address', fs.createReadStream(files.residentialAddress.data));
|
|
|
+ form.append('income', fs.createReadStream(files.income.data));
|
|
|
+ const timestamp = +moment();
|
|
|
+ const nonce = md5(timestamp);
|
|
|
+ const signData = timestamp + nonce;
|
|
|
+ const sign = this.utils.signBySha256(signData, API_SERECT).toUpperCase();
|
|
|
+ const res = await this.httpService.post(PREMINUM_KEY_URL, form, {
|
|
|
+ headers: {
|
|
|
+ 'SunPay-Key': API_KEY,
|
|
|
+ 'SunPay-Timestamp': timestamp,
|
|
|
+ 'SunPay-Nonce': nonce,
|
|
|
+ 'SunPay-Sign': sign,
|
|
|
+ ...form.getHeaders()
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.logger.info('高级KYC接口返回', JSON.stringify(res.data));
|
|
|
+ const { is_success, msg, data } = res.data;
|
|
|
+ if (is_success && data) {
|
|
|
+ return {
|
|
|
+ customerId: payload.customerId
|
|
|
+ };
|
|
|
+ } else if (!is_success && msg === 'Server Error: Cannot premium repeatedly') {
|
|
|
+ return {
|
|
|
+ customerId: payload.customerId
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ throw new Error(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async createAdvanced(payload: any, files: any) {
|
|
|
+ const form = new FormData();
|
|
|
+ form.append('customer_id', payload.customerId);
|
|
|
+ form.append('document_type', payload.documentType);
|
|
|
+ form.append('document_number', payload.documentNumber);
|
|
|
+ form.append('front_side_document', fs.createReadStream(files.frontSideDocument.data));
|
|
|
+ form.append('back_side_document', fs.createReadStream(files.backSideDocument.data));
|
|
|
+ form.append('customer_photo', fs.createReadStream(files.customerPhoto.data));
|
|
|
+ const timestamp = +moment();
|
|
|
+ const nonce = md5(timestamp);
|
|
|
+ const signData = timestamp + nonce;
|
|
|
+ const sign = this.utils.signBySha256(signData, API_SERECT).toUpperCase();
|
|
|
+ const res = await this.httpService.post(ADVANCED_KEY_URL, form, {
|
|
|
+ headers: {
|
|
|
+ 'SunPay-Key': API_KEY,
|
|
|
+ 'SunPay-Timestamp': timestamp,
|
|
|
+ 'SunPay-Nonce': nonce,
|
|
|
+ 'SunPay-Sign': sign,
|
|
|
+ ...form.getHeaders()
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.logger.info('进阶KYC接口返回', JSON.stringify(res.data));
|
|
|
+ const { is_success, msg, data } = res.data;
|
|
|
+ if (is_success && data) {
|
|
|
+ return {
|
|
|
+ customerId: payload.customerId
|
|
|
+ };
|
|
|
+ } else if (!is_success && msg === 'Server Error: Cannot advance repeatedly') {
|
|
|
+ return {
|
|
|
+ customerId: payload.customerId
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ throw new Error(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async createBasic(payload: any) {
|
|
|
+ const param = {
|
|
|
+ "out_user_id": payload.outUserId,
|
|
|
+ "customer_name": payload.customerName,
|
|
|
+ "customer_email": payload.customerEmail,
|
|
|
+ "country_code": payload.countryCode,
|
|
|
+ "residence_country": payload.residenceCountry,
|
|
|
+ "birth_date": moment(payload.birthDate).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ }
|
|
|
+ const timestamp = +moment();
|
|
|
+ const nonce = md5(timestamp);
|
|
|
+ const data = timestamp + nonce + JSON.stringify(param);
|
|
|
+ const sign = this.utils.signBySha256(data, API_SERECT).toUpperCase();
|
|
|
+ const res = await this.httpService.post(BASIC_KEY_URL, param, {
|
|
|
+ headers: {
|
|
|
+ 'SunPay-Key': API_KEY,
|
|
|
+ 'SunPay-Timestamp': timestamp,
|
|
|
+ 'SunPay-Nonce': nonce,
|
|
|
+ 'SunPay-Sign': sign
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.logger.info('基础KYC接口返回', param, JSON.stringify(res.data));
|
|
|
+ const { is_success, msg } = res.data;
|
|
|
+ if (is_success && res.data.data.customer_id) {
|
|
|
+ return {
|
|
|
+ customerId: res.data.data.customer_id
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ throw new Error(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async getCountries() {
|
|
|
+ const timestamp = +moment();
|
|
|
+ const nonce = md5(timestamp);
|
|
|
+ const data = timestamp + nonce;
|
|
|
+ const sign = this.utils.signBySha256(data, API_SERECT).toUpperCase();
|
|
|
+ const res = await this.httpService.get(COUNTRIES_URL, {
|
|
|
+ headers: {
|
|
|
+ 'SunPay-Key': API_KEY,
|
|
|
+ 'SunPay-Timestamp': timestamp,
|
|
|
+ 'SunPay-Nonce': nonce,
|
|
|
+ 'SunPay-Sign': sign
|
|
|
+ }
|
|
|
+ });
|
|
|
+ const { is_success, msg } = res.data;
|
|
|
+ if (is_success) {
|
|
|
+ return res.data.data;
|
|
|
+ } else {
|
|
|
+ throw new Error(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async order(payload) {
|
|
|
+ return {
|
|
|
+ payUrl: `http://localhost:8080/#/?t=${payload.orderNo}`,
|
|
|
+ isDone: false
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ async createOrder(payload) {
|
|
|
+ const param = {
|
|
|
+ out_order_no: payload.orderNo,
|
|
|
+ customer_id: payload.customerId,
|
|
|
+ currency: 'USD',
|
|
|
+ amount: +payload.amount,
|
|
|
+ payment_type: "CARD",
|
|
|
+ client_ip: payload.userIp || "127.0.0.0",
|
|
|
+ billing_address_country_code: "US",
|
|
|
+ webhook_url: NOTIFY_HOST + '/SunCard/notifyOrder',
|
|
|
+ cancel_url: payload.returnUrl || 'https://www.baidu.com',
|
|
|
+ };
|
|
|
+ const timestamp = +moment();
|
|
|
+ const nonce = md5(timestamp);
|
|
|
+ const data = timestamp + nonce + JSON.stringify(param);
|
|
|
+ const sign = this.utils.signBySha256(data, API_SERECT).toUpperCase();
|
|
|
+ const res = await this.httpService.post(URL, param, {
|
|
|
+ headers: {
|
|
|
+ 'SunPay-Key': API_KEY,
|
|
|
+ 'SunPay-Timestamp': timestamp,
|
|
|
+ 'SunPay-Nonce': nonce,
|
|
|
+ 'SunPay-Sign': sign
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.logger.info('下单接口返回', param, JSON.stringify(res.data));
|
|
|
+ const { is_success, msg } = res.data;
|
|
|
+ if (is_success && res.data.data.check_out_url) {
|
|
|
+ return {
|
|
|
+ payUrl: res.data.data.check_out_url,
|
|
|
+ traceNo: res.data.data.order_no
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ throw new Error(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async query(payload) {
|
|
|
+ if (!payload.traceNo) {
|
|
|
+ return {
|
|
|
+ status: 0,
|
|
|
+ msg: 'traceNo is'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const param = {
|
|
|
+ orderNo: payload.traceNo
|
|
|
+ };
|
|
|
+ const timestamp = +moment();
|
|
|
+ const nonce = md5(timestamp);
|
|
|
+ const data = timestamp + nonce;
|
|
|
+ const sign = this.utils.signBySha256(data, API_SERECT).toUpperCase();
|
|
|
+ const res = await this.httpService.get(`${URL}/${param.orderNo}`, {
|
|
|
+ headers: {
|
|
|
+ 'SunPay-Key': API_KEY,
|
|
|
+ 'SunPay-Timestamp': timestamp,
|
|
|
+ 'SunPay-Nonce': nonce,
|
|
|
+ 'SunPay-Sign': sign
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.logger.info('查询接口返回', JSON.stringify(res.data));
|
|
|
+ const { is_success, msg } = res.data;
|
|
|
+ if (is_success && res.data.data.order_status === 'SUCCESS ') {
|
|
|
+ return {
|
|
|
+ status: 1,
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ return {
|
|
|
+ status: 0,
|
|
|
+ msg,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async handleOrderNotify(payload, headers) {
|
|
|
+ const { data } = payload;
|
|
|
+ const sign = headers['SunPay-Sign'];
|
|
|
+ const timestamp = headers['SunPay-Timestamp'];
|
|
|
+ const nonce = headers['SunPay-Nonce'];
|
|
|
+ const key = headers['SunPay-Key'];
|
|
|
+ const str = timestamp + nonce + JSON.stringify(data);
|
|
|
+ const validSign = this.utils.signBySha256(str, API_SERECT).toUpperCase();
|
|
|
+ if (sign !== validSign) {
|
|
|
+ throw new Error('sign error');
|
|
|
+ }
|
|
|
+ if (data.status !== 'SUCCESS') {
|
|
|
+ throw new Error('order no success');
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ date: moment(),
|
|
|
+ orderNo: data.out_order_no,
|
|
|
+ traceNo: data.order_no,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|