UNPKG

rapid-unipay

Version:

UnionPay module

110 lines (101 loc) 3.79 kB
/** * Copyright (c) 2017 Lucky Byte, Inc. */ const debug = require('debug')('unipay'); const crypto = require('crypto'); const moment = require('moment'); const winston = require('winston'); const utils = require('../lib/utils'); const post = require('../lib/post'); /** * 银联代付,后台交易,银联响应结果,外加后台通知 * * 参数: * dest_url: 银联代付请求地址 * params: 一个 JSON 对象,包含下列的 key: * * merno: 商户代码 * * order_id: 商户订单号 * * cert_sn: 签名证书 Serial Number * * sign_pem: 签名证书,PEM * * acct_no: 卡号/账号 * * acct_name: 账户姓名(和 acct_cert_no 必填其一) * * acct_cert_no: 账户身份证号码(和 acct_name 必填其一) * * verify_cer: 验证响应报文签名证书 * * back_url: 后台通知地址 * * amount: 交易金额,单位为分 * * encrypt_cer: 加密证书,可选 * * encrypt_cer_sn: 加密证书序号,可选 * * 返回: * JSON,包含 2 个字段: * reqt: 请求报文, JSON * resp: 响应报文, JSON, 通过报文中 respCode 确定交易是否成功 */ const exchange = async (dest_url, params) => { if (!dest_url || !params) { throw new Error('银联代付请求参数无效,用法 exchange(dest_url, {...})'); } const required_keys = [ 'merno', 'cert_sn', 'sign_pem', 'verify_cer', 'order_id', 'acct_no', 'back_url', 'amount' ] for (let i = 0; i < required_keys.length; i++) { const key = required_keys[i]; if (!params[key]) { throw new Error(`银联代付请求参数缺少[${key}]`); } } if (!params.acct_name && !params.acct_cert_no) { throw new Error('代付参数 [acct_name] 和 [acct_cert_no] 必填其一'); } const amount = parseInt(params.amount); if (!amount) { throw new Error(`代付请求金额[${params.amount}]无效`); } let reqt_json = { version: '5.0.0', encoding: 'UTF-8', signMethod: '01', txnType: '12', txnSubType: '00', bizType: '000401', channelType: '07', accessType: '0', txnTime: moment().format('YYYYMMDDHHmmss'), certId: params.cert_sn, merId: params.merno, orderId: params.order_id, backUrl: params.back_url, currencyCode: '156', txnAmt: amount, } if (params.version) { if (params.version != '5.0.0' && params.version != '5.1.0') { throw new Error('参数 version 无效,必须是 5.0.0 或 5.1.0'); } reqt_json.version = params.version; } if (!params.encrypt_cer) { reqt_json.accNo = params.acct_no; } else { if (!params.encrypt_cer_sn) { throw new Error('提供了加密证书,但未提供加密证书ID'); } reqt_json.encryptCertId = params.encrypt_cer_sn; reqt_json.accNo = utils.pubkey_encrypt(params.encrypt_cer, params.acct_no); } reqt_json.customerInfo = utils.build_cust_info(params); reqt_json.signature = utils.gen_reqt_sign(reqt_json, params.sign_pem); winston.info('银联代付请求报文:', JSON.stringify(reqt_json, null, 2)); const resp_data = await post(dest_url, reqt_json, {retry: 1}); const resp_json = utils.parse_resp_data(resp_data); winston.info('银联代付响应报文:', JSON.stringify(resp_json, null, 2)); if (!utils.verify_resp_sign(resp_json, params.verify_cer)) { throw new Error('验证代付响应报文签名失败'); } debug('验证代付响应报文签名通过'); return { reqt: reqt_json, resp: resp_json } } module.exports = { exchange: exchange, }