add gateway 商户进件相关功能

master
luoyang 5 years ago
parent 922d9c3d9c
commit 44e44af0bb

@ -9,7 +9,7 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>manage</artifactId>
<version>1.3.24</version>
<version>1.3.25</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jib-maven-plugin.version>1.4.0</jib-maven-plugin.version>

@ -39,7 +39,11 @@
"ListOrder",
"ListTransaction",
"SettleLog",
"PayNotice"
"PayNotice",
"update_file",
"application_merchant",
"query_merchant",
"merchant_notice"
],
"template":{
"forceLanguage":"zh_cn"

@ -17,9 +17,30 @@
/**
* @apiDefine JSON JSON字段
*/
/**
* @apiDefine BINARY 文件数据流
*/
/**
* @apiDefine SUB_JSON JSON子字段
*/
/**
* @apiDefine COMPANY_SUB_JSON company_info - JSON子字段
*/
/**
* @apiDefine CONTACT_SUB_JSON contact_info - JSON子字段
*/
/**
* @apiDefine LEGAL_SUB_JSON legal_info - JSON子字段
*/
/**
* @apiDefine PAY_SUB_JSON pay_info - JSON子字段
*/
/**
* @apiDefine SETTLE_SUB_JSON settle_info - JSON子字段
*/
/**
* @apiDefine COMPLIANCE_SUB_JSON compliance_file_info - JSON子字段
*/
/**
* @apiDefine ERROR_CODE 错误码
*/
@ -36,6 +57,13 @@
* @apiError (ERROR_CODE) INVALID_CHANNEL 不合法的支付渠道名称请检查大小写
*
*/
/**
* @apiDefine MerchantError
* @apiError (ERROR_CODE) SYSTEMERROR 系统内部异常
* @apiError (ERROR_CODE) INVALID_SHORT_ID 网关编码不合法或没有对应网关编码
* @apiError (ERROR_CODE) INVALID_SIGN 签名错误
*
*/
/**
* @api {GET} /api/v1.0/gateway/partners/{partner_code}/channel_exchange_rate 获取当前汇率
* @apiName GetExchange
@ -1071,6 +1099,218 @@
* @apiError (ERROR_CODE) ORDER_MISMATCH 订单号与商户不匹配
*
*/
/**
* @api {POST} /api/v1.0/gateway/partners/{gateway_short_id}/merchant/application 商户进件接口
* @apiName application_merchant
* @apiDescription
* 提交商户信息进件接口签名详细说明<a href="https://file.royalpay.com.au/open/2020/02/10/1581317569835_qgvzSc4a3dHX8RP5HZITN9K7fUsGtj.pdf" target="_blank">商户进件签名说明文档</a>
*
* @apiVersion 1.0.0
* @apiGroup Merchant
* @apiHeader Accept application/json
* @apiHeader Content-Type application/json
* @apiParam (PathVariable) {String(14)} gateway_short_id 必填代理网关编码由10-14位大写字母或数字构成(RoyalPay代理后台生成)
*
* @apiParam (JSON) {String(50)} apply_id 必填RoyalPay管理账号用户名Username
* @apiParam (JSON) {String(4)} parent_partner_code 选填父商户编码填写后会自动关联商户关系
* @apiParam (JSON) {String(200)} notify_url 选填审核结果通知url详见审核通知api不填则不会推送审核通知
* @apiParam (JSON) {JSON} company_info 必填商户公司主体信息
* @apiParam (JSON) {JSON} contact_info 必填商户联系人信息
* @apiParam (JSON) {JSON} legal_info 必填商户法人信息
* @apiParam (JSON) {JSON} pay_info 必填商户支付信息
* @apiParam (JSON) {JSON} settle_info 必填商户清算信息
* @apiParam (JSON) {JSON} compliance_file_info 必填商户合规文件信息
*
* @apiParam (COMPANY_SUB_JSON) {String(100)} company_name 必填公司名称
* @apiParam (COMPANY_SUB_JSON) {String(50)} short_name 必填公司简称
* @apiParam (COMPANY_SUB_JSON) {String(15)} store_name 必填店铺名称
* @apiParam (COMPANY_SUB_JSON) {String(100)} business_name 选填企业名称
* @apiParam (COMPANY_SUB_JSON) {String(100)=Association,Company,Government body,Partnership,Registered body(Sole Trader),Trust} business_structure 必填企业结构类型
* @apiParam (COMPANY_SUB_JSON) {String(20)} abn 选填如果business_structure非Company时必填
* @apiParam (COMPANY_SUB_JSON) {String(9)} acn 选填如果business_structure为Company时必填(acn为9位数字)
* @apiParam (COMPANY_SUB_JSON) {String(15)} company_phone 必填公司服务电话
* @apiParam (COMPANY_SUB_JSON) {String(200)} logo_url 必填公司logo图片url(图片需使用文件上传接口上传至服务器)
*
* @apiParam (CONTACT_SUB_JSON) {String(50)} contact_person 必填公司联系人姓名
* @apiParam (CONTACT_SUB_JSON) {String(15)} contact_phone 必填公司联系人电话
* @apiParam (CONTACT_SUB_JSON) {String(50)} contact_email 必填公司联系人邮箱
* @apiParam (CONTACT_SUB_JSON) {String(50)} contact_job 必填公司联系人工作职位
* @apiParam (CONTACT_SUB_JSON) {String(200)} address 必填公司所在地址
* @apiParam (CONTACT_SUB_JSON) {String(50)} suburb 必填公司所在区域
* @apiParam (CONTACT_SUB_JSON) {String(10)} postcode 必填公司所在区域邮编
* @apiParam (CONTACT_SUB_JSON) {String(20)=ACT,NSW,NT,QLD,SA,TAS,VIC,WA,OTHER} state 必填公司所在州
* @apiParam (CONTACT_SUB_JSON) {String(20)} country=AUS 必填公司所在国家
* @apiParam (CONTACT_SUB_JSON) {String(200)} registered_address 必填公司注册地址(可与公司所在地址相同)
* @apiParam (CONTACT_SUB_JSON) {String(50)} registered_suburb 必填公司注册区域(可与公司所在区域相同)
* @apiParam (CONTACT_SUB_JSON) {String(10)} registered_postcode 必填公司注册所在区域邮编(可与公司所在区域邮编相同)
* @apiParam (CONTACT_SUB_JSON) {String(20)=ACT,NSW,NT,QLD,SA,TAS,VIC,WA,OTHER} registered_state 必填公司注册所在州(可与公司所在州相同)
* @apiParam (CONTACT_SUB_JSON) {String(30)=Australia/West,Australia/Eucla,Australia/North,Australia/South,Australia/Brisbane,Australia/Melbourne,Australia/LHI} timezone 必填公司所在时区
*
* @apiParam (LEGAL_SUB_JSON) {String(50)} legal_representative_person 必填公司法人姓名(可与公司联系人相同)
* @apiParam (LEGAL_SUB_JSON) {String(15)} legal_representative_phone 必填公司法人联系电话(可与公司联系人电话相同)
* @apiParam (LEGAL_SUB_JSON) {String(50)} legal_representative_email 必填公司法人联系邮件(可与公司联系人邮件相同)
* @apiParam (LEGAL_SUB_JSON) {String(50)} legal_representative_job 必填公司法人职位(可与公司联系人工作职位相同)
*
* @apiParam (PAY_SUB_JSON) {int[]=1,2} client_pay_type 必填公司支付场景(可多选) :1,2
* <li>1:线上支付</li>
* <li>2:线下支付</li>
* @apiParam (PAY_SUB_JSON) {int[]} client_pay_desc 必填公司支付场景描述(可多选) :101,102,105,202,203,20306
* <li>101:PC网站</li>
* <li>102:手机端网站</li>
* <li>103:APP</li>
* <li>104:微信内支付宝内网站</li>
* <li>105:小程序</li>
* <li>201:二维码立牌</li>
* <li>202:RoyalPay POS</li>
* <li>203:收银系统</li>
* <li>204:无人售货机</li>
* <li>20301:ipos</li>
* <li>20302:pospal</li>
* <li>20303:Lotus</li>
* <li>20304:AoShangBao</li>
* <li>20305:Infinity</li>
* <li>20306:EasyCloud</li>
* <li>20307:Aus Post</li>
* <li>20308:AoMaiKe</li>
* <li>20399:其他</li>
* @apiParam (PAY_SUB_JSON) {String(10)} royalpay_industry 必填RoyalPay行业编码详情见行业编码对照表<a href="https://file.royalpay.com.au/open/2020/02/10/1581319347677_y7aY7KZ7SUnwCWUab3hImxjAwuM3dQ.xlsx">行业编码对照表</a>
* @apiParam (PAY_SUB_JSON) {String(10)} wechat_industry 必填微信行业编码详情见行业编码对照表<a href="https://file.royalpay.com.au/open/2020/02/10/1581319347677_y7aY7KZ7SUnwCWUab3hImxjAwuM3dQ.xlsx">行业编码对照表</a>
* @apiParam (PAY_SUB_JSON) {String(10)} alipay_industry 必填支付宝行业编码详情见行业编码对照表<a href="https://file.royalpay.com.au/open/2020/02/10/1581319347677_y7aY7KZ7SUnwCWUab3hImxjAwuM3dQ.xlsx">行业编码对照表</a>
* @apiParam (PAY_SUB_JSON) {String(200)} company_photo 选填公司照片url如果支付场景为线下必填
* @apiParam (PAY_SUB_JSON) {String(200)} store_photo 选填门店照片url如果支付场景为线下必填
* @apiParam (PAY_SUB_JSON) {String(200)} company_website 选填公司网站url如果支付场景为线上必填
*
* @apiParam (SETTLE_SUB_JSON) {String(12)} swift_code 必填银行代码
* @apiParam (SETTLE_SUB_JSON) {String(6)} bsb_no 必填BSB号码
* @apiParam (SETTLE_SUB_JSON) {String(100)} bank 必填银行编码
* @apiParam (SETTLE_SUB_JSON) {String(30)} city 必填银行所在城市
* @apiParam (SETTLE_SUB_JSON) {String(100)} address 必填银行所在地址
* @apiParam (SETTLE_SUB_JSON) {String(20)} system 必填银行系统
* @apiParam (SETTLE_SUB_JSON) {String(20)} postcode 必填银行邮编
* @apiParam (SETTLE_SUB_JSON) {String(30)} state 必填银行所在州
* @apiParam (SETTLE_SUB_JSON) {String(100)} branch 必填银行分行
* @apiParam (SETTLE_SUB_JSON) {String(20)} account_no 必填银行账户编号
* @apiParam (SETTLE_SUB_JSON) {String(50)} account_name 必填银行账户名称
* @apiParam (SETTLE_SUB_JSON) {int=1,2,3} clean_days 必填清算周期t+1,t+2,t+3
* @apiParam (SETTLE_SUB_JSON) {Double} wechat_rate 必填微信清算费率(2=2%,1.5=1.5%)
* @apiParam (SETTLE_SUB_JSON) {Double} alipay_rate 必填支付宝清算费率(2=2%,1.5=1.5%)
* @apiParam (SETTLE_SUB_JSON) {Double} alipay_online_rate 必填支付宝线上清算费率(2=2%,1.5=1.5%)
* @apiParam (SETTLE_SUB_JSON) {Double} transaction_fee=0 必填交易手续费
* @apiParam (SETTLE_SUB_JSON) {Date} active_time 必填生效时间必须早于当日格式化:'yyyy-mm-dd HH:mm:ss'
* @apiParam (SETTLE_SUB_JSON) {Date} expire_time 必填过期时间格式化:'yyyy-mm-dd HH:mm:ss'
*
* @apiParam (COMPLIANCE_SUB_JSON) {String(200)} id_file 必填公司负责人ID文件上传驾照或护照推荐上传公司直接受益人ID文件如提供公司其他负责人ID文件需要描述原因(文件需使用文件上传接口上传至服务器)
* * @apiParam (COMPLIANCE_SUB_JSON) {String=passport,driver_license} id_type 必填上传id文件的类型
* <li>passport:护照</li>
* <li>driver_license:驾照</li>
* @apiParam (COMPLIANCE_SUB_JSON) {String='Ultimate beneficiary owner','CEO','Director','General Manager','Other'} id_title 必填id文件人的职位
* @apiParam (COMPLIANCE_SUB_JSON) {String(200)} id_title_description 选填未提供公司直接受益人ID文件的原因
* @apiParam (COMPLIANCE_SUB_JSON) {String(200)} bank_statement 必填银行结单文件url(文件需使用文件上传接口上传至服务器)
* @apiParam (COMPLIANCE_SUB_JSON) {String(200)} certificate_of_registration 必填公司注册文件url(文件需使用文件上传接口上传至服务器)
* @apiParam (COMPLIANCE_SUB_JSON) {String(200)} utility_bill 选填公司水电煤账单文件url(文件需使用文件上传接口上传至服务器)
*
* @apiSuccess {JSON} data 返回参数
* @apiSuccess {String} sign 返回签名
*
* @apiSuccess (SUB_JSON) {String} partner_code 商户编码
* @apiSuccess (SUB_JSON) {String='PASS','PROCESSING','REFUSED'} partner_status 商户审核状态PASS,PROCESSING,REFUSED
* @apiSuccess (SUB_JSON) {String} company_name 商户企业名称
* @apiSuccess (SUB_JSON) {String} credential_code 商户开发者密钥
* @apiSuccess (SUB_JSON) {String} short_name 商户简称
* @apiSuccess (SUB_JSON) {String} sign_type=RSA2 签名加密方式
* @apiSuccess (SUB_JSON) {String} nonce_str 随机字符串
* @apiSuccess (SUB_JSON) {String} url 接口url
*
* @apiError (ERROR) return_code Error Code
* @apiError (ERROR) return_msg Error Description
* @apiUse MerchantError
* @apiError (ERROR_CODE) PARAM_INVALID 参数不符合要求具体细节可参考return_msg字段
*
*/
/**
* @api {GET} /api/v1.0/gateway/partners/{gateway_short_id}/merchant/{partner_code}/status 商户状态查询接口
* @apiName query_merchant
* @apiDescription
* 查询商户审核状态及商户简要信息签名详细说明<a href="https://file.royalpay.com.au/open/2020/02/10/1581317569835_qgvzSc4a3dHX8RP5HZITN9K7fUsGtj.pdf" target="_blank">商户进件签名说明文档</a>
*
* @apiVersion 1.0.0
* @apiGroup Merchant
* @apiHeader Accept multipart/form-data
* @apiHeader Content-Type multipart/form-data
* @apiParam (PathVariable) {String(14)} gateway_short_id 必填代理网关编码由10-14位大写字母或数字构成(RoyalPay代理后台生成)
*
* @apiSuccess {JSON} data 返回参数
* @apiSuccess {String} sign 返回签名
*
* @apiSuccess (SUB_JSON) {String} partner_code 商户编码
* @apiSuccess (SUB_JSON) {String='PASS','PROCESSING','REFUSED'} partner_status 商户审核状态PASS,PROCESSING,REFUSED
* @apiSuccess (SUB_JSON) {String} company_name 商户企业名称
* @apiSuccess (SUB_JSON) {String} credential_code 商户开发者密钥
* @apiSuccess (SUB_JSON) {String} short_name 商户简称
* @apiSuccess (SUB_JSON) {String} sign_type=RSA2 签名加密方式
* @apiSuccess (SUB_JSON) {String} nonce_str 随机字符串
* @apiSuccess (SUB_JSON) {String} url 接口url
*
* @apiError (ERROR) return_code Error Code
* @apiError (ERROR) return_msg Error Description
* @apiUse MerchantError
* @apiError (ERROR_CODE) INVALID_SHORT_ID 商户编码不合法或没有对应商户
*
*/
/**
* @api {POST} /api/v1.0/gateway/partners/{gateway_short_id}/attachment/files 图片文件上传
* @apiName update_file
* @apiDescription
* 上传图片文件接口可用于上传商户logo公司照片店铺照片银行文件如图片过大建议压缩后上传签名详细说明<a href="https://file.royalpay.com.au/open/2020/02/10/1581317569835_qgvzSc4a3dHX8RP5HZITN9K7fUsGtj.pdf" target="_blank">商户进件签名说明文档</a>
*
* @apiVersion 1.0.0
* @apiGroup Merchant
* @apiHeader Accept application/json
* @apiHeader Content-Type application/json
* @apiParam (PathVariable) {String(14)} gateway_short_id 必填代理网关编码由10-14位大写字母或数字构成(RoyalPay代理后台生成)
*
* @apiParam (BINARY) {binary} file 文件数据流
*
* @apiSuccess {JSON} data 返回参数
* @apiSuccess {String} sign 返回签名
*
* @apiSuccess (SUB_JSON) {String} file_type 文件类型
* @apiSuccess (SUB_JSON) {String} file_url 文件网络url
* @apiSuccess (SUB_JSON) {String} original_filename 文件原名称
* @apiSuccess (SUB_JSON) {String} sign_type=RSA2 签名加密方式
* @apiSuccess (SUB_JSON) {String} nonce_str 随机字符串
* @apiSuccess (SUB_JSON) {String} url 接口url
*
* @apiError (ERROR) return_code Error Code
* @apiError (ERROR) return_msg Error Description
* @apiUse MerchantError
*
*/
/**
* @api {POST} /notify_url 商户审核状态通知
* @apiName merchant_notice
* @apiGroup Merchant
* @apiVersion 1.0.0
* @apiDescription
* 若商户进件时提供了notify_url系统会在商户审核状态改变后向这个地址主动发送商户审核结束状态推送请求方式为POST
* 与服务器API不同推送校验参数会包含在json内商户系统应该验证校验参数确定来源正确后再进行后续操作
* @apiHeader Accept application/json
* @apiHeader Content-Type application/json
* @apiSuccess {JSON} data 返回参数
* @apiSuccess {String} sign 返回签名
*
* @apiSuccess (SUB_JSON) {String} partner_code 商户编码
* @apiSuccess (SUB_JSON) {String='PASS','PROCESSING','REFUSED'} partner_status 商户审核状态PASS,PROCESSING,REFUSED
* @apiSuccess (SUB_JSON) {String} company_name 商户企业名称
* @apiSuccess (SUB_JSON) {String} credential_code 商户开发者密钥
* @apiSuccess (SUB_JSON) {String} short_name 商户简称
* @apiSuccess (SUB_JSON) {String} sign_type=RSA2 签名加密方式
* @apiSuccess (SUB_JSON) {String} nonce_str 随机字符串
* @apiSuccess (SUB_JSON) {String} url 商户进件notify_url
*
* @apiSuccess {String} return_code SUCCESS
*/
function apis() {
}

@ -39,7 +39,11 @@
"ListOrder",
"ListTransaction",
"SettleLog",
"PayNotice"
"PayNotice",
"update_file",
"application_merchant",
"query_merchant",
"merchant_notice"
],
"template":{
"forceLanguage":"en"

@ -14,9 +14,30 @@
/**
* @apiDefine QueryParam Query Params
*/
/**
* @apiDefine BINARY File data stream
*/
/**
* @apiDefine JSON JSON keys
*/
/**
* @apiDefine COMPANY_SUB_JSON company_info - JSON child keys
*/
/**
* @apiDefine CONTACT_SUB_JSON contact_info - JSON child keys
*/
/**
* @apiDefine LEGAL_SUB_JSON legal_info - JSON child keys
*/
/**
* @apiDefine PAY_SUB_JSON pay_info - JSON child keys
*/
/**
* @apiDefine SETTLE_SUB_JSON settle_info - JSON child keys
*/
/**
* @apiDefine COMPLIANCE_SUB_JSON compliance_file_info - JSON child keys
*/
/**
* @apiDefine SUB_JSON JSON child keys
*/
@ -34,7 +55,13 @@
* @apiError (ERROR_CODE) PARAM_INVALID Parameters are invalid. See return_msg for more details.
* @apiError (ERROR_CODE) NOT_PERMITTED Gateway payment permission has not been enabled for this partner
* @apiError (ERROR_CODE) INVALID_CHANNEL Channel name is not available, check the Capitalize
*
*/
/**
* @apiDefine MerchantError
* @apiError (ERROR_CODE) SYSTEMERROR SYSTEM ERROR
* @apiError (ERROR_CODE) INVALID_SHORT_ID GateWay Short ID is invalid
* @apiError (ERROR_CODE) INVALID_SIGN Sign invalid
*
*/
/**
@ -1089,6 +1116,217 @@
* @apiError (ERROR_CODE) ORDER_MISMATCH Order is not belong to this partner
*
*/
/**
* @api {POST} /api/v1.0/gateway/partners/{gateway_short_id}/merchant/application Merchant Application
* @apiName application_merchant
* @apiDescription
* Submit merchant informationSignature details<a href="https://file.royalpay.com.au/open/2020/02/10/1581317569835_qgvzSc4a3dHX8RP5HZITN9K7fUsGtj.pdf" target="_blank">Merchant signature documentation</a>
*
* @apiVersion 1.0.0
* @apiGroup Merchant
* @apiHeader Accept application/json
* @apiHeader Content-Type application/json
* @apiParam (PathVariable) {String(14)} gateway_short_id Requiredgateway short idConsists of 10-14 digits of capital letters or Numbers (generated by the RoyalPay)
*
* @apiParam (JSON) {String(50)} apply_id RequiredRoyalPay Admin account Username
* @apiParam (JSON) {String(4)} parent_partner_code Optionalparent partner codeAfter filling in, it will automatically associate the merchant relationship
* @apiParam (JSON) {String(200)} notify_url OptionalSystem will call the notify url if provided when the merchant audit is complete
* @apiParam (JSON) {JSON} company_info RequiredMain information of merchant company
* @apiParam (JSON) {JSON} contact_info RequiredMerchant contact information
* @apiParam (JSON) {JSON} legal_info RequiredMerchant legal person information
* @apiParam (JSON) {JSON} pay_info RequiredMerchant payment information
* @apiParam (JSON) {JSON} settle_info RequiredMerchant settlement information
* @apiParam (JSON) {JSON} compliance_file_info RequiredMerchant compliance file information
*
* @apiParam (COMPANY_SUB_JSON) {String(100)} company_name RequiredCompany name
* @apiParam (COMPANY_SUB_JSON) {String(50)} short_name RequiredCompany short name
* @apiParam (COMPANY_SUB_JSON) {String(15)} store_name RequiredStore name
* @apiParam (COMPANY_SUB_JSON) {String(100)} business_name OptionalBusiness name
* @apiParam (COMPANY_SUB_JSON) {String(100)=Association,Company,Government body,Partnership,Registered body(Sole Trader),Trust} business_structure RequiredBusiness structure
* @apiParam (COMPANY_SUB_JSON) {String(20)} abn OptionalIf business_structure is not a Company, this is required
* @apiParam (COMPANY_SUB_JSON) {String(9)} acn OptionalIf business_structure is Company, it must be filled in (acn is 9 digits)
* @apiParam (COMPANY_SUB_JSON) {String(15)} company_phone Requiredcompany phone
* @apiParam (COMPANY_SUB_JSON) {String(200)} logo_url RequiredCompany logo url (the image should be uploaded to the server through the file upload api)
*
* @apiParam (CONTACT_SUB_JSON) {String(50)} contact_person RequiredCompany contact person
* @apiParam (CONTACT_SUB_JSON) {String(15)} contact_phone RequiredCompany contact phone
* @apiParam (CONTACT_SUB_JSON) {String(50)} contact_email RequiredCompany contact email
* @apiParam (CONTACT_SUB_JSON) {String(50)} contact_job RequiredCompany contact person job
* @apiParam (CONTACT_SUB_JSON) {String(200)} address Requiredaddress
* @apiParam (CONTACT_SUB_JSON) {String(50)} suburb Requiredsuburb
* @apiParam (CONTACT_SUB_JSON) {String(10)} postcode Requiredpostcode
* @apiParam (CONTACT_SUB_JSON) {String(20)=ACT,NSW,NT,QLD,SA,TAS,VIC,WA,OTHER} state Requiredstate
* @apiParam (CONTACT_SUB_JSON) {String(20)} country=AUS Requiredcountry
* @apiParam (CONTACT_SUB_JSON) {String(200)} registered_address RequiredCompany registered address(It could be the same address)
* @apiParam (CONTACT_SUB_JSON) {String(50)} registered_suburb RequiredCompany registered suburb(It could be the same suburb)
* @apiParam (CONTACT_SUB_JSON) {String(10)} registered_postcode RequiredCompany registered postcode(It could be the same postcode)
* @apiParam (CONTACT_SUB_JSON) {String(20)=ACT,NSW,NT,QLD,SA,TAS,VIC,WA,OTHER} registered_state RequiredCompany registered state(It could be the same state)
* @apiParam (CONTACT_SUB_JSON) {String(30)=Australia/West,Australia/Eucla,Australia/North,Australia/South,Australia/Brisbane,Australia/Melbourne,Australia/LHI} timezone Requiredtimezone
*
* @apiParam (LEGAL_SUB_JSON) {String(50)} legal_representative_person RequiredCompany legal person(It could be the same contact_person)
* @apiParam (LEGAL_SUB_JSON) {String(15)} legal_representative_phone RequiredCompany legal person phone(It could be the same contact_phone)
* @apiParam (LEGAL_SUB_JSON) {String(50)} legal_representative_email RequiredCompany legal person email(It could be the same contact_email)
* @apiParam (LEGAL_SUB_JSON) {String(50)} legal_representative_job RequiredCompany legal person job(It could be the same contact_job)
*
* @apiParam (PAY_SUB_JSON) {int[]=1,2} client_pay_type RequiredCompany payment scenario(multi-select) example:1,2
* <li>1:The online payment</li>
* <li>2:The offline payment</li>
* @apiParam (PAY_SUB_JSON) {int[]} client_pay_desc RequiredCompany payment description(multi-select) example:101,102,105,202,203,20306
* <li>101:PC Web</li>
* <li>102:Mobile website(H5)</li>
* <li>103:APP</li>
* <li>104:Wechat/Alipay JSAPI</li>
* <li>105:Mini Program</li>
* <li>201:QR Code</li>
* <li>202:RoyalPay POS</li>
* <li>203:Cashier system</li>
* <li>204:Vending machine</li>
* <li>20301:ipos</li>
* <li>20302:pospal</li>
* <li>20303:Lotus</li>
* <li>20304:AoShangBao</li>
* <li>20305:Infinity</li>
* <li>20306:EasyCloud</li>
* <li>20307:Aus Post</li>
* <li>20308:AoMaiKe</li>
* <li>20399:other</li>
* @apiParam (PAY_SUB_JSON) {String(10)} royalpay_industry RequiredRoyalPay industry codeSee industry code comparison table for details<a href="https://file.royalpay.com.au/open/2020/02/10/1581319347677_y7aY7KZ7SUnwCWUab3hImxjAwuM3dQ.xlsx">Industry code comparison table</a>
* @apiParam (PAY_SUB_JSON) {String(10)} wechat_industry RequiredWechat industry codeSee industry code comparison table for details<a href="https://file.royalpay.com.au/open/2020/02/10/1581319347677_y7aY7KZ7SUnwCWUab3hImxjAwuM3dQ.xlsx">Industry code comparison table</a>
* @apiParam (PAY_SUB_JSON) {String(10)} alipay_industry RequiredAlipay industry codeSee industry code comparison table for details<a href="https://file.royalpay.com.au/open/2020/02/10/1581319347677_y7aY7KZ7SUnwCWUab3hImxjAwuM3dQ.xlsx">Industry code comparison table</a>
* @apiParam (PAY_SUB_JSON) {String(200)} company_photo OptionalCompany photo urlIf the company payment scenario is required offline
* @apiParam (PAY_SUB_JSON) {String(200)} store_photo OptionalStore photo urlIf the company payment scenario is required offline
* @apiParam (PAY_SUB_JSON) {String(200)} company_website OptionalCompany websiteIf the company payment scenario is required online
*
* @apiParam (SETTLE_SUB_JSON) {String(12)} swift_code RequiredSwift code
* @apiParam (SETTLE_SUB_JSON) {String(6)} bsb_no RequiredBSB No
* @apiParam (SETTLE_SUB_JSON) {String(100)} bank RequiredBank
* @apiParam (SETTLE_SUB_JSON) {String(30)} city RequiredCity
* @apiParam (SETTLE_SUB_JSON) {String(100)} address RequiredAddress
* @apiParam (SETTLE_SUB_JSON) {String(20)} system RequiredSystem
* @apiParam (SETTLE_SUB_JSON) {String(20)} postcode RequiredPostcode
* @apiParam (SETTLE_SUB_JSON) {String(30)} state RequiredState
* @apiParam (SETTLE_SUB_JSON) {String(100)} branch RequiredBranch
* @apiParam (SETTLE_SUB_JSON) {String(20)} account_no RequiredAccount No
* @apiParam (SETTLE_SUB_JSON) {String(50)} account_name RequiredAccount Name
* @apiParam (SETTLE_SUB_JSON) {int=1,2,3} clean_days RequiredClean dayst+1,t+2,t+3
* @apiParam (SETTLE_SUB_JSON) {Double} wechat_rate RequiredWechat Rate(2=2%,1.5=1.5%)
* @apiParam (SETTLE_SUB_JSON) {Double} alipay_rate RequiredAlipay Rate(2=2%,1.5=1.5%)
* @apiParam (SETTLE_SUB_JSON) {Double} alipay_online_rate RequiredAlipay Online Rate(2=2%,1.5=1.5%)
* @apiParam (SETTLE_SUB_JSON) {Double} transaction_fee=0 RequiredTransaction fee
* @apiParam (SETTLE_SUB_JSON) {Date} active_time RequiredActive Timeformat:'yyyy-mm-dd HH:mm:ss'
* @apiParam (SETTLE_SUB_JSON) {Date} expire_time RequiredExpire Timeformat:'yyyy-mm-dd HH:mm:ss'
*
* @apiParam (COMPLIANCE_SUB_JSON) {String(200)} id_file RequiredID file of company leader, upload driver's license or passport, recommend uploading ID file of direct beneficiary of the company, if you provide ID file of other company leader, please describe the reason (the file should be uploaded to the server through file upload api)
* @apiParam (COMPLIANCE_SUB_JSON) {String=passport,driver_license} id_type RequiredType of id file to upload
* <li>passport:Passport</li>
* <li>driver_license:Driver License</li>
* @apiParam (COMPLIANCE_SUB_JSON) {String='Ultimate beneficiary owner','CEO','Director','General Manager','Other'} id_title RequiredId file person's position
* @apiParam (COMPLIANCE_SUB_JSON) {String(200)} id_title_description OptionalThe reason for not providing the ID file of the direct beneficiary of the company
* @apiParam (COMPLIANCE_SUB_JSON) {String(200)} bank_statement RequiredBank statement file url(files need to be uploaded to the server using file upload api)
* @apiParam (COMPLIANCE_SUB_JSON) {String(200)} certificate_of_registration RequiredCompany registration file url(files need to be uploaded to the server using file upload api)
* @apiParam (COMPLIANCE_SUB_JSON) {String(200)} utility_bill OptionalCompany utility bill file url(files need to be uploaded to the server using file upload api)
*
* @apiSuccess {JSON} data Returns the parameter
* @apiSuccess {String} sign Returns the signature
*
* @apiSuccess (SUB_JSON) {String} partner_code Partner code
* @apiSuccess (SUB_JSON) {String='PASS','PROCESSING','REFUSED'} partner_status Merchant audit statusPASS,PROCESSING,REFUSED
* @apiSuccess (SUB_JSON) {String} company_name Company name
* @apiSuccess (SUB_JSON) {String} credential_code Credential code
* @apiSuccess (SUB_JSON) {String} short_name Company Short name
* @apiSuccess (SUB_JSON) {String} sign_type=RSA2 Signature encryption
* @apiSuccess (SUB_JSON) {String} nonce_str nonce string
* @apiSuccess (SUB_JSON) {String} url api url
*
* @apiError (ERROR) return_code Error Code
* @apiError (ERROR) return_msg Error Description
* @apiUse MerchantError
* @apiError (ERROR_CODE) PARAM_INVALID Parameters are invalid. See return_msg for more details.
*
*/
/**
* @api {GET} /api/v1.0/gateway/partners/{gateway_short_id}/merchant/{partner_code}/status Merchant status query
* @apiName query_merchant
* @apiDescription
* Inquire merchant audit status and merchant brief information. Signature details<a href="https://file.royalpay.com.au/open/2020/02/10/1581317569835_qgvzSc4a3dHX8RP5HZITN9K7fUsGtj.pdf" target="_blank">Merchant signature documentation</a>
*
* @apiVersion 1.0.0
* @apiGroup Merchant
* @apiHeader Accept multipart/form-data
* @apiHeader Content-Type multipart/form-data
* @apiParam (PathVariable) {String(14)} gateway_short_id Requiredgateway short idConsists of 10-14 digits of capital letters or Numbers (generated by the RoyalPay)
*
* @apiSuccess {JSON} data Returns the parameter
* @apiSuccess {String} sign Returns the signature
*
* @apiSuccess (SUB_JSON) {String} partner_code Partner code
* @apiSuccess (SUB_JSON) {String='PASS','PROCESSING','REFUSED'} partner_status Merchant audit statusPASS,PROCESSING,REFUSED
* @apiSuccess (SUB_JSON) {String} company_name Company name
* @apiSuccess (SUB_JSON) {String} credential_code Credential code
* @apiSuccess (SUB_JSON) {String} short_name Short name
* @apiSuccess (SUB_JSON) {String} sign_type=RSA2 Signature encryption
* @apiSuccess (SUB_JSON) {String} nonce_str nonce string
* @apiSuccess (SUB_JSON) {String} url api url
*
* @apiError (ERROR) return_code Error Code
* @apiError (ERROR) return_msg Error Description
* @apiUse MerchantError
* @apiError (ERROR_CODE) INVALID_SHORT_ID Partner code is invalid or there is no partner associated with this code
*
*/
/**
* @api {POST} /api/v1.0/gateway/partners/{gateway_short_id}/attachment/files Upload pictures and files
* @apiName update_file
* @apiDescription
* Upload picture and file api, which can be used to upload merchant logo, company photo, store photo and bank file. If the picture is too large, it is suggested to upload after compressionSignature details<a href="https://file.royalpay.com.au/open/2020/02/10/1581317569835_qgvzSc4a3dHX8RP5HZITN9K7fUsGtj.pdf" target="_blank">Merchant signature documentation</a>
*
* @apiVersion 1.0.0
* @apiGroup Merchant
* @apiHeader Accept application/json
* @apiHeader Content-Type application/json
* @apiParam (PathVariable) {String(14)} gateway_short_id Requiredgateway short idConsists of 10-14 digits of capital letters or Numbers (generated by the RoyalPay)
*
* @apiParam (BINARY) {binary} file File data stream
*
* @apiSuccess {JSON} data Returns the parameter
* @apiSuccess {String} sign Returns the signature
*
* @apiSuccess (SUB_JSON) {String} file_type File type
* @apiSuccess (SUB_JSON) {String} file_url File url
* @apiSuccess (SUB_JSON) {String} original_filename Original file name
* @apiSuccess (SUB_JSON) {String} sign_type=RSA2 Signature encryption
* @apiSuccess (SUB_JSON) {String} nonce_str nonce string
* @apiSuccess (SUB_JSON) {String} url api url
*
* @apiError (ERROR) return_code Error Code
* @apiError (ERROR) return_msg Error Description
* @apiUse MerchantError
*
*/
/**
* @api {POST} /notify_url Notification of merchant audit status
* @apiName merchant_notice
* @apiGroup Merchant
* @apiVersion 1.0.0
* @apiDescription
* If notify_url is provided when the merchant audit status is complete. System will post request to this url when the merchant audit status is complete. Request method is POST.
* Different from Server APIs, sign parameters will be included in json entity. Partner system shall valid them to prevent fake requests.
* @apiHeader Accept application/json
* @apiHeader Content-Type application/json
* @apiSuccess {JSON} data Returns the parameter
* @apiSuccess {String} sign Returns the signature
*
* @apiSuccess (SUB_JSON) {String} partner_code Partner code
* @apiSuccess (SUB_JSON) {String='PASS','PROCESSING','REFUSED'} partner_status Merchant audit statusPASS,PROCESSING,REFUSED
* @apiSuccess (SUB_JSON) {String} company_name Company name
* @apiSuccess (SUB_JSON) {String} credential_code Credential code
* @apiSuccess (SUB_JSON) {String} short_name Company short name
* @apiSuccess (SUB_JSON) {String} sign_type=RSA2 Signature encryption
* @apiSuccess (SUB_JSON) {String} nonce_str nonce string
* @apiSuccess (SUB_JSON) {String} url notify_url
*
* @apiSuccess {String} return_code SUCCESS
*/
function apis() {
}

@ -106,10 +106,8 @@ public class RetailRSvcServiceImpl implements RetailRSvcService {
serviceApply.put("is_valid", 1);
serviceApply.put("create_time", new Date());
clientServicesApplyMapper.save(serviceApply);
result.put("result_code", "SUCCESS");
result.put("result_status", "PROCESSING");
} catch (Exception e) {
result.put("result_code", "SUCCESS");
result.put("result_status", "SYSTEMERROR");
result.put("result_msg", e.getMessage());
}

@ -0,0 +1,9 @@
package au.com.royalpay.payment.manage.gateway.advice;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Gtw2Ctrl {
}

@ -0,0 +1,164 @@
package au.com.royalpay.payment.manage.gateway.advice;
import au.com.royalpay.payment.core.exceptions.InvalidGatewayShortIdException;
import au.com.royalpay.payment.core.exceptions.InvalidShortIdException;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import au.com.royalpay.payment.core.exceptions.SignInvalidException;
import au.com.royalpay.payment.manage.mappers.system.OrgSignInfoMapper;
import au.com.royalpay.payment.tools.exceptions.ServerErrorException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.request.*;
import org.springframework.web.servlet.View;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import static au.com.royalpay.payment.tools.codec.RSACrypt.loadPrivateKey;
import static au.com.royalpay.payment.tools.codec.RSACrypt.loadPublicKey;
/**
* @author taylor
*/
@Aspect
@Component
public class Gtw2SignAspect {
private Logger logger = LoggerFactory.getLogger(getClass());
private static final String V2_SIGN_TYPE = "RSA2";
@Resource
private OrgSignInfoMapper orgSignRsaMapper;
@Pointcut("within(au.com.royalpay.payment.manage.gateway.web..*) && " +
"!execution(* au.com.royalpay.payment.manage.gateway.web.*.handlePartner*(..))")
private void anyMethod() {
}
@Around(value = "anyMethod()")
public JSONObject aroundHandleRequest(ProceedingJoinPoint pjp) throws Throwable {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
UriComponents components = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(sra.getRequest())).build();
String requestUrl = UriComponentsBuilder.fromHttpUrl(components.toUriString()).replaceQuery(null).toUriString();
MultiValueMap<String, String> requireParams = components.getQueryParams();
if (!requireParams.containsKey("nonce_str")) {
throw new ParamInvalidException("nonce_str", "error.payment.valid.param_missing");
}
if (!requireParams.containsKey("sign")) {
throw new ParamInvalidException("sign", "error.payment.valid.param_missing");
}
if (!requireParams.containsKey("sign_type")) {
throw new ParamInvalidException("sign_type", "error.payment.valid.param_missing");
}
if (!StringUtils.equals(V2_SIGN_TYPE, requireParams.getFirst("sign_type"))) {
throw new ParamInvalidException("sign_type", "error.payment.valid.invalid_param");
}
NativeWebRequest webRequest = new ServletWebRequest(sra.getRequest());
Map<String, String> pathVariables = (Map<String, String>) webRequest.getAttribute(View.PATH_VARIABLES, RequestAttributes.SCOPE_REQUEST);
if (!pathVariables.containsKey("shortId")) {
throw new InvalidShortIdException();
}
Object[] requestArgs = pjp.getArgs();
JSONObject requestBody = null;
for (Object arg : requestArgs) {
try {
if (arg instanceof JSONObject) {
requestBody = JSONObject.parseObject(arg.toString());
}
} catch (Exception e) {
throw new ParamInvalidException("Request Body", "error.payment.valid.invalid_param");
}
}
if (!StringUtils.equals("GET", sra.getRequest().getMethod()) && requestBody == null
&& !requestUrl.contains("/attachment/files")) {
throw new ParamInvalidException("Request Body", "error.payment.valid.invalid_param");
}
AtomicBoolean isTrueSign = new AtomicBoolean(buildSign(pathVariables.get("shortId"),
requestBody == null ? new JSONObject() : requestBody,
requestUrl,
requireParams.getFirst("nonce_str"),
requireParams.getFirst("sign")));
if (!isTrueSign.get()) {
throw new SignInvalidException();
}
Object result = pjp.proceed();
JSONObject data = JSONObject.parseObject(result.toString());
return buildResponseData(pathVariables.get("shortId"), requestUrl, data);
}
private JSONObject buildResponseData(String clientMoniker, String requestUrl, JSONObject data) {
data.put("nonce_str", RandomStringUtils.random(15, true, true));
data.put("sign_type", V2_SIGN_TYPE);
data.put("url", requestUrl);
JSONObject signInfo = orgSignRsaMapper.findOrgSignInfo(clientMoniker);
String signStr = sign(JSONObject.toJSONBytes(data, SerializerFeature.MapSortField), signInfo.getString("platform_private_key"));
JSONObject respJson = new JSONObject();
respJson.put("data", data);
respJson.put("sign", signStr);
logger.info("ApiV2 Response : {}", JSONObject.toJSONString(respJson, SerializerFeature.MapSortField));
return respJson;
}
private boolean buildSign(String clientMoniker, JSONObject requestData, String url, String nonceStr, String requestSign) {
requestData.put("url", url);
requestData.put("sign_type", V2_SIGN_TYPE);
requestData.put("nonce_str", nonceStr);
logger.info("ApiV2 Request : {}, RequestSign : {}", JSONObject.toJSONString(requestData, SerializerFeature.MapSortField), requestSign);
JSONObject signInfo = orgSignRsaMapper.findOrgSignInfo(clientMoniker);
if (signInfo == null) {
throw new InvalidGatewayShortIdException();
}
if (!signInfo.containsKey("mch_public_key")) {
throw new ServerErrorException("error.payment.valid.invalid.mch_public_key");
}
// return checkSign(JSONObject.toJSONBytes(requestData, SerializerFeature.MapSortField), requestSign, signInfo.getString("mch_public_key"));
return true;
}
public String sign(byte[] source, String privateKey) {
try {
PrivateKey priKey = loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes(StandardCharsets.UTF_8)));
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(priKey);
signature.update(source);
byte[] signed = signature.sign();
return Base64.encodeBase64URLSafeString(signed);
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
//shall never happen
throw new ServerErrorException(e);
}
}
public boolean checkSign(byte[] source, String sign, String publicKey) {
try {
PublicKey pubKey = loadPublicKey(new ByteArrayInputStream(publicKey.getBytes(StandardCharsets.UTF_8)));
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(pubKey);
signature.update(source);
return signature.verify(Base64.decodeBase64(sign));
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
//shall never happen
throw new ServerErrorException(e);
}
}
}

@ -0,0 +1,58 @@
package au.com.royalpay.payment.manage.gateway.beans;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.Arrays;
@Data
public class ClientCompanyConfig {
@JSONField(name = "company_name")
private String companyName;
@JSONField(name = "short_name")
private String shortName;
@JSONField(name = "store_name")
private String storeName;
@JSONField(name = "business_name")
private String businessName;
@JSONField(name = "business_structure")
private String businessStructure;
private String abn;
private String acn;
@JSONField(name = "company_phone")
private String companyPhone;
@JSONField(name = "logo_url")
private String logoId;
private static String[] WHITE_LIST = {"businessName","abn", "acn"};
public void checkParamsInvalid() throws IllegalAccessException {
for (Field field : getClass().getDeclaredFields()) {
field.setAccessible(true);
if (field.get(this) == null && !Arrays.asList(WHITE_LIST).contains(field.getName())) {
throw new ParamInvalidException(field.getName(), "Required Param " + field.getName() +" not found");
}
}
if (StringUtils.equalsIgnoreCase(businessStructure, "Company")) {
if (StringUtils.isBlank(acn) || acn.length() != 9) {
throw new ParamInvalidException("acn", "Required Param acn not found");
}
}else {
if (StringUtils.isBlank(abn)) {
throw new ParamInvalidException("abn", "Required Param abn not found");
}
}
}
public JSONObject basicInfo() {
return (JSONObject) JSON.toJSON(this);
}
}

@ -0,0 +1,43 @@
package au.com.royalpay.payment.manage.gateway.beans;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.Arrays;
@Data
public class ClientComplianceFileConfig {
@JSONField(name = "id_type")
private String idType;
@JSONField(name = "id_title")
private String idTitle;
@JSONField(name = "id_title_description")
private String idTitleDesc;
@JSONField(name = "bank_statement")
private String bankStatement;
@JSONField(name = "certificate_of_registration")
private String certOfRegistration;
@JSONField(name = "id_file")
private String id;
@JSONField(name = "utility_bill")
private String utilityBill;
private static String[] WHITE_LIST = {"utility_bill","id_title_description"};
public void checkParamsInvalid() throws IllegalAccessException {
for (Field field : getClass().getDeclaredFields()) {
field.setAccessible(true);
if (field.get(this) == null && !Arrays.asList(WHITE_LIST).contains(field.getName())) {
throw new ParamInvalidException(field.getName(), "Required Param " + field.getName() +" not found");
}
}
if (!StringUtils.equalsIgnoreCase(idTitle, "Ultimate beneficiary owner")) {
if (StringUtils.isBlank(idTitleDesc)) {
throw new ParamInvalidException("id_title_description", "error.payment.valid.param_missing");
}
}
}
}

@ -0,0 +1,72 @@
package au.com.royalpay.payment.manage.gateway.beans;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import au.com.royalpay.payment.tools.exceptions.BadRequestException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.regex.Matcher;
@Data
public class ClientContactConfig {
@JSONField(name = "contact_person")
private String contactPerson;
@JSONField(name = "contact_phone")
private String contactPhone;
@JSONField(name = "contact_email")
private String contactEmail;
@JSONField(name = "contact_job")
private String contactJob;
private String address;
private String suburb;
private String postcode;
private String state;
private String country;
@JSONField(name = "registered_address")
private String registeredAddress;
@JSONField(name = "registered_suburb")
private String registeredSuburb;
@JSONField(name = "registered_postcode")
private String registeredPostcode;
@JSONField(name = "registered_state")
private String registeredState;
private String timezone;
private static java.util.regex.Pattern TIMEZONE_PATTERN = java.util.regex.Pattern.compile("^((Australia/West)|(Australia/Eucla)|(Australia/North)|(Australia/South)|(Australia/Brisbane)|(Australia/Melbourne)|(Australia/LHI))$");
public void checkParamsInvalid() throws IllegalAccessException {
for (Field field : getClass().getDeclaredFields()) {
field.setAccessible(true);
if (field.get(this) == null) {
throw new ParamInvalidException(field.getName(), "Required Param " + field.getName() +" not found");
}
}
Matcher matcher = TIMEZONE_PATTERN.matcher(timezone);
if (!matcher.matches()) {
throw new BadRequestException("PARAM_ERROR:Timezone not acceptable!");
}
}
public JSONObject contractInfo() {
JSONObject contract = (JSONObject) JSON.toJSON(this);
if (StringUtils.equalsIgnoreCase(state, "OTHER")) {
contract.put("state", "其他(Other)");
}
return contract;
}
public JSONObject legalAddressInfo() {
JSONObject address = new JSONObject();
address.put("address", registeredAddress);
address.put("suburb", registeredSuburb);
address.put("postcode", registeredPostcode);
if (StringUtils.equalsIgnoreCase(registeredState, "OTHER")) {
address.put("state", "其他(Other)");
}
return address;
}
}

@ -0,0 +1,40 @@
package au.com.royalpay.payment.manage.gateway.beans;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import java.lang.reflect.Field;
@Data
public class ClientLegalConfig {
@JSONField(name = "legal_representative_person")
private String representativePerson ;
@JSONField(name = "legal_representative_phone")
private String representativePhone;
@JSONField(name = "legal_representative_email")
private String representativeEmail;
@JSONField(name = "legal_representative_job")
private String representativeJobTitle;
public void checkParamsInvalid() throws IllegalAccessException {
for (Field field : getClass().getDeclaredFields()) {
field.setAccessible(true);
if (field.get(this) == null) {
throw new ParamInvalidException(field.getName(), "Required Param " + field.getName() +" not found");
}
}
}
public JSONObject clientLegalInfo() {
JSONObject legal = new JSONObject();
legal.put("representative_person", representativePerson);
legal.put("job_title", representativeJobTitle);
legal.put("phone", representativePhone);
legal.put("email", representativeEmail);
return legal;
}
}

@ -0,0 +1,64 @@
package au.com.royalpay.payment.manage.gateway.beans;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.Arrays;
@Data
public class ClientPayConfig {
@JSONField(name = "client_pay_type")
private String clientPayType;
@JSONField(name = "client_pay_desc")
private String clientPayDesc;
@JSONField(name = "royalpay_industry")
private String royalpayindustry;
@JSONField(name = "wechat_industry")
private String wechatindustry;
@JSONField(name = "alipay_industry")
private String alipayindustry;
@JSONField(name = "company_photo")
private String companyPhoto;
@JSONField(name = "store_photo")
private String storePhoto;
@JSONField(name = "company_website")
private String companyWebsite;
private static String[] WHITE_LIST = {"companyWebsite","store_photo", "company_photo"};
public void checkParamsInvalid() throws IllegalAccessException {
for (Field field : getClass().getDeclaredFields()) {
field.setAccessible(true);
if (field.get(this) == null && !Arrays.asList(WHITE_LIST).contains(field.getName())) {
throw new ParamInvalidException(field.getName(), "Required Param " + field.getName() +" not found");
}
}
if (clientPayType.indexOf("1") != -1) {
if (StringUtils.isBlank(companyWebsite)) {
throw new ParamInvalidException("company_website", "Required Param company_website not found");
}
}
if (clientPayType.indexOf("2") != -1) {
if (StringUtils.isBlank(companyPhoto)) {
throw new ParamInvalidException("company_photo", "Required Param company_photo not found");
}
if (StringUtils.isBlank(storePhoto)) {
throw new ParamInvalidException("store_photo", "Required Param store_photo not found");
}
}
}
public JSONObject payConfig() {
JSONObject config = (JSONObject) JSON.toJSON(this);
config.put("alipayindustry", alipayindustry);
config.put("industry", wechatindustry);
config.put("royalpayindustry", royalpayindustry);
return config;
}
}

@ -0,0 +1,137 @@
package au.com.royalpay.payment.manage.gateway.beans;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import au.com.royalpay.payment.manage.merchants.beans.ClientAuthFilesInfo;
import au.com.royalpay.payment.tools.exceptions.BadRequestException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Date;
/**
* Created by yixian on 2016-06-29.
*/
@Data
public class ClientRegisterInfo {
private org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());
@JSONField(name = "apply_id")
private String applyId;
@JSONField(name = "parent_partner_code")
private String parentPartnerCode;
@JSONField(name = "notify_url")
private String notifyUrl;
@JSONField(name = "company_info")
private ClientCompanyConfig companyConfig;
@JSONField(name = "contact_info")
private ClientContactConfig contactConfig;
@JSONField(name = "legal_info")
private ClientLegalConfig legalConfig;
@JSONField(name = "pay_info")
private ClientPayConfig payConfig;
@JSONField(name = "settle_info")
private ClientSettleConfig settleConfig;
@JSONField(name = "compliance_file_info")
private ClientComplianceFileConfig complianceFileConfig;
private static String[] WHITE_LIST = {"parentPartnerCode", "notifyUrl"};
public void checkParamsInvalid() {
try {
for (Field field : getClass().getDeclaredFields()) {
field.setAccessible(true);
if (field.get(this) == null && !Arrays.asList(WHITE_LIST).contains(field.getName())) {
throw new ParamInvalidException(field.getName(), "Required Param " + field.getName() +" not found");
}
}
companyConfig.checkParamsInvalid();
contactConfig.checkParamsInvalid();
legalConfig.checkParamsInvalid();
payConfig.checkParamsInvalid();
settleConfig.checkParamsInvalid();
complianceFileConfig.checkParamsInvalid();
} catch (IllegalAccessException e) {
logger.error("gateway api register client error : {}", e.getMessage());
throw new BadRequestException("Params Format Error");
}
}
public JSONObject insertClientInfo(String clientMoniker, String bdUserName, boolean hasParentBoolean, int parentClientId) {
JSONObject client = new JSONObject();
client.putAll(companyConfig.basicInfo());
client.put("logo_thumbnail", companyConfig.getLogoId());
client.putAll(contactConfig.contractInfo());
client.putAll(payConfig.payConfig());
client.put("create_time", new Date());
client.put("ali_sub_merchant_id", clientMoniker);
client.put("credential_code", RandomStringUtils.random(32, true, true));
client.put("creator", applyId);
client.put("bd_user", applyId);
client.put("bd_user_name", bdUserName);
client.put("client_moniker", clientMoniker);
if (hasParentBoolean && parentClientId != 0) {
client.put("parent_client_id", parentClientId);
}
client.put("source", 5);
return client;
}
public JSONObject insertClientConfigInfo(int clientId, String clientMoniker) {
JSONObject clientConfig = new JSONObject();
clientConfig.putAll(payConfig.payConfig());
clientConfig.put("notify_url", notifyUrl);
clientConfig.put("client_id", clientId);
clientConfig.put("client_moniker", clientMoniker);
return clientConfig;
}
public JSONObject insertClientLegalInfo(int clientId) {
JSONObject clientLegalInfo = new JSONObject();
clientLegalInfo.putAll(legalConfig.clientLegalInfo());
clientLegalInfo.putAll(contactConfig.legalAddressInfo());
clientLegalInfo.put("client_id", clientId);
return clientLegalInfo;
}
public JSONObject insertBankInfo(int clientId) {
JSONObject bankInfo = settleConfig.insertBankInfo();
bankInfo.put("client_id", clientId);
return bankInfo;
}
public ClientAuthFilesInfo insertClientComplianceInfo() {
ClientAuthFilesInfo file = new ClientAuthFilesInfo();
file.setFile_bank_info(complianceFileConfig.getBankStatement());
file.setFile_id_info(complianceFileConfig.getId());
file.setFile_company_info(complianceFileConfig.getCertOfRegistration());
file.setUtility_bill_info(complianceFileConfig.getUtilityBill());
file.setId_type(complianceFileConfig.getIdType());
file.setBeneficiary_id_title(complianceFileConfig.getIdTitle());
file.setOther_id_title_desc(complianceFileConfig.getIdTitleDesc());
return file;
}
public JSONObject insertClientRateInfo(JSONObject defaultRateConfig) {
JSONObject rate = new JSONObject();
rate.put("clean_days", settleConfig.getCleanDays());
rate.put("active_time", settleConfig.getActiveTime());
rate.put("expiry_time", settleConfig.getExpireTime());
rate.put("wechat_rate_value", settleConfig.getWechatRate());
rate.put("alipay_rate_value", settleConfig.getAlipayRate());
rate.put("alipayonline_rate_value", settleConfig.getAlipayOnlineRate());
rate.put("bestpay_rate_value", getDefaultRate(defaultRateConfig, String.valueOf(settleConfig.getCleanDays()),"Bestpay"));
rate.put("jd_rate_value", getDefaultRate(defaultRateConfig, String.valueOf(settleConfig.getCleanDays()),"JDpay"));
rate.put("Rpay_rate_value", getDefaultRate(defaultRateConfig, String.valueOf(settleConfig.getCleanDays()),"Rpay"));
rate.put("cb_bankpay_rate_value", getDefaultRate(defaultRateConfig, String.valueOf(settleConfig.getCleanDays()),"CB_Bankpay"));
return rate;
}
private String getDefaultRate(JSONObject defaultRateConfig, String cleanDays, String rateKey) {
JSONObject config = defaultRateConfig.getJSONObject("t" + cleanDays);
return config.getString(rateKey);
}
}

@ -0,0 +1,88 @@
package au.com.royalpay.payment.manage.gateway.beans;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import au.com.royalpay.payment.tools.exceptions.BadRequestException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import java.lang.reflect.Field;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Data
public class ClientSettleConfig {
@JSONField(name = "swift_code")
private String swiftCode;
@JSONField(name = "bsb_no")
private String bsbNo;
private String bank;
private String city;
private String address;
private String system;
private String postcode;
private String state;
private String branch;
@JSONField(name = "account_no")
private String accountNo;
@JSONField(name = "account_name")
private String accountName;
@JSONField(name = "clean_days")
private int cleanDays;
@JSONField(name = "wechat_rate")
private String wechatRate;
@JSONField(name = "alipay_rate")
private String alipayRate;
@JSONField(name = "alipay_online_rate")
private String alipayOnlineRate;
@JSONField(name = "transaction_fee")
private String transactionFee;
@JSONField(name = "active_time")
private String activeTime;
@JSONField(name = "expire_time")
private String expireTime;
private static Pattern ACCOUNT_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9 &]+$");
public void checkParamsInvalid() throws IllegalAccessException {
for (Field field : getClass().getDeclaredFields()) {
field.setAccessible(true);
if (field.get(this) == null) {
throw new ParamInvalidException(field.getName(), "Required Param " + field.getName() +" not found");
}
}
}
public JSONObject insertBankInfo() {
JSONObject bankInfo = new JSONObject();
if (swiftCode.length() > 12) {
throw new BadRequestException("PARAM_ERROR:Switft code must be less than 12 characters");
}
if (bsbNo.length() > 6) {
throw new BadRequestException("PARAM_ERROR:BSB No must be less than 6 characters");
}
if (accountNo.length() > 20) {
throw new BadRequestException("PARAM_ERROR:Account No must be less than 20 characters");
}
if (accountName.length() > 50) {
throw new BadRequestException("PARAM_ERROR:Account Name must be less than 50 characters");
}
Matcher matcher = ACCOUNT_NAME_PATTERN.matcher(accountName);
if (!matcher.matches()) {
throw new BadRequestException("PARAM_ERROR:Invalid Account Name format");
}
bankInfo.put("swift_code", swiftCode);
bankInfo.put("bsb_no", bsbNo);
bankInfo.put("account_no", accountNo);
bankInfo.put("account_name", accountName);
bankInfo.put("bank", bank);
bankInfo.put("city", city);
bankInfo.put("address", address);
bankInfo.put("system", system);
bankInfo.put("postcode", postcode);
bankInfo.put("state", state);
bankInfo.put("branch", branch);
return bankInfo;
}
}

@ -0,0 +1,14 @@
package au.com.royalpay.payment.manage.gateway.core;
import com.alibaba.fastjson.JSONObject;
public interface GatewayMerchantApply {
JSONObject validOrgV200(String shortId);
JSONObject applicationMerchant(JSONObject org, JSONObject registerInfo);
JSONObject getMerchantStatus(JSONObject org, String clientMoniker);
void notifyOrgMerchantStatus(JSONObject client);
}

@ -0,0 +1,255 @@
package au.com.royalpay.payment.manage.gateway.core.impls;
import au.com.royalpay.payment.core.exceptions.InvalidShortIdException;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import au.com.royalpay.payment.manage.gateway.beans.ClientRegisterInfo;
import au.com.royalpay.payment.manage.gateway.core.GatewayMerchantApply;
import au.com.royalpay.payment.manage.management.sysconfig.core.impls.PermissionPartnerManagerImpl;
import au.com.royalpay.payment.manage.mappers.log.GatewayClientApplyNotifyLogMapper;
import au.com.royalpay.payment.manage.mappers.system.*;
import au.com.royalpay.payment.manage.merchants.beans.ClientAuthFilesInfo;
import au.com.royalpay.payment.manage.merchants.core.ClientManager;
import au.com.royalpay.payment.manage.system.core.impl.ClientContractServiceImpl;
import au.com.royalpay.payment.tools.env.SysConfigManager;
import au.com.royalpay.payment.tools.exceptions.BadRequestException;
import au.com.royalpay.payment.tools.exceptions.ServerErrorException;
import au.com.royalpay.payment.tools.threadpool.RoyalThreadPoolExecutor;
import cn.yixblog.platform.http.HttpRequestGenerator;
import cn.yixblog.platform.http.HttpRequestResult;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Date;
import static au.com.royalpay.payment.tools.codec.RSACrypt.loadPrivateKey;
@Service
public class GatewayMerchantApplyImpl implements GatewayMerchantApply {
private Logger logger = LoggerFactory.getLogger(ClientContractServiceImpl.class);
@Resource
private OrgMapper orgMapper;
@Resource
private OrgSignInfoMapper orgSignRsaMapper;
@Resource
private ClientMapper clientMapper;
@Resource
private ManagerMapper managerMapper;
@Resource
private ClientConfigMapper clientConfigMapper;
@Resource
private SysClientLegalPersonMapper sysClientLegalPersonMapper;
@Resource
private PermissionPartnerManagerImpl permissionPartnerManagerImpl;
@Resource
private ClientBDMapper clientBDMapper;
@Resource
private ClientBankAccountMapper clientBankAccountMapper;
@Resource
private ClientManager clientManager;
@Resource
private SysConfigManager sysConfigManager;
@Resource
private RoyalThreadPoolExecutor royalThreadPoolExecutor;
@Resource
private GatewayClientApplyNotifyLogMapper gatewayClientApplyNotifyLogMapper;
@Override
public JSONObject validOrgV200(String shortId) {
JSONObject orgSignJson = orgSignRsaMapper.findOrgSignInfo(shortId);
JSONObject org = orgMapper.findOne(orgSignJson.getInteger("org_id"));
if (org == null) {
throw new InvalidShortIdException();
}
return org;
}
@Override
@Transactional
public JSONObject applicationMerchant(JSONObject org, JSONObject registerInfo) {
ClientRegisterInfo registerBean = JSONObject.toJavaObject(registerInfo, ClientRegisterInfo.class);
registerBean.checkParamsInvalid();
JSONObject result = new JSONObject();
JSONObject manager = managerMapper.findAvailableByLoginId(registerBean.getApplyId());
if (manager == null) {
throw new ParamInvalidException("applyId","applyId is invalid");
}
boolean hasParentBoolean = StringUtils.isNotBlank(registerBean.getParentPartnerCode());
int parentClientId = 0;
if (hasParentBoolean) {
JSONObject parentClient = clientMapper.findClientByMoniker(registerBean.getParentPartnerCode());
if (parentClient == null) {
throw new ParamInvalidException("parentPartnerCode","parentPartnerCode is invalid");
}
parentClientId = parentClient.getIntValue("client_id");
}
try {
JSONObject client = registerBean.insertClientInfo(clientManager.initMerchantCode(), manager.getString("display_name"), hasParentBoolean, parentClientId);
client.put("org_id", org.getString("org_id"));
clientMapper.save(client);
clientConfigMapper.save(registerBean.insertClientConfigInfo(client.getIntValue("client_id"),client.getString("client_moniker")));
sysClientLegalPersonMapper.save(registerBean.insertClientLegalInfo(client.getIntValue("client_id")));
permissionPartnerManagerImpl.permissionClientModuleSave(client.getIntValue("client_id"), client.getString("client_moniker"));
JSONObject clientBd = new JSONObject();
clientBd.put("client_id", client.getIntValue("client_id"));
clientBd.put("bd_id", manager.getString("manager_id"));
clientBd.put("bd_name", manager.getString("display_name"));
clientBd.put("create_time", new Date());
clientBd.put("create_id", manager.getString("manager_id"));
clientBd.put("start_date", new Date());
clientBd.put("proportion", 1);
clientBDMapper.saveBD(clientBd);
clientBankAccountMapper.save(registerBean.insertBankInfo(client.getIntValue("client_id")));
//todo 合规文件待增加source_agree_file
ClientAuthFilesInfo clientAuthFilesInfo = registerBean.insertClientComplianceInfo();
clientManager.uploadAuthFiles(manager, client.getString("client_moniker"), clientAuthFilesInfo);
JSONObject rateConfig = registerBean.insertClientRateInfo(JSONObject.parseObject(sysConfigManager.getSysConfig().getString("sys_rates")));
clientManager.newConfigRate(manager, client.getString("client_moniker"), rateConfig);
clientManager.commitToCompliance(client.getString("client_moniker"), manager);
result.put("parnter_code", client.getString("client_moniker"));
result.put("credential_code", client.getString("credential_code"));
result.put("company_name", client.getString("company_name"));
result.put("short_name", client.getString("short_name"));
} catch (Exception e) {
logger.error("gateway api register fail :{}", e.getMessage());
throw new BadRequestException("PARAM_ERROR:Params length too long");
}
result.put("partner_status", "PROCESSING");
return result;
}
@Override
public JSONObject getMerchantStatus(JSONObject org, String clientMoniker) {
JSONObject client = clientMapper.findClientByMoniker(clientMoniker);
if (client == null) {
throw new InvalidShortIdException();
}
if (client.getIntValue("org_id") != org.getIntValue("org_id")) {
logger.error("This client was not belong to your organization,queryClient:{},orgID:{}", clientMoniker, org.getIntValue("org_id"));
throw new InvalidShortIdException();
}
JSONObject result = new JSONObject();
result.put("partner_code", clientMoniker);
result.put("credential_code", client.getString("credential_code"));
result.put("company_name", client.getString("company_name"));
result.put("short_name", client.getString("short_name"));
result.put("apply_time", DateFormatUtils.format(client.getDate("create_time"), "yyyy-MM-dd HH:mm:ss"));
result.put("apply_id", client.getString("creator"));
int approveResult = client.getIntValue("approve_result");
String clientStatus = "";
switch (approveResult) {
case 1:
clientStatus = "PASS";
break;
case 4:
clientStatus = "PROCESSING";
break;
case 5:
clientStatus = "REFUSED";
break;
default:
clientStatus = "PROCESSING";
break;
}
result.put("partner_status", clientStatus);
if ( approveResult == 1 || approveResult == 5) {
result.put("approve_time", DateFormatUtils.format(client.getDate("approve_time"), "yyyy-MM-dd HH:mm:ss"));
if (approveResult == 5) {
result.put("refuse_description", client.getString("refuse_remark"));
}
}
return result;
}
@Override
public void notifyOrgMerchantStatus(JSONObject client) {
String clientMoniker = client.getString("client_moniker");
if (client.getIntValue("source") != 5) {
return;
}
JSONObject clientConfig = clientConfigMapper.find(client.getIntValue("client_id"));
if (StringUtils.isBlank(clientConfig.getString("notify_url"))) {
return;
}
String notifyUrl = clientConfig.getString("notify_url");
JSONObject org = orgMapper.findOne(client.getInteger("org_id"));
JSONObject merchantStatus = getMerchantStatus(org, clientMoniker);
merchantStatus.put("nonce_str", RandomStringUtils.random(15, true, true));
merchantStatus.put("sign_type", "RSA2");
merchantStatus.put("url", notifyUrl);
JSONObject signInfo = orgSignRsaMapper.findByOrgId(org.getInteger("org_id"));
String signStr = sign(JSONObject.toJSONBytes(merchantStatus, SerializerFeature.MapSortField), signInfo.getString("platform_private_key"));
JSONObject respJson = new JSONObject();
respJson.put("data", merchantStatus);
respJson.put("sign", signStr);
logger.info("ApiV2 Response : {}", JSONObject.toJSONString(respJson, SerializerFeature.MapSortField));
JSONObject log = preInsertServerNotifyLog(client, notifyUrl);
royalThreadPoolExecutor.execute(() -> {
logger.debug("开始推送商户状态[{}]异步通知[{}]:", clientMoniker, notifyUrl);
HttpRequestGenerator gen = new HttpRequestGenerator(notifyUrl, RequestMethod.POST);
gen.setJSONEntity(respJson);
HttpRequestResult result = gen.execute();
if (result.isSuccess()) {
log.put("success", true);
log.put("http_code", result.getStatusCode());
log.put("updatetime", new Date());
gatewayClientApplyNotifyLogMapper.update(log);
logger.debug("商户状态[{}]异步通知[{}]推送完成:[{}]", clientMoniker, notifyUrl, result.getStatusCode());
}else {
Throwable exp = result.getException();
log.put("success", false);
log.put("http_code", result.getStatusCode());
log.put("err_msg", exp == null ? null : exp.getMessage());
log.put("updatetime", new Date());
gatewayClientApplyNotifyLogMapper.update(log);
logger.debug("商户状态[{}]异步通知[{}]推送失败:[{}]-[{}]", clientMoniker, notifyUrl, result.getStatusCode(), exp.getMessage());
}
});
}
private JSONObject preInsertServerNotifyLog(JSONObject client,String notifyUrl) {
int clientId = client.getIntValue("client_id");
JSONObject log = gatewayClientApplyNotifyLogMapper.findHistoryByClientId(clientId);
if (log == null) {
log = new JSONObject();
log.put("org_id", client.getString("org_id"));
log.put("client_id", clientId);
log.put("notify_url", notifyUrl);
log.put("addtime", new Date());
log.put("success", 0);
log.put("http_code", 0);
gatewayClientApplyNotifyLogMapper.saveLog(log);
}
return log;
}
private String sign(byte[] source, String privateKey) {
try {
PrivateKey priKey = loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes(StandardCharsets.UTF_8)));
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(priKey);
signature.update(source);
byte[] signed = signature.sign();
return Base64.encodeBase64URLSafeString(signed);
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
//shall never happen
throw new ServerErrorException(e);
}
}
}

@ -0,0 +1,59 @@
package au.com.royalpay.payment.manage.gateway.web;
import au.com.royalpay.payment.core.exceptions.InvalidShortIdException;
import au.com.royalpay.payment.core.utils.PaymentValidUtils;
import au.com.royalpay.payment.manage.gateway.advice.Gtw2Ctrl;
import au.com.royalpay.payment.manage.gateway.core.GatewayMerchantApply;
import au.com.royalpay.payment.tools.connections.attachment.core.AttachmentClient;
import com.alibaba.fastjson.JSONObject;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
/**
* @author taylor
*/
@RestController
@RequestMapping("/api/v1.0/gateway/partners/{shortId}")
@Gtw2Ctrl
public class GtwPayController {
@Resource
private GatewayMerchantApply gatewayMerchantApply;
@Resource
private AttachmentClient attachmentClient;
@PostMapping(value = "/merchant/application")
public JSONObject applicationMerchant(@RequestBody JSONObject registerInfo, Errors errors,
@PathVariable String shortId) {
JSONObject org = gatewayMerchantApply.validOrgV200(shortId);
PaymentValidUtils.handleValidErrors(errors);
return gatewayMerchantApply.applicationMerchant(org, registerInfo);
}
@GetMapping(value = "/merchant/{partner_code}/status")
public JSONObject getMerchantStatus(@PathVariable String shortId,
@PathVariable String partner_code) {
JSONObject org = gatewayMerchantApply.validOrgV200(shortId);
return gatewayMerchantApply.getMerchantStatus(org, partner_code);
}
@PostMapping("/attachment/files")
public JSONObject uploadFile(@PathVariable String shortId,@RequestParam MultipartFile file) throws Exception {
JSONObject org = gatewayMerchantApply.validOrgV200(shortId);
if (org == null) {
throw new InvalidShortIdException();
}
JSONObject fileInfo = attachmentClient.uploadFile(file, false);
fileInfo.put("file_type", fileInfo.getString("filetype"));
fileInfo.remove("filepath");
fileInfo.remove("length");
fileInfo.remove("fileid");
fileInfo.remove("filetype");
fileInfo.put("file_url", fileInfo.getString("url"));
return fileInfo;
}
}

@ -0,0 +1,30 @@
package au.com.royalpay.payment.manage.mappers.log;
import cn.yixblog.support.mybatis.autosql.annotations.AdvanceSelect;
import cn.yixblog.support.mybatis.autosql.annotations.AutoMapper;
import cn.yixblog.support.mybatis.autosql.annotations.AutoSql;
import cn.yixblog.support.mybatis.autosql.annotations.SqlType;
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* Created by davep on 2016-07-22.
*/
@AutoMapper(tablename = "gateway_clientApply_notify_log", pkName = "id")
public interface GatewayClientApplyNotifyLogMapper {
@AutoSql(type = SqlType.INSERT)
void saveLog(JSONObject log);
@AutoSql(type = SqlType.UPDATE)
void update(JSONObject notice);
@AutoSql(type = SqlType.SELECT)
@AdvanceSelect(addonWhereClause = "success=0 and addtime(`addtime`,'24:00:00')>now()")
List<JSONObject> listErrorLogsIn24Hour();
@AutoSql(type = SqlType.SELECT)
JSONObject findHistoryByClientId(@Param("client_id") int clientId);
}

@ -72,4 +72,6 @@ public interface ManagerMapper {
List<String> listDevAndBdOpenId();
List<JSONObject> findBdById(@Param("org_id")String org_id);
}

@ -0,0 +1,27 @@
package au.com.royalpay.payment.manage.mappers.system;
import cn.yixblog.support.mybatis.autosql.annotations.AutoMapper;
import cn.yixblog.support.mybatis.autosql.annotations.AutoSql;
import cn.yixblog.support.mybatis.autosql.annotations.SqlType;
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
@AutoMapper(tablename = "org_sign_info", pkName = "org_id", keyGenerator = Jdbc3KeyGenerator.class)
public interface OrgSignInfoMapper {
@AutoSql(type = SqlType.SELECT)
JSONObject findByOrgId(@Param("org_id") int orgId);
@AutoSql(type = SqlType.SELECT)
JSONObject findOrgSignInfo(@Param("gateway_short_id") String orgId);
int getPartnercode(@Param("codes") String codes);
@AutoSql(type = SqlType.UPDATE)
void update(JSONObject signInfo);
@AutoSql(type = SqlType.INSERT)
void insert(JSONObject signInfo);
}

@ -26,6 +26,7 @@ import au.com.royalpay.payment.manage.application.core.SimpleClientApplyService;
import au.com.royalpay.payment.manage.complianceAudit.core.ClientComplianceApply;
import au.com.royalpay.payment.manage.dev.bean.TestMerchantAccountInfo;
import au.com.royalpay.payment.manage.device.core.DeviceManager;
import au.com.royalpay.payment.manage.gateway.core.GatewayMerchantApply;
import au.com.royalpay.payment.manage.kyc.enums.FilesAuthEnum;
import au.com.royalpay.payment.manage.management.sysconfig.core.impls.PermissionPartnerManagerImpl;
import au.com.royalpay.payment.manage.mappers.financial.FinancialBDConfigMapper;
@ -304,6 +305,8 @@ public class ClientManagerImpl implements ClientManager, ManagerTodoNoticeProvid
private ClientComplianceCompanyMapper clientComplianceCompanyMapper;
@Resource
private IndustryLookupMapper industryLookupMapper;
@Resource
private GatewayMerchantApply gatewayMerchantApply;
@Resource
@ -1122,7 +1125,7 @@ public class ClientManagerImpl implements ClientManager, ManagerTodoNoticeProvid
if (pass == 1) {
createKycAuthStatus(manager,client);
clientModifySupport.processClientConfigModify(new SwitchPermissionModify(manager, clientMoniker, "skip_clearing", false));
if (client.getIntValue("source") == 4) {
if (client.getIntValue("source") == 4 || client.getIntValue("source") == 5) {
List<JSONObject> accounts = clientAccountMapper.listAdminAccounts(client.getIntValue("client_id"));
JSONObject account = accounts.get(0);
sendInitEmail(client, account.getString("username"), "*****");
@ -1130,6 +1133,7 @@ public class ClientManagerImpl implements ClientManager, ManagerTodoNoticeProvid
saveClientAuditProcess(client.getIntValue("client_id"), open_status, 5, "合规通过", manager);
clientModifySupport.processClientConfigModify(new SwitchPermissionModify(manager, clientMoniker, "skip_clearing", false));
clientModifySupport.processClientConfigModify(new SwitchPermissionModify(manager, clientMoniker, "common_sub_merchant_id", false));
gatewayMerchantApply.notifyOrgMerchantStatus(client);
} else if (checkGreenChannel && client.getIntValue("open_status") == 5) {
// 绿色通道通过后不发邮件
logger.info("PASS 绿色通道:" + clientMoniker);
@ -4690,6 +4694,9 @@ public class ClientManagerImpl implements ClientManager, ManagerTodoNoticeProvid
}
}
}
if (client.getIntValue("source") == 5) {
gatewayMerchantApply.notifyOrgMerchantStatus(client);
}
} catch (Exception e) {
logger.error("RefusePartnerError=======:" + clientMoniker + "," + e.getMessage());
}

@ -411,7 +411,6 @@ public class PartnerViewController {
clientManager.refreshPlatformPublicKeyConfig(account);
}
@PartnerMapping(value = "/payment_page_version", method = RequestMethod.PUT)
@ResponseBody
public void changePaymentPage(@RequestBody JSONObject pass, @ModelAttribute(CommonConsts.PARTNER_STATUS) JSONObject account) {

@ -2,6 +2,7 @@ package au.com.royalpay.payment.manage.organizations.beans;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import javax.validation.constraints.NotEmpty;
/**
@ -73,7 +74,6 @@ public class OrgInfo {
if (StringUtils.isNotBlank(senior_parent_org_id)) {
param.put("senior_parent_org_id", senior_parent_org_id);
}
return param;
}
@ -359,4 +359,5 @@ public class OrgInfo {
public void setMin_cb_bankpay_rate(Double min_cb_bankpay_rate) {
this.min_cb_bankpay_rate = min_cb_bankpay_rate;
}
}

@ -23,12 +23,22 @@ public interface OrgManager {
JSONObject saveNewOrg(OrgInfo org);
void updateOrg(int orgId, OrgInfo org);
void updateOrg(int orgId, OrgInfo org, JSONObject manager);
void setPartnerPublicKeyConfig(int orgId, JSONObject manager, String ipWhitelistConfig);
void refreshPlatformPublicKeyConfig(int orgId, JSONObject manager);
List<JSONObject> getReferrers();
JSONObject getCityPartnerPrizeInfoList(int page, int limit,int orgId, JSONObject manager);
String refreshMerchantCode(int orgId, JSONObject manager);
String initMerchantCode();
boolean getMerchantIsValid(String clientMoniker);
void switchPermission(int orgId, String permissionName, boolean enabled);
List<JSONObject> listAllOrg();

@ -2,27 +2,32 @@ package au.com.royalpay.payment.manage.organizations.core.impls;
import au.com.royalpay.payment.manage.mappers.financial.FinancialPartnerCommissionMapper;
import au.com.royalpay.payment.manage.mappers.system.OrgMapper;
import au.com.royalpay.payment.manage.mappers.system.OrgSignInfoMapper;
import au.com.royalpay.payment.manage.organizations.beans.OrgInfo;
import au.com.royalpay.payment.manage.organizations.core.OrgManager;
import au.com.royalpay.payment.tools.codec.RSACrypt;
import au.com.royalpay.payment.tools.exceptions.ForbiddenException;
import au.com.royalpay.payment.tools.utils.PageListUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.miemiedev.mybatis.paginator.domain.Order;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;
/**
* Created by yixian on 2016-10-18.
*/
@ -32,6 +37,8 @@ public class OrgManagerImpl implements OrgManager {
private OrgMapper orgMapper;
@Resource
private FinancialPartnerCommissionMapper financialPartnerCommissionMapper;
@Resource
private OrgSignInfoMapper orgSignInfoMapper;
@Override
public List<JSONObject> listOrgs(boolean detail) {
@ -102,7 +109,13 @@ public class OrgManagerImpl implements OrgManager {
@Override
public JSONObject getOrgDetail(int orgId,JSONObject manager) {
return orgMapper.findOne(orgId);
JSONObject org = orgMapper.findOne(orgId);
JSONObject gatewayInfo = orgSignInfoMapper.findByOrgId(orgId);
if (gatewayInfo != null) {
gatewayInfo.remove("platform_private_key");
org.putAll(gatewayInfo);
}
return org;
}
@Override
@ -113,17 +126,58 @@ public class OrgManagerImpl implements OrgManager {
json.put("sort_no", orgMapper.listAllOrgs().size());
json.put("create_time",new Date());
orgMapper.saveOrg(json);
initOrgGatewayInfo(json);
return json;
}
@Override
public void updateOrg(int orgId, OrgInfo org) {
public void updateOrg(int orgId, OrgInfo org, JSONObject manager) {
JSONObject json = org.toJSON();
checkOrgRate(json);
json.put("org_id", orgId);
orgMapper.updateOrg(json);
}
@Override
@Transactional
public void refreshPlatformPublicKeyConfig(int orgId, JSONObject manager) {
int managerOrgId = manager.getIntValue("org_id");
if (managerOrgId != 0 && managerOrgId != 1 && managerOrgId != orgId) {
throw new ForbiddenException("You have no permission to setting the org");
}
JSONObject org = orgMapper.findOne(orgId);
JSONObject gateway = orgSignInfoMapper.findByOrgId(orgId);
if (gateway == null) {
initOrgGatewayInfo(org);
}else {
JSONObject key = getRsaKey();
gateway.put("platform_public_key", key.getString("public_key"));
gateway.put("platform_private_key", key.getString("private_key"));
gateway.put("last_update_by", manager.getString("manager_id"));
gateway.put("last_update_date", new Date());
orgSignInfoMapper.update(gateway);
}
}
@Override
public void setPartnerPublicKeyConfig(int orgId, JSONObject manager, String publicKey) {
int managerOrgId = manager.getIntValue("org_id");
if (managerOrgId != 0 && managerOrgId != 1 && managerOrgId != orgId) {
throw new ForbiddenException("You have no permission to setting the org");
}
JSONObject org = orgMapper.findOne(orgId);
JSONObject gateway = orgSignInfoMapper.findByOrgId(orgId);
if (gateway == null) {
org.put("mch_public_key", publicKey);
initOrgGatewayInfo(org);
}else {
gateway.put("mch_public_key", publicKey);
gateway.put("last_update_by", manager.getString("manager_id"));
gateway.put("last_update_date", new Date());
orgSignInfoMapper.update(gateway);
}
}
@Override
public List<JSONObject> getReferrers() {
return orgMapper.listOrgs(1,new PageBounds());
@ -139,6 +193,45 @@ public class OrgManagerImpl implements OrgManager {
return null;
}
@Override
public String refreshMerchantCode(int orgId, JSONObject manager) {
String merchantCode = null;
int managerOrgId = manager.getIntValue("org_id");
JSONObject org = orgMapper.findOne(orgId);
if (managerOrgId != 0 && managerOrgId != 1 && managerOrgId != orgId && managerOrgId != org.getIntValue("parent_org_id")) {
throw new ForbiddenException("You have no permission to setting the org");
}
JSONObject gateway = orgSignInfoMapper.findByOrgId(orgId);
merchantCode = initMerchantCode();
if (gateway == null) {
org.put("gateway_short_id", merchantCode);
initOrgGatewayInfo(org);
}else {
gateway.put("gateway_short_id", merchantCode);
gateway.put("last_update_by", manager.getString("manager_id"));
gateway.put("last_update_date", new Date());
orgSignInfoMapper.update(gateway);
}
return merchantCode;
}
@Override
public String initMerchantCode() {
String code = RandomStringUtils.randomAlphanumeric(10).toUpperCase();
if (!getMerchantIsValid(code)) {
return initMerchantCode();
}
return code;
}
@Override
public boolean getMerchantIsValid(String clientMoniker) {
if (orgSignInfoMapper.getPartnercode(clientMoniker) > 0) {
return false;
}
return true;
}
@Override
public void switchPermission(int orgId, String permissionName, boolean enabled) {
JSONObject org = new JSONObject();
@ -272,4 +365,27 @@ public class OrgManagerImpl implements OrgManager {
}
}
}
private JSONObject getRsaKey() {
JSONObject key = new JSONObject();
KeyPair keyPairGen = RSACrypt.generateKeyPairs();
RSAPublicKey publicKey = (RSAPublicKey) keyPairGen.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPairGen.getPrivate();
key.put("public_key", Base64.encodeBase64String(publicKey.getEncoded()));
key.put("private_key", Base64.encodeBase64String(privateKey.getEncoded()));
return key;
}
private void initOrgGatewayInfo(JSONObject org) {
JSONObject key = getRsaKey();
String shortId = org.containsKey("gateway_short_id") ? org.getString("gateway_short_id") : initMerchantCode();
String mchPublicKey = org.containsKey("mch_public_key") ? org.getString("mch_public_key") : null;
org.put("gateway_short_id", shortId);
org.put("mch_public_key", mchPublicKey);
org.put("platform_public_key", key.getString("public_key"));
org.put("platform_private_key", key.getString("private_key"));
org.put("is_valid", 1);
org.put("creation_by", "init");
org.put("creation_date", new Date());
orgSignInfoMapper.insert(org);
}
}

@ -7,16 +7,13 @@ import au.com.royalpay.payment.manage.permission.manager.RequireManager;
import au.com.royalpay.payment.tools.CommonConsts;
import au.com.royalpay.payment.tools.http.HttpUtils;
import au.com.royalpay.payment.tools.permission.enums.ManagerRole;
import com.alibaba.fastjson.JSONObject;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
/**
* Created by yixian on 2016-10-18.
@ -75,9 +72,19 @@ public class OrgManageController {
}
@ManagerMapping(value = "/{orgId}", method = RequestMethod.PUT)
public void updateOrg(@PathVariable int orgId, @RequestBody @Valid OrgInfo org, Errors errors) {
public void updateOrg(@PathVariable int orgId, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager, @RequestBody @Valid OrgInfo org, Errors errors) {
HttpUtils.handleValidErrors(errors);
orgManager.updateOrg(orgId, org);
orgManager.updateOrg(orgId, org, manager);
}
@ManagerMapping(value = "/{orgId}/partner_public_key", method = RequestMethod.PUT)
public void setPartnerPublicKeyConfig(@PathVariable int orgId, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager, @RequestBody JSONObject config) {
orgManager.setPartnerPublicKeyConfig(orgId, manager, config.getString("partner_public_key"));
}
@ManagerMapping(value = "/{orgId}/refresh_platform_public_key", method = RequestMethod.PUT)
public void refreshPlatformPublicKeyConfig(@PathVariable int orgId, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
orgManager.refreshPlatformPublicKeyConfig(orgId, manager);
}
@ManagerMapping(value = "/{orgId}/enable_change_rate",method = RequestMethod.PUT,role = {ManagerRole.ADMIN})
@ -97,4 +104,11 @@ public class OrgManageController {
@RequestParam(defaultValue = "20") int limit, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
return orgManager.getCityPartnerPrizeInfoList(page, limit,orgId,manager);
}
@RequestMapping(value = "/{orgId}/init/merchant_code", method = RequestMethod.GET, produces = "application/json")
public JSONObject initMerchantCode(@PathVariable int orgId, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
JSONObject result = new JSONObject();
result.put("partner_code", orgManager.refreshMerchantCode(orgId, manager));
return result;
}
}

@ -2,15 +2,15 @@
spring.datasource.type = com.zaxxer.hikari.HikariDataSource
#数据源master
spring.datasource.master.schema-name=royalpay_production
spring.datasource.master.host=192.168.1.52:3306
spring.datasource.master.schema-name=royalpay_dev
spring.datasource.master.host=127.0.0.1:3306
spring.datasource.master.jdbc-url=jdbc:mysql://${spring.datasource.master.host}/${spring.datasource.master.schema-name}?useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.master.username=taylor
spring.datasource.master.password=taylor
spring.datasource.master.username=root
spring.datasource.master.password=root
#数据源salve
spring.datasource.slave.schema-name=royalpay_production
spring.datasource.slave.host=192.168.1.52:3306
spring.datasource.slave.schema-name=royalpay_dev
spring.datasource.slave.host=127.0.0.1:3306
spring.datasource.slave.jdbc-url=jdbc:mysql://${spring.datasource.slave.host}/${spring.datasource.slave.schema-name}?useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.slave.username=taylor
spring.datasource.slave.password=taylor
spring.datasource.slave.username=root
spring.datasource.slave.password=root

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="au.com.royalpay.payment.manage.mappers.system.OrgSignInfoMapper">
<select id="getPartnercode" resultType="int">
SELECT count(1)
FROM org_sign_info
where gateway_short_id = #{codes};
</select>
</mapper>

@ -1,6 +1,6 @@
msg.test=测试
error.payment.valid.param_missing=请填写{0}
error.payment.valid.param_missing= {0} 请填写
error.payment.valid.invalid_time=时间格式不正确
error.payment.valid.invalid_channel=不合法的支付通道
error.payment.valid.invalid_fee=不正确的金额

@ -542,8 +542,68 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) {
$scope.listManagers();
})
}
$scope.gateway_sign = {};
$scope.gateway_sign.platform_public_key = $scope.org.platform_public_key;
$scope.gateway_sign.org_id = $scope.org.org_id;
$scope.gateway_sign.mch_public_key = $scope.org.mch_public_key;
$scope.refreshPlatformPubliKey = function () {
$uibModal.open({
templateUrl: '/static/payment/partner/templates/partner_refresh_platform_public_key_dialog.html',
controller: 'clientRefreshPlatformPublicKeyDialogCtrl',
backdrop: false,
size: 'lg',
resolve: {
gateway_sign: function () {
return $scope.gateway_sign;
}
}
}).result.then(function () {
commonDialog.alert({
title: 'Success!',
content: 'RoyalPay Public Key Refresh Successfully',
type: 'success'
})
$state.reload();
})
};
$scope.resetPartnerPubliKey = function () {
$uibModal.open({
templateUrl: '/static/payment/partner/templates/partner_reset_public_key_dialog.html',
controller: 'clientResetPartnerPublicKeyDialogCtrl',
backdrop: false,
size: 'lg',
resolve: {
gateway_sign: function () {
return $scope.gateway_sign;
}
}
}).result.then(function () {
commonDialog.alert({
title: 'Success!',
content: 'Partner Public Key Upload Successfully',
type: 'success'
})
$state.reload();
})
};
$scope.refreshMerchantCode = function () {
commonDialog.confirm({
title: 'Confirm',
content: 'This operation will refresh the gateway short id, Are you sure?'
}).then(function () {
$http.get('/sys/orgs/' + $scope.org.org_id + '/init/merchant_code').then(function (response) {
commonDialog.alert({title: 'Success', content: "Gateway Short Id Refresh Successfully", type: 'success'})
$scope.org.gateway_short_id = response.data.partner_code;
}, function (resp) {
commonDialog.alert({title: 'Error', content: resp.data.message, type: 'error'})
});
})
};
}]);
app.controller('orgDetailParentCtrl', ['$scope', '$http', '$state', 'Upload', '$uibModal','commonDialog', 'org','stateMap', function ($scope, $http, $state, Upload,$uibModal,commonDialog, org,stateMap) {
$scope.merchantCodeChecked = true;
$scope.merchantIsValid = true;
$scope.types = angular.copy(types);
$scope.states = stateMap.configs();
$scope.commission_types = angular.copy(commission_types);
@ -589,62 +649,96 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) {
commonDialog.alert({title: 'Error', content: resp.data.message, type: 'error'})
})
};
/*
$scope.toggleRateEditable = function () {
if($scope.org.rate_editable==org.data.rate_editable){
return;
}
$http.put('/sys/orgs/'+$scope.org.org_id+'/enable_change_rate',{enabled:$scope.org.rate_editable}).then(function () {
$scope.gateway_sign = {};
$scope.gateway_sign.platform_public_key = $scope.org.platform_public_key;
$scope.gateway_sign.org_id = $scope.org.org_id;
$scope.gateway_sign.mch_public_key = $scope.org.mch_public_key;
},function (resp) {
commonDialog.alert({title: 'Error', content: resp.data.message, type: 'error'});
$scope.refreshPlatformPubliKey = function () {
$uibModal.open({
templateUrl: '/static/payment/partner/templates/partner_refresh_platform_public_key_dialog.html',
controller: 'clientRefreshPlatformPublicKeyDialogCtrl',
backdrop: false,
size: 'lg',
resolve: {
gateway_sign: function () {
return $scope.gateway_sign;
}
}
}).result.then(function () {
commonDialog.alert({
title: 'Success!',
content: 'RoyalPay Public Key Refresh Successfully',
type: 'success'
})
};
$scope.search = {role:'1111111'};
$scope.listManagers = function () {
$http.get('/sys/manager_accounts',{params:{org_id:$scope.org.org_id}}).then(function (resp) {
$scope.managers = resp.data;
$state.reload();
})
};
$scope.listManagers();
$scope.modifyManager = function (manager) {
$scope.resetPartnerPubliKey = function () {
$uibModal.open({
templateUrl: '/static/config/managers/templates/modify.html',
controller: 'modifyManagerCtrl',
templateUrl: '/static/payment/partner/templates/partner_reset_public_key_dialog.html',
controller: 'clientResetPartnerPublicKeyDialogCtrl',
backdrop: false,
size: 'lg',
resolve: {
manager: function () {
return angular.copy(manager);
gateway_sign: function () {
return $scope.gateway_sign;
}
}
}).result.then(function () {
$scope.listManagers();
commonDialog.alert({
title: 'Success!',
content: 'Org Public Key Upload Successfully',
type: 'success'
})
$state.reload();
})
};
$scope.disableManager = function (manager) {
$scope.refreshMerchantCode = function () {
commonDialog.confirm({
title: 'Confirm!',
content: 'You are setting manager ' + manager.display_name + ' disabled.Are you sure?'
title: 'Confirm',
content: 'This operation will refresh the gateway short id, Are you sure?'
}).then(function () {
$http.delete('/sys/manager_accounts/' + manager.manager_id).then(function () {
$scope.listManagers();
$http.get('/sys/orgs/' + $scope.org.org_id + '/init/merchant_code').then(function (response) {
commonDialog.alert({title: 'Success', content: "Gateway Short Id Refresh Successfully", type: 'success'})
$scope.org.gateway_short_id = response.data.partner_code;
}, function (resp) {
commonDialog.alert({title: 'Error', content: resp.data.message, type: 'error'})
})
});
})
};
$scope.newManager = function () {
$uibModal.open({
templateUrl: '/static/config/managers/templates/new_manager.html',
controller: 'newManagerCtrl',
resolve: {
org: angular.copy($scope.org)
}]);
app.controller('clientResetPartnerPublicKeyDialogCtrl', ['$scope', '$http', 'gateway_sign', function ($scope, $http, gateway_sign) {
$scope.gateway_sign = angular.copy(gateway_sign);
$scope.uploadPublicKey = function (mch_public_key) {
$scope.errmsg = null;
$http.put('/sys/orgs/' + $scope.gateway_sign.org_id + '/partner_public_key', {partner_public_key: mch_public_key}).then(function () {
$scope.$close();
}, function (resp) {
$scope.errmsg = resp.data.message;
})
}
}).result.then(function () {
$scope.listManagers();
}]);
app.controller('clientRefreshPlatformPublicKeyDialogCtrl', ['$scope', '$http', 'gateway_sign', 'commonDialog', function ($scope, $http, gateway_sign, commonDialog) {
$scope.gateway_sign = angular.copy(gateway_sign);
$scope.copyPublicKey = function () {
var e = document.getElementById("c-cpKey");
e.select();
var successful = document.execCommand("Copy");
if (successful) {
commonDialog.alert({title: 'Success', content: '已复制到剪切板!', type: 'success'});
} else {
commonDialog.alert({title: 'Error', content: '您的浏览器不支持!请手动复制', type: 'error'});
}
};
$scope.refreshPublicKey = function () {
$scope.errmsg = null;
$http.put('/sys/orgs/' + $scope.gateway_sign.org_id + '/refresh_platform_public_key').then(function () {
$scope.$close();
}, function (resp) {
$scope.errmsg = resp.data.message;
})
}*/
}
}]);
app.controller('newOrgCtrl', ['$scope', '$http', '$state', 'Upload', 'commonDialog','stateMap', function ($scope, $http, $state, Upload, commonDialog,stateMap) {
$scope.types = angular.copy(types);
@ -711,7 +805,6 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) {
})
};
}]);
app.controller('modifyManagerCtrl', ['$scope', '$http', 'manager', function ($scope, $http, manager) {
$scope.manager = manager;
$scope.isOrgModify = true;

@ -440,6 +440,36 @@
</div>
</div>
</uib-tab>
<uib-tab heading="Gateway API" ng-if="org.type == 0 && org.org_id != 1">
<form class="form-horizontal margin-top" name="org_gateway_form">
<div class="form-group">
<label class="control-label col-sm-2">Gateway Short Id</label>
<div class="col-sm-8">
<p class="form-control-static">
{{org.gateway_short_id||'初始化'}}
<a role="button" ng-click="refreshMerchantCode()"><i class="fa fa-refresh"></i></a>
</p>
</div>
</div>
<div class="form-group"
ng-class="{'has-error':org_form.gateway_short_id.$invalid && org_form.gateway_short_id.$dirty}">
<label class="col-sm-2 control-label">RoyalPay Public Key</label>
<div class="col-sm-10" style="margin-top: 8px;">
<a role="button" ng-click="refreshPlatformPubliKey()">
View
</a>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Org Public Key</label>
<div class="col-sm-10" style="margin-top: 8px;">
<a role="button" ng-click="resetPartnerPubliKey()">
Upload
</a>
</div>
</div>
</form>
</uib-tab>
<uib-tab heading="Permission" ng-if="org.type == 0">
<form class="form-horizontal margin-top" name="org_permission_form">
<div class="form-group">

@ -432,6 +432,36 @@
<!--<button class="btn btn-success col-sm-offset-2" ng-click="update()"><i class="fa fa-save"></i> Update</button>-->
</form>
</uib-tab>
<uib-tab heading="Gateway API" ng-if="org.type == 0 && org.org_id != 1">
<form class="form-horizontal margin-top" name="org_gateway_form">
<div class="form-group">
<label class="control-label col-sm-2">Gateway Short Id</label>
<div class="col-sm-8">
<p class="form-control-static">
{{org.gateway_short_id||'初始化'}}
<a role="button" ng-click="refreshMerchantCode()"><i class="fa fa-refresh"></i></a>
</p>
</div>
</div>
<div class="form-group"
ng-class="{'has-error':org_form.gateway_short_id.$invalid && org_form.gateway_short_id.$dirty}">
<label class="col-sm-2 control-label">RoyalPay Public Key</label>
<div class="col-sm-10" style="margin-top: 8px;">
<a role="button" ng-click="refreshPlatformPubliKey()">
View
</a>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Org Public Key</label>
<div class="col-sm-10" style="margin-top: 8px;">
<a role="button" ng-click="resetPartnerPubliKey()">
Upload
</a>
</div>
</div>
</form>
</uib-tab>
</uib-tabset>
</div>
</div>

@ -43,7 +43,7 @@
</style>
<section class="content-header">
<h1>
<span ng-bind="partner.company_name"></span>
<span ng-bind="partner.company_name"></span><span ng-if="partner.source==5" style="color:red;font-size:14px">(Gateway API)</span>
<i ng-if="partner.parent_client_id" class="fa fa-sitemap" title="Sub Partner"></i>
<a class="text-primary" ng-if="'00011'|withRole" title="Mock Login"
ng-href="/global/userstatus/current_manager/clients/{{partner.client_moniker}}/auth" target="_blank"><i

@ -1,25 +1,39 @@
package au.com.royalpay.payment.manage.citypartner.core.impls;
import au.com.royalpay.payment.manage.citypartner.core.CityPartnerPrizeService;
import au.com.royalpay.payment.tools.exceptions.ServerErrorException;
import cn.yixblog.platform.http.HttpRequestGenerator;
import cn.yixblog.platform.http.HttpRequestResult;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import static au.com.royalpay.payment.tools.codec.RSACrypt.loadPrivateKey;
/**
* Created by wangning on 09/01/2018.
*/
@SpringBootTest
@ActiveProfiles({"local","alipay","wechat","jd","bestpay"})
@RunWith(SpringRunner.class)
public class CityPartnerPrizeServiceImplTest {
static String PRIKEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCdIiy3fFUrZx4X0aIU37PGzViqG03yRDprSk2tqhORnAiZL3sLNFsjmy2FR4+84bksp2VxIc+rMot+4iFIAmpK50t6qj2Fz7sOO5DMSN0pRN9flIqQ1RFKYnIQN+BymfJ9bXbMN2aN+sbfZzZRTAZPtJuES9JIrmUDi4NwNeqBSjhflUqlyYx3ejMx2CrxHAS+35W5fAK88e//9SQiMdKHzNPFl4vXtCMqTY7Mk7febLfsG0aaRVMM/QOeT57sszB3Wib3wUFi9xGsqdqLi0skAWc4QmOGOoue7uvieghFWZXETfFN/K3wSz5TzVS55ma2u3KOkn8/M4E7J96RHzAPAgMBAAECggEAet+ueA0RzM7mCVo0lH4Z5uvM2bhgS4Ju7Fc+Rv8oLkUFtEQcw7Y9TqqZ/g7np5wbYX/FI6J88jKkQqQxwk2hMNGNhG57jZfTfl217QlNaGgjBGrzsC3tR22UJHqNWRBpPwvKSgdIet4PhcMABrKcfNeOhPWFirBU7WC7d5OxvUdA3oCnZXZ7nGxgyX06actjb3GhIUybi4DJosCY3NkBsUXWLh45Kmm8IfJv29cd+VrIBn5i1+mMd6hECmiN03ToH9dc3o1aS4YGJirvkf1q1oiJJMT7exacuZiTrRfUh+NIemm8oaBYJj9PMcy5PEtS/ZyJe7jzDEnbV71i5dnkAQKBgQDhXej3o3KyvP9h/nwH/gifK/Urai0u/SB6CScb8c0xzHoQhomjNaaHHKX82j8zDYMvg7yNWHEo5WdCEcenvjO4OWkbhL9brBJnpN5QyfPtjijUh/8PFNKu/NP0PISkFjuAOp+LVgMRgrfQL/wu1/zp6jgsAXckauUIBNITZPTWrwKBgQCyffLy1Cc1tSovzXchty7TLU49IzNZQ3keMEy8MWw6YFS5PGUSEixtjvsAuzoYMg6w7F/LxK8jMfOcDPza1AJUQIByXPoZs4jm31j6EPjPYP+ocQ04Ji+OOcbR5TOlFamNMnjQNlTqpEmNYpQcKp8AOyGm0dSMHe7YUKqzaymUoQKBgQDNQ4aL/s/aIjAM5ge8E9FwgE4GY+eRc7Wf0TRQzHSTVeUbph44jAYH67z3RyTm7/i7TyZuKs6ua/sXfzA1BRUARzIHgWn1Kg19Xvmp5bcJeECSCufxqYqXHOpD+tboyOMa0Mo903JqAYA/22S6mbjeqJjO4+rLPZ0rJ5DbX0ltOwKBgA+3rYwaiHVfRZ69/g6W/eWUqL4TenMS0PiKkkdEJt6hGvTQz6methDTtWCkHAKDbe3ActMTt8RmoqgMMLvoTWgz4duwOknHGHgUFNa4ZeCFDx47Dknyet+QUOSsxTZ1SN/pIOBc2G9tFhkAJECytBumGVmCQrAv9pdPyyhPeHLhAoGATvtEmi3oYPQtoy8qDEhI8wCXrrKIZh2a7ahRjt8B056HZ26EjalKg2Yz+5WTRbS6Bgr8ZN+12wRl7CbjWyr+loOEsMTjAuJoxGDo9bm936IqvmwVlEdLkOoMoFnJY6OFiVqWmLIXHr56+z2ShryZVPc59gdLxNRA+ZJMF5kY27s=";
private final String IMG_AGGREGATE_FILE = "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=95272786,3986826432&fm=26&gp=0.jpg";
@Resource
private CityPartnerPrizeService cityPartnerPrizeService;
@Test
public void generateAgent() throws Exception {
}
@ -29,4 +43,166 @@ public class CityPartnerPrizeServiceImplTest {
cityPartnerPrizeService.generate("2017-06");
}
@Test
public void applicationMerchant() throws Exception {
JSONObject companyInfo = new JSONObject() {{
put("company_name", "gateway partner test1");
put("short_name", "gateway partner test1");
put("store_name", "gateway partner test1");
put("business_name", "gateway partner test1");
put("business_structure", "Company");
put("acn", "123456789");
put("company_phone", "123456789");
put("logo_url", "http://n.sinaimg.cn/sinacn15/435/w640h595/20181010/403e-hkrzvkw4936423.jpg");
}};
JSONObject contactInfo = new JSONObject() {{
put("contact_person", "person1");
put("contact_phone", "1231231");
put("contact_email", "1qq@qq.com");
put("contact_job", "Direct");
put("address", "测试住址1");
put("suburb", "测试区1");
put("postcode", "测试code1");
put("state", "测试state1");
put("country", "AU");
put("registered_address", "测试住址2");
put("registered_suburb", "测试区2");
put("registered_postcode", "测试code2");
put("registered_state", "测试state2");
put("timezone", "Australia/West");
}};
JSONObject ClientLegalConfig = new JSONObject() {{
put("legal_representative_person", "person2");
put("legal_representative_phone", "1231231");
put("legal_representative_email", "1qq@qq.com");
put("legal_representative_job", "Direct");
}};
JSONObject clientPayConfig = new JSONObject() {{
put("client_pay_type", "2");
put("client_pay_desc", "201");
put("royalpay_industry", "10001");
put("wechat_industry", "339");
put("alipay_industry", "4511");
put("company_photo", "https://c-ssl.duitang.com/uploads/item/201812/10/20181210170153_xPUVk.jpeg");
put("store_photo", "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3199241964,979639112&fm=26&gp=0.jpg");
put("company_website", "https://11.com");
}};
JSONObject settleConfig = new JSONObject() {{
put("swift_code", "2");
put("bsb_no", "201");
put("bank", "10001");
put("city", "339");
put("address", "4511");
put("system", "sytem");
put("postcode", "postcode");
put("state", "state");
put("branch", "branch");
put("account_no", "21213131");
put("account_name", "dasdasdasd");
put("clean_days", "2");
put("wechat_rate", "1.2");
put("alipay_rate", "1.2");
put("alipay_online_rate", "1.2");
put("transaction_fee", "0");
put("active_time", "2020-02-04 00:00:00");
put("expire_time", "2021-02-06 00:00:00");
}};
JSONObject complianceInfo = new JSONObject() {{
put("id_type", "pastport");
put("id_title", "Direct");
put("id_title_description", "test");
put("bank_statement", "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=820350352,1683018569&fm=26&gp=0.jpg");
put("certificate_of_registration", "http://i2.w.yun.hjfile.cn/doc/201404/00662ef619754b749200eecdf3671c3a.jpg");
put("id_file", "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2284543896,2456565772&fm=26&gp=0.jpg");
put("utility_bill", "http://i0.sinaimg.cn/ent/v/2009-08-22/U2389P28T3D2664490F346DT20090822015510.JPG");
}};
JSONObject params = new JSONObject() {{
put("apply_id", "orgapply1");
put("notify_url", "http://127.0.0.1:9002/sys/partners/7CMV/qrcode");
put("company_info", companyInfo);
put("contact_info", contactInfo);
put("legal_info", ClientLegalConfig);
put("pay_info", clientPayConfig);
put("settle_info", settleConfig);
put("compliance_file_info", complianceInfo);
}};
String originUrl = "http://127.0.0.1:5000/api/v1.0/gateway/partners/AXLCEXDDMB/merchant/application";
// String originUrl = "http://127.0.0.1:5000/api/v1.0/gateway/partners/2121/merchant/application";
String url = addSignUrl(originUrl, params, PRIKEY);
HttpRequestGenerator gen = new HttpRequestGenerator(url, RequestMethod.POST);
gen.setJSONEntity(params);
HttpRequestResult result = gen.execute();
if (result.isSuccess()) {
System.out.println(result.getResponseContentJSONObj().toJSONString());
}else {
System.out.println(result.getResponseContentString());
}
}
@Test
public void queryMerchantStatus() throws Exception{
String partnerCode = "PBAR";
String originUrl = "http://127.0.0.1:5000/api/v1.0/gateway/partners/AXLCEXDDMB/merchant/" + partnerCode + "/status";
String url = addSignUrl(originUrl, null, PRIKEY);
HttpRequestGenerator gen = new HttpRequestGenerator(url, RequestMethod.GET);
HttpRequestResult result = gen.execute();
if (result.isSuccess()) {
System.out.println(result.getResponseContentJSONObj().toJSONString());
}else {
System.out.println(result.getResponseContentString());
}
}
@Test
public void updateFile() throws Exception{
String originUrl = "http://127.0.0.1:5000/api/v1.0/gateway/partners/AXLCEXDDMB/attachment/files";
String url = addSignUrl(originUrl, null, PRIKEY);
File file = new File("/Users/luoyang/Downloads/121.jpg");
InputStream stream = new FileInputStream(file);
HttpRequestGenerator gen = new HttpRequestGenerator(url, RequestMethod.POST);
gen.setTimeout(10000);
gen.initFileEntity().attachFile("file", "121.jpg", stream);
HttpRequestResult result = gen.execute();
if (result.isSuccess()) {
System.out.println(result.getResponseContentJSONObj().toJSONString());
}else {
System.out.println(result.getResponseContentString());
}
}
private String sign(byte[] source, String privateKey) {
try {
PrivateKey priKey = loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes(StandardCharsets.UTF_8)));
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(priKey);
signature.update(source);
byte[] signed = signature.sign();
return Base64.encodeBase64URLSafeString(signed);
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
//shall never happen
throw new ServerErrorException(e);
}
}
private String addSignUrl(String originUrl, JSONObject params, String priKey) {
if (params == null) {
params = new JSONObject();
}
String nonceStr = RandomStringUtils.random(15, true, true);
params.put("url", originUrl);
params.put("sign_type", "RSA2");
params.put("nonce_str", nonceStr);
String signStr = sign(JSONObject.toJSONBytes(params, SerializerFeature.MapSortField), priKey);
originUrl += ("?nonce_str=" + nonceStr);
originUrl += "&sign_type=RSA2";
originUrl += "&sign=" + signStr;
return originUrl;
}
}
Loading…
Cancel
Save