From: qiaowei Date: Mon, 22 Jul 2019 09:50:33 +0000 (+0800) Subject: 支付宝接口、微信接口 X-Git-Tag: 1.0.0^2~9 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=1657eefdde847e5b9d10f9cd609473310fbc170d;p=epayment%2Ffood_payapi.git 支付宝接口、微信接口 --- diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QrcodePayParam.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QrcodePayParam.java index 6ffef6f0..c7f18f41 100644 --- a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QrcodePayParam.java +++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QrcodePayParam.java @@ -48,6 +48,17 @@ public class QrcodePayParam extends APIRequestParam { @NotNull(message = "必须指定是否匿名支付", groups = ConfirmAction.class) private Boolean anonymous; + /**请求IP*/ + private String spip; + + public String getSpip() { + return spip; + } + + public void setSpip(String spip) { + this.spip = spip; + } + public String getBillno() { return billno; } diff --git a/payapi/build.gradle b/payapi/build.gradle index e2cdeddf..0381f489 100644 --- a/payapi/build.gradle +++ b/payapi/build.gradle @@ -83,6 +83,8 @@ dependencies { implementation 'commons-dbcp:commons-dbcp:1.4' implementation project(':payapi-common') + /*支付宝SDK*/ + implementation group: 'com.alipay.sdk', name: 'alipay-sdk-java', version: '3.7.110.ALL' annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" annotationProcessor 'org.projectlombok:lombok:1.18.8' diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java index 950f3381..0d56cc14 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java @@ -10,8 +10,8 @@ public enum AgentCode { WAIT_NOTIFY("wait_notify", "交易已发起,等待通知"), SHORT_OF_BALANCE("short_of_balance", "余额不足"), NOT_SUPPORT("not_support", "不支持功能"), - COMMON_ERROR("common_error", "其它错误"); - + COMMON_ERROR("common_error", "其它错误"), + CONFIG_ERROR("config_error", "参数配置错误"); AgentCode(String code, String msg) { this.code = code; this.msg = msg; diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentResponse.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentResponse.java index e7766713..80f65a36 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentResponse.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentResponse.java @@ -1,50 +1,54 @@ package com.supwisdom.dlpay.agent; public class AgentResponse { - private AgentCode code; - private String agentCode; - private String agentMsg; + public static final String AGENTCODE_SUCCESS = "0"; - private String agentRefno; - private DtlStatus dtlStatus; + public static final String AGENTCODE_FAIL = "1"; - public AgentCode getCode() { - return code; - } + private AgentCode code; + private String agentCode; + private String agentMsg; - public void setCode(AgentCode code) { - this.code = code; - } + private String agentRefno; + private DtlStatus dtlStatus; - public String getAgentCode() { - return agentCode; - } + public AgentCode getCode() { + return code; + } - public void setAgentCode(String agentCode) { - this.agentCode = agentCode; - } + public void setCode(AgentCode code) { + this.code = code; + } - public String getAgentMsg() { - return agentMsg; - } + public String getAgentCode() { + return agentCode; + } - public void setAgentMsg(String agentMsg) { - this.agentMsg = agentMsg; - } + public void setAgentCode(String agentCode) { + this.agentCode = agentCode; + } - public String getAgentRefno() { - return agentRefno; - } + public String getAgentMsg() { + return agentMsg; + } - public void setAgentRefno(String agentRefno) { - this.agentRefno = agentRefno; - } + public void setAgentMsg(String agentMsg) { + this.agentMsg = agentMsg; + } - public DtlStatus getDtlStatus() { - return dtlStatus; - } + public String getAgentRefno() { + return agentRefno; + } - public void setDtlStatus(DtlStatus dtlStatus) { - this.dtlStatus = dtlStatus; - } + public void setAgentRefno(String agentRefno) { + this.agentRefno = agentRefno; + } + + public DtlStatus getDtlStatus() { + return dtlStatus; + } + + public void setDtlStatus(DtlStatus dtlStatus) { + this.dtlStatus = dtlStatus; + } } diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/DtlStatus.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/DtlStatus.java index d80d5036..a13f1d52 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/agent/DtlStatus.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/DtlStatus.java @@ -4,5 +4,6 @@ public enum DtlStatus { SUCCESS, //成功 FAIL, //失败 REFUND, //已退款 - PARTIAL_REFUND //部分退款 + PARTIAL_REFUND, //部分退款 + WAIT //等待付款 } diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java index 96f8b06b..fb420417 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java @@ -65,6 +65,9 @@ public class QrcodePayTrans { @Column(name = "tenantid", length = 20) private String tenantid; + @Column(name = "spid", length = 20) + private String spip; + public QrcodePayTrans() { } @@ -179,4 +182,12 @@ public class QrcodePayTrans { public void setUpdateTime(Timestamp updateTime) { this.updateTime = updateTime; } + + public String getSpip() { + return spip; + } + + public void setSpip(String spip) { + this.spip = spip; + } } diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/bean/WechatReqResp.java b/payapi/src/main/java/com/supwisdom/dlpay/api/bean/WechatReqResp.java index f69eb688..40b62e51 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/api/bean/WechatReqResp.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/api/bean/WechatReqResp.java @@ -237,6 +237,41 @@ public class WechatReqResp { this.sign = MD5.encodeByMD5(str.toString()); return sign; } + public String generalQuerySign(){ + this.nonce_str = RandomUtils.getRandomString(30); + StringBuffer str = new StringBuffer() + .append("appid=").append(this.appid) + .append("&mch_id=").append(this.mch_id) + .append("&nonce_str=").append(nonce_str) + .append("&out_trade_no=").append(this.out_trade_no); + str.append("&key=").append(this.key); + this.sign = MD5.encodeByMD5(str.toString()); + return sign; + } + public String generalQueryXML(){ + StringBuffer requestStr = new StringBuffer(); + requestStr + .append("") + .append("") + .append(this.appid) + .append("") + .append("") + .append(this.mch_id) + .append("") + .append("") + .append(this.nonce_str) + .append("") + .append("") + .append(this.out_trade_no) + .append("") + ; + requestStr.append("") + .append(this.sign) + .append("") + .append(""); + return requestStr.toString(); + } + public String generalCheckSign(){ this.nonce_str = RandomUtils.getRandomString(30); StringBuffer str = new StringBuffer() diff --git a/payapi/src/main/java/com/supwisdom/dlpay/util/PaytypeUtil.java b/payapi/src/main/java/com/supwisdom/dlpay/util/PaytypeUtil.java index 8222e90a..55108af4 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/util/PaytypeUtil.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/util/PaytypeUtil.java @@ -7,4 +7,40 @@ public class PaytypeUtil { public static final String YKTPAY = "yktpay"; public static final String WECHAT = "wechat"; + + + /** + * 支付宝支付,配置的KEY值 + */ + public static final String CFG_ALIPAY_APPID = "alipay.appid"; + + public static final String CFG_ALIPAY_PRIVATEKEY = "alipay.privatekey"; + + public static final String CFG_ALIPAY_PUBLICKEY = "alipay.publickey"; + + public static final String CFG_ALIPAY_PAYURL = "alipay.payurl"; + + public static final String CFG_ALIPAY_NOTIFY = "alipay.notify"; + + public static final String CFG_ALIPAY_RETURNURL = "alipay.returnurl"; + + /** + * 微信支付,配置的KEY值 + */ + public static final String CFG_WECHAT_APPID = "wechat.appid"; + + public static final String CFG_WECHAT_MECHID = "wechat.mechid"; + + public static final String CFG_WECHAT_MECHKEY = "wechat.mechkey"; + + public static final String CFG_WECHAT_NOTIFY = "wechat.notify"; + + public static final String CFG_WECHAT_OAUTHCODE = "https://api.mch.weixin.qq.com/tools/authcodetoopenid"; + + public static final String CFG_WECHAT_QRCODEPAY = "https://api.mch.weixin.qq.com/pay/micropay"; + + public static final String CFG_WECHAT_UNIONPAY = "https://api.mch.weixin.qq.com/pay/unifiedorder"; + + public static final String CFG_WECHAT_QUERY = "https://api.mch.weixin.qq.com/pay/orderquery"; + } diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt index a89e2e1d..3f8cde22 100644 --- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt @@ -4,29 +4,52 @@ import com.supwisdom.dlpay.agent.AgentCode import com.supwisdom.dlpay.agent.AgentPayService import com.supwisdom.dlpay.agent.AgentResponse import com.supwisdom.dlpay.api.domain.TTransactionMain +import com.supwisdom.dlpay.api.service.ConsumePayService +import com.supwisdom.dlpay.framework.util.TradeCode +import com.supwisdom.dlpay.framework.util.TradeDict import org.springframework.stereotype.Component +interface AlipayService { + fun doQrcodepay(transaction: TTransactionMain): AgentResponse + + fun doPrepay(transaction: TTransactionMain): AgentResponse + + fun doRefund(transaction: TTransactionMain): AgentResponse + + fun doQuery(transaction: TTransactionMain): AgentResponse + + fun doNotify(param: Map): AgentResponse +} + @Component("alipayAgent") -class AlipayAgentService : AgentPayService { +class AlipayAgentService(val consumePayService: ConsumePayService, + val aipayService: AlipayService) : AgentPayService { + override fun auth(shopaccno: String?, billno: String?): AgentResponse { + if (consumePayService.checkShopPaytype(shopaccno!!, TradeDict.PAYTYPE_ALIPAY, true)) { + //TODO 支付宝实名认证逻辑 + } return AgentResponse().apply { this.code = AgentCode.NOT_SUPPORT } } override fun pay(transaction: TTransactionMain): AgentResponse { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + return when (transaction.transCode) { + TradeCode.TRANSCODE_QRCODE -> aipayService.doQrcodepay(transaction) + else -> aipayService.doPrepay(transaction) + } } override fun cancel(transaction: TTransactionMain): AgentResponse { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + return refund(transaction) } override fun refund(transaction: TTransactionMain): AgentResponse { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + return aipayService.doRefund(transaction) } override fun query(transaction: TTransactionMain): AgentResponse { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + return aipayService.doQuery(transaction) } } \ No newline at end of file diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/alipay_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/alipay_service_impl.kt new file mode 100644 index 00000000..53afcd71 --- /dev/null +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/alipay_service_impl.kt @@ -0,0 +1,260 @@ +package com.supwisdom.dlpay.agent.service.impl + +import com.supwisdom.dlpay.agent.AgentCode +import com.supwisdom.dlpay.agent.AgentResponse +import com.supwisdom.dlpay.agent.service.AlipayService +import com.supwisdom.dlpay.api.service.SourceTypeService +import com.supwisdom.dlpay.framework.util.TradeDict +import com.supwisdom.dlpay.util.PaytypeUtil +import mu.KotlinLogging +import org.springframework.stereotype.Service +import com.alipay.api.request.AlipayTradePayRequest +import com.alipay.api.DefaultAlipayClient +import com.alipay.api.domain.AlipayTradePayModel +import com.supwisdom.dlpay.agent.service.AgentServiceProxy +import com.supwisdom.dlpay.api.domain.TTransactionMain +import com.alipay.api.AlipayApiException +import com.alipay.api.internal.util.AlipaySignature +import com.alipay.api.request.AlipayTradeAppPayRequest +import com.supwisdom.dlpay.api.service.ConsumePayService +import com.supwisdom.dlpay.api.service.TransactionServiceProxy +import com.alipay.api.request.AlipayTradeQueryRequest +import com.supwisdom.dlpay.agent.DtlStatus +import com.alipay.api.domain.AlipayTradeQueryModel +import com.alipay.api.domain.AlipayTradeRefundModel + + +@Service +class AlipayServiceImpl(val sourceTypeService: SourceTypeService, + val agentServiceProxy: AgentServiceProxy, + val consumePayService: ConsumePayService, + val transactionService: TransactionServiceProxy) : AlipayService { + val logger = KotlinLogging.logger { } + + fun checkCfg(config: Map, resp: AgentResponse): Boolean { + if (config[PaytypeUtil.CFG_ALIPAY_APPID].isNullOrEmpty() + || config[PaytypeUtil.CFG_ALIPAY_PRIVATEKEY].isNullOrEmpty() + || config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY].isNullOrEmpty()) { + resp.code = AgentCode.CONFIG_ERROR + resp.agentCode = AgentResponse.AGENTCODE_FAIL + resp.agentMsg = "支付宝相关配置为空" + logger.error { "请检查:${PaytypeUtil.CFG_ALIPAY_APPID},${PaytypeUtil.CFG_ALIPAY_PRIVATEKEY},${PaytypeUtil.CFG_ALIPAY_PUBLICKEY}" } + return false + } + return true + } + + override fun doQrcodepay(transaction: TTransactionMain): AgentResponse { + var qrcodePayTrans = agentServiceProxy.qrcodePayTransFindByRefno(transaction.refno) + val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_ALIPAY, transaction.shopDtl.shopaccno, qrcodePayTrans.isAnonymous, false) + var agentResponse = AgentResponse() + if (checkCfg(config, agentResponse)) { + var payurl = config[PaytypeUtil.CFG_ALIPAY_PAYURL] + if (payurl.isNullOrEmpty()) { + payurl = "https://openapi.alipay.com/gateway.do" + } + val alipayClient = DefaultAlipayClient(payurl, config[PaytypeUtil.CFG_ALIPAY_APPID], config[PaytypeUtil.CFG_ALIPAY_PRIVATEKEY], "json", "UTF-8", config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY], "RSA2") + val request = AlipayTradePayRequest() + request.bizModel = AlipayTradePayModel().apply { + this.authCode = qrcodePayTrans.qrcode + this.outTradeNo = transaction.refno + this.subject = "POS扫支付宝二维码消费" + this.totalAmount = transaction.shopDtl.amount.toString() + } + try { + val response = alipayClient.execute(request) + if ("10000" == response.code) { + if (response.isSuccess) { + agentResponse.agentRefno = response.tradeNo + agentResponse.code = AgentCode.SUCCESS + agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS + } else { + agentResponse.code = AgentCode.FAIL + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = response.subMsg + logger.error { "支付宝:${response.code},${response.msg},${response.subCode},${response.subMsg}" } + } + } else if ("10003" == response.code || "20000" == response.code) { + agentResponse.code = AgentCode.REQUIRE_QUERY + agentResponse.agentMsg = "支付请求已提交,等待用户支付" + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + logger.error { "支付宝:${response.code},${response.msg},${response.subCode},${response.subMsg}" } + } else { + agentResponse.code = AgentCode.FAIL + agentResponse.agentMsg = response.msg + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + logger.error { "支付宝:${response.code},${response.msg},${response.subCode},${response.subMsg}" } + } + } catch (e: AlipayApiException) { + logger.error { "支付宝:${e.message}" } + agentResponse.code = AgentCode.FAIL + agentResponse.agentMsg = "调用支付宝异常" + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + } + } + return agentResponse + } + + override fun doPrepay(transaction: TTransactionMain): AgentResponse { + val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_ALIPAY, transaction.shopDtl.shopaccno, false, false) + var agentResponse = AgentResponse() + if (checkCfg(config, agentResponse)) { + if (config[PaytypeUtil.CFG_ALIPAY_NOTIFY].isNullOrEmpty()) { + agentResponse.code = AgentCode.CONFIG_ERROR + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = "支付宝相关配置为空" + logger.error { "支付宝异步通知地址未配置:${PaytypeUtil.CFG_ALIPAY_NOTIFY}" } + } + var payurl = config[PaytypeUtil.CFG_ALIPAY_PAYURL] + if (payurl.isNullOrEmpty()) { + payurl = "https://openapi.alipay.com/gateway.do" + } + val alipayClient = DefaultAlipayClient(payurl, config[PaytypeUtil.CFG_ALIPAY_APPID], config[PaytypeUtil.CFG_ALIPAY_PRIVATEKEY], "json", "UTF-8", config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY], "RSA2") + val request = AlipayTradeAppPayRequest() + var productCode = "" + //判断是否为H5 + //productCode = "QUICK_WAP_WAY" + request.bizModel = AlipayTradePayModel().apply { + this.outTradeNo = transaction.refno + this.subject = "支付宝支付" + this.totalAmount = transaction.shopDtl.amount.toString() + this.productCode = productCode + } + request.notifyUrl = config[PaytypeUtil.CFG_ALIPAY_NOTIFY] + request.returnUrl = config[PaytypeUtil.CFG_ALIPAY_RETURNURL] + try { + /** + * h5 支付方式 + * String form = alipayClient.pageExecute(request).getBody(); + * + * */ + val response = alipayClient.sdkExecute(request) + if (response.isSuccess) { + agentResponse.agentRefno = response.tradeNo + agentResponse.code = AgentCode.REQUIRE_QUERY + agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS + //body 为APP + agentResponse.agentMsg = response.body + } else { + agentResponse.code = AgentCode.FAIL + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = response.subMsg + logger.error { "支付宝:${response.code},${response.msg},${response.subCode},${response.subMsg}" } + } + } catch (e: AlipayApiException) { + logger.error { "支付宝:${e.message}" } + agentResponse.code = AgentCode.FAIL + agentResponse.agentMsg = "调用支付宝异常" + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + } + } + return agentResponse + } + + override fun doRefund(transaction: TTransactionMain): AgentResponse { + var agentResponse = AgentResponse() + val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_ALIPAY, transaction.shopDtl.shopaccno, false, false) + if (checkCfg(config, agentResponse)) { + var payurl = config[PaytypeUtil.CFG_ALIPAY_PAYURL] + if (payurl.isNullOrEmpty()) { + payurl = "https://openapi.alipay.com/gateway.do" + } + val alipayClient = DefaultAlipayClient(payurl, config[PaytypeUtil.CFG_ALIPAY_APPID], config[PaytypeUtil.CFG_ALIPAY_PRIVATEKEY], "json", "UTF-8", config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY], "RSA2") + val request = AlipayTradeQueryRequest() + request.bizModel = AlipayTradeRefundModel().apply { + this.outTradeNo = transaction.refno + this.refundAmount = transaction.shopDtl.amount.toString() + } + val response = alipayClient.execute(request) + if (response.isSuccess) { + agentResponse.code = AgentCode.SUCCESS + agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS + agentResponse.dtlStatus = DtlStatus.REFUND + } else { + agentResponse.code = AgentCode.FAIL + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = "支付宝退款失败" + } + } + return agentResponse + } + + override fun doQuery(transaction: TTransactionMain): AgentResponse { + var agentResponse = AgentResponse() + val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_ALIPAY, transaction.shopDtl.shopaccno, false, false) + if (checkCfg(config, agentResponse)) { + var payurl = config[PaytypeUtil.CFG_ALIPAY_PAYURL] + if (payurl.isNullOrEmpty()) { + payurl = "https://openapi.alipay.com/gateway.do" + } + val alipayClient = DefaultAlipayClient(payurl, config[PaytypeUtil.CFG_ALIPAY_APPID], config[PaytypeUtil.CFG_ALIPAY_PRIVATEKEY], "json", "UTF-8", config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY], "RSA2") + val request = AlipayTradeQueryRequest() + request.bizModel = AlipayTradeQueryModel().apply { + this.outTradeNo = transaction.refno + } + val response = alipayClient.execute(request) + if (response.isSuccess) { + //check response.totalAmount + agentResponse.code = AgentCode.SUCCESS + agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS + when (response.tradeStatus) { + "TRADE_SUCCESS", "TRADE_FINISHED" -> agentResponse.dtlStatus = DtlStatus.SUCCESS + "TRADE_CLOSED" -> agentResponse.dtlStatus = DtlStatus.REFUND + "WAIT_BUYER_PAY" -> agentResponse.dtlStatus = DtlStatus.WAIT + } + } else { + agentResponse.code = AgentCode.FAIL + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = "支付宝查询失败" + } + } + return agentResponse + } + + override fun doNotify(param: Map): AgentResponse { + var refno = param["out_trade_no"] + var agentResponse = AgentResponse() + if (refno.isNullOrEmpty()) { + agentResponse.code = AgentCode.FAIL + agentResponse.agentMsg = "返回流水号为空" + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + return agentResponse + } + var transaction = consumePayService.getTransactionMainDtl(refno, null, null) + if (transaction == null) { + agentResponse.code = AgentCode.REFNO_NOT_EXISTS + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + return agentResponse + } + if (transaction.status == TradeDict.DTL_STATUS_SUCCESS) { + agentResponse.code = AgentCode.SUCCESS + agentResponse.agentMsg = "流水已成功,不能重复入账" + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + return agentResponse + } + val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_ALIPAY, transaction.shopDtl.shopaccno, false, false) + if (config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY].isNullOrEmpty()) { + agentResponse.code = AgentCode.CONFIG_ERROR + agentResponse.agentMsg = "商户公钥未配置" + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + return agentResponse + } + var flag = AlipaySignature.rsaCheckV1(param, config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY], "UTF-8", "RSA2") + return when (flag) { + true -> { + //total amt 校验 map["total_amount"] + transactionService.success(refno) + agentResponse.code = AgentCode.SUCCESS + agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS + agentResponse + } + false -> { + logger.error { "支付宝签名校验错误" } + agentResponse.code = AgentCode.FAIL + agentResponse.agentMsg = "签名校验错误" + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse + } + } + } +} \ No newline at end of file diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/wechat_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/wechat_service_impl.kt new file mode 100644 index 00000000..e3beb793 --- /dev/null +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/wechat_service_impl.kt @@ -0,0 +1,263 @@ +package com.supwisdom.dlpay.agent.service.impl + +import com.supwisdom.dlpay.agent.AgentCode +import com.supwisdom.dlpay.agent.AgentResponse +import com.supwisdom.dlpay.agent.DtlStatus +import com.supwisdom.dlpay.agent.service.AgentServiceProxy +import com.supwisdom.dlpay.agent.service.WechatService +import com.supwisdom.dlpay.api.bean.WechatReqResp +import com.supwisdom.dlpay.api.dao.PersonIdentityDao +import com.supwisdom.dlpay.api.domain.TTransactionMain +import com.supwisdom.dlpay.api.service.ConsumePayService +import com.supwisdom.dlpay.api.service.SourceTypeService +import com.supwisdom.dlpay.api.service.TransactionServiceProxy +import com.supwisdom.dlpay.framework.util.* +import com.supwisdom.dlpay.util.PaytypeUtil +import mu.KotlinLogging +import org.apache.commons.lang.StringUtils +import org.springframework.stereotype.Service +import org.springframework.web.client.RestTemplate + + +@Service +class WechatServiceImpl(val sourceTypeService: SourceTypeService, + val agentServiceProxy: AgentServiceProxy, + val personIdentityDao: PersonIdentityDao, + val consumePayService: ConsumePayService, + val transactionService: TransactionServiceProxy, + val restTemplate: RestTemplate) : WechatService { + + val logger = KotlinLogging.logger { } + + fun checkCfg(config: Map, resp: AgentResponse): Boolean { + if (config[PaytypeUtil.CFG_WECHAT_APPID].isNullOrEmpty() + || config[PaytypeUtil.CFG_WECHAT_MECHKEY].isNullOrEmpty() + || config[PaytypeUtil.CFG_WECHAT_MECHID].isNullOrEmpty()) { + resp.code = AgentCode.CONFIG_ERROR + resp.agentCode = AgentResponse.AGENTCODE_FAIL + resp.agentMsg = "微信相关配置为空" + logger.error { "请检查:${PaytypeUtil.CFG_WECHAT_APPID},${PaytypeUtil.CFG_WECHAT_MECHID},${PaytypeUtil.CFG_WECHAT_MECHKEY}" } + return false + } + return true + } + + override fun doAuth(shopaccno: String?, billno: String?): AgentResponse { + var qrcodeTrans = agentServiceProxy.qrcodePayTransFindByMerchIdAndBillno(shopaccno, billno) + var agentResponse = AgentResponse() + if (qrcodeTrans == null) { + agentResponse.code = AgentCode.REFNO_NOT_EXISTS + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + return agentResponse + } + val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_WECHAT, shopaccno, qrcodeTrans.isAnonymous, false) + if (checkCfg(config, agentResponse)) { + val bean = WechatReqResp().apply { + this.appid = config[PaytypeUtil.CFG_WECHAT_APPID] + this.auth_code = qrcodeTrans.qrcode + this.mch_id = config[PaytypeUtil.CFG_WECHAT_MECHID] + this.key = config[PaytypeUtil.CFG_WECHAT_MECHKEY] + } + bean.generalCheckSign() + var xml = bean.generalCheckXML() + var res = restTemplate.postForEntity(PaytypeUtil.CFG_WECHAT_OAUTHCODE, xml, String::class.java) + var eleMap = XmlUtils.parseXml(res.body) + var retcode = eleMap["return_code"] + var resultCode = eleMap["result_code"] + var openid = eleMap["openid"] + if (!retcode.isNullOrEmpty() && "SUCCESS" == retcode + && !resultCode.isNullOrEmpty() && "SUCCESS" == resultCode && !openid.isNullOrEmpty()) { + qrcodeTrans.agentUserId = openid + var ip = personIdentityDao.getByThirdUid(openid) + if (ip != null) { + qrcodeTrans.agentUserId = ip.person.userid + } + agentServiceProxy.qrcodePayTransSaveOrUpdate(qrcodeTrans) + agentResponse.code = AgentCode.SUCCESS + agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS + } else { + logger.error { "code=${eleMap["err_code"]},des=${eleMap["err_code_des"]}" } + agentResponse.code = AgentCode.FAIL + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = "二维码身份查询失败" + } + } + return agentResponse + } + + override fun doQrcodepay(transaction: TTransactionMain): AgentResponse { + var qrcodeTrans = agentServiceProxy.qrcodePayTransFindByRefno(transaction.refno) + var agentResponse = AgentResponse() + if (qrcodeTrans == null) { + agentResponse.code = AgentCode.REFNO_NOT_EXISTS + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + return agentResponse + } + val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_WECHAT, transaction.shopDtl.shopaccno, qrcodeTrans.isAnonymous, false) + if (checkCfg(config, agentResponse)) { + val bean = WechatReqResp().apply { + this.appid = config[PaytypeUtil.CFG_WECHAT_APPID] + this.auth_code = qrcodeTrans.qrcode + this.mch_id = config[PaytypeUtil.CFG_WECHAT_MECHID] + this.key = config[PaytypeUtil.CFG_WECHAT_MECHKEY] + this.out_trade_no = transaction.refno + this.total_fee = MoneyUtil.YuanToFen(transaction.shopDtl.amount) + this.spbill_create_ip = qrcodeTrans.spip + } + + bean.generalPaySign() + var xml = bean.generaPayXML() + var res = restTemplate.postForEntity(PaytypeUtil.CFG_WECHAT_QRCODEPAY, xml, String::class.java) + var eleMap = XmlUtils.parseXml(res.body) + var retcode = eleMap["return_code"] + var resultCode = eleMap["result_code"] + var openid = eleMap["openid"] + if (!retcode.isNullOrEmpty() && "SUCCESS" == retcode + && !resultCode.isNullOrEmpty() && "SUCCESS" == resultCode && !openid.isNullOrEmpty()) { + agentResponse.code = AgentCode.SUCCESS + agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS + agentResponse.dtlStatus = DtlStatus.SUCCESS + } else { + logger.error { "code=${eleMap["err_code"]},des=${eleMap["err_code_des"]}" } + agentResponse.code = AgentCode.REQUIRE_QUERY + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = "请查询支付结果" + } + } + return agentResponse + } + + override fun doPrepay(transaction: TTransactionMain): AgentResponse { + var agentResponse = AgentResponse() + + val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_WECHAT, transaction.shopDtl.shopaccno, false, false) + if (checkCfg(config, agentResponse)) { + //H5 支付 + val bean = WechatReqResp().apply { + this.appid = config[PaytypeUtil.CFG_WECHAT_APPID] + this.mch_id = config[PaytypeUtil.CFG_WECHAT_MECHID] + this.key = config[PaytypeUtil.CFG_WECHAT_MECHKEY] + this.out_trade_no = transaction.refno + this.total_fee = MoneyUtil.YuanToFen(transaction.shopDtl.amount) + this.spbill_create_ip = "" + this.body = "微信支付" + this.trade_type = "MWEB" + this.notify_url = config[PaytypeUtil.CFG_WECHAT_NOTIFY] + this.scene_info = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"" + config[PaytypeUtil.CFG_WECHAT_NOTIFY] + "\",\"wap_name\": \"微信支付\"}}" + } + //TODO IP 问题 + bean.generaSign() + val xml = bean.generaXML() + var res = restTemplate.postForEntity(PaytypeUtil.CFG_WECHAT_UNIONPAY, xml, String::class.java) + var eleMap = XmlUtils.parseXml(res.body) + var retcode = eleMap["return_code"] + var resultCode = eleMap["result_code"] + val mweb_url = eleMap["mweb_url"] + if (!retcode.isNullOrEmpty() && "SUCCESS" == retcode + && !resultCode.isNullOrEmpty() && "SUCCESS" == resultCode && !mweb_url.isNullOrEmpty()) { + agentResponse.code = AgentCode.REQUIRE_QUERY + agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS + agentResponse.agentMsg = mweb_url + agentResponse.agentRefno = eleMap["prepay_id"] + } else { + logger.error { "code=${eleMap["err_code"]},des=${eleMap["err_code_des"]}" } + agentResponse.code = AgentCode.FAIL + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = "预下单失败" + } + } + return agentResponse + } + + override fun doQuery(transaction: TTransactionMain): AgentResponse { + var agentResponse = AgentResponse() + val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_WECHAT, transaction.shopDtl.shopaccno, false, false) + if (checkCfg(config, agentResponse)) { + //H5 支付 + val bean = WechatReqResp().apply { + this.appid = config[PaytypeUtil.CFG_WECHAT_APPID] + this.mch_id = config[PaytypeUtil.CFG_WECHAT_MECHID] + this.key = config[PaytypeUtil.CFG_WECHAT_MECHKEY] + this.out_trade_no = transaction.refno + } + bean.generalQuerySign() + val xml = bean.generalQueryXML() + var res = restTemplate.postForEntity(PaytypeUtil.CFG_WECHAT_QUERY, xml, String::class.java) + var eleMap = XmlUtils.parseXml(res.body) + var retcode = eleMap["return_code"] + var resultCode = eleMap["result_code"] + val trade_state = eleMap["trade_state"] + if (!retcode.isNullOrEmpty() && "SUCCESS" == retcode + && !resultCode.isNullOrEmpty() && "SUCCESS" == resultCode) { + agentResponse.code = AgentCode.REQUIRE_QUERY + agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS + when (trade_state) { + "SUCCESS" -> agentResponse.dtlStatus = DtlStatus.SUCCESS + "REFUND" -> agentResponse.dtlStatus = DtlStatus.REFUND + "NOTPAY", "CLOSED", "REVOKED", "PAYERROR" -> agentResponse.dtlStatus = DtlStatus.FAIL + "USERPAYING" -> agentResponse.dtlStatus = DtlStatus.WAIT + } + } else { + logger.error { "code=${eleMap["err_code"]},des=${eleMap["err_code_des"]}" } + agentResponse.code = AgentCode.FAIL + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = "查询失败" + } + } + return agentResponse + } + + override fun doRefund(transaction: TTransactionMain): AgentResponse { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun doNotify(param: Map): AgentResponse { + var agentResponse = AgentResponse() + var transaction = consumePayService.getTransactionMainDtl(param["out_trade_no"], null, null) + if (transaction == null) { + agentResponse.code = AgentCode.REFNO_NOT_EXISTS + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + return agentResponse + } + if (transaction.status == TradeDict.DTL_STATUS_SUCCESS) { + agentResponse.code = AgentCode.SUCCESS + agentResponse.agentMsg = "流水已成功,不能重复入账" + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + return agentResponse + } + val sign = param["sign"] + if (StringUtils.isEmpty(sign)) { + logger.error("签名错误") + agentResponse.code = AgentCode.FAIL + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = "签名错误" + } + var temp = StringUtil.paraFilter(param) + var signStr = StringUtil.createLinkString(temp) + val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_WECHAT, transaction.shopDtl.shopaccno, false, false) + var key = config[PaytypeUtil.CFG_WECHAT_MECHKEY] + signStr += "&key=$key" + val signRet = MD5.encodeByMD5(signStr) + logger.error("*******signStr=$signStr") + if (!signRet.equals(sign, ignoreCase = true)) { + logger.error("签名错误:$signRet,$sign") + agentResponse.code = AgentCode.FAIL + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = "签名错误" + } + val returnCode = param["return_code"] + val resultCode = param["result_code"] + if (!returnCode.isNullOrEmpty() && "SUCCESS" == returnCode + && !resultCode.isNullOrEmpty() && "SUCCESS" == resultCode) { + transactionService.success(transaction.refno) + agentResponse.code = AgentCode.SUCCESS + agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS + } else { + agentResponse.code = AgentCode.FAIL + agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL + agentResponse.agentMsg = "${param["err_code"]}:${param["err_code_des"]}" + logger.error { "code=${param["err_code"]},des=${param["err_code_des"]}" } + } + return agentResponse + } +} \ No newline at end of file diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/wechat_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/wechat_service.kt new file mode 100644 index 00000000..380221c4 --- /dev/null +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/wechat_service.kt @@ -0,0 +1,56 @@ +package com.supwisdom.dlpay.agent.service + +import com.supwisdom.dlpay.agent.AgentCode +import com.supwisdom.dlpay.agent.AgentPayService +import com.supwisdom.dlpay.agent.AgentResponse +import com.supwisdom.dlpay.api.domain.TTransactionMain +import com.supwisdom.dlpay.api.service.ConsumePayService +import com.supwisdom.dlpay.framework.util.TradeCode +import com.supwisdom.dlpay.framework.util.TradeDict +import org.springframework.stereotype.Component + +interface WechatService { + fun doAuth(shopaccno: String?, billno: String?): AgentResponse + + fun doQrcodepay(transaction: TTransactionMain): AgentResponse + + fun doPrepay(transaction: TTransactionMain): AgentResponse + + fun doQuery(transaction: TTransactionMain): AgentResponse + + fun doRefund(transaction: TTransactionMain): AgentResponse + + fun doNotify(param: Map): AgentResponse +} + +@Component("wechatpayAgent") +class WeChatPayAgentService(val consumePayService: ConsumePayService, + val wechatService: WechatService) : AgentPayService { + override fun auth(shopaccno: String?, billno: String?): AgentResponse { + if (consumePayService.checkShopPaytype(shopaccno!!, TradeDict.PAYTYPE_WECHAT, true)) { + return wechatService.doAuth(shopaccno, billno) + } + return AgentResponse().apply { + this.code = AgentCode.NOT_SUPPORT + } + } + + override fun pay(transaction: TTransactionMain?): AgentResponse { + return when (transaction!!.transCode) { + TradeCode.TRANSCODE_QRCODE -> wechatService.doQrcodepay(transaction!!) + else -> wechatService.doPrepay(transaction!!) + } + } + + override fun cancel(transaction: TTransactionMain?): AgentResponse { + return refund(transaction) + } + + override fun refund(transaction: TTransactionMain?): AgentResponse { + return wechatService.doRefund(transaction!!) + } + + override fun query(transaction: TTransactionMain?): AgentResponse { + return wechatService.doQuery(transaction!!) + } +} \ No newline at end of file diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/weichat_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/weichat_service.kt deleted file mode 100644 index dc748d75..00000000 --- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/weichat_service.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.supwisdom.dlpay.agent.service - -import com.supwisdom.dlpay.agent.AgentCode -import com.supwisdom.dlpay.agent.AgentPayService -import com.supwisdom.dlpay.agent.AgentResponse -import com.supwisdom.dlpay.api.domain.TTransactionMain -import org.springframework.stereotype.Component - -@Component("wechatpayAgent") -class WeChatPayAgentService : AgentPayService { - override fun auth(shopaccno: String?, billno: String?): AgentResponse { - return AgentResponse().apply { - this.code = AgentCode.NOT_SUPPORT - } - } - - override fun pay(transaction: TTransactionMain?): AgentResponse { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun cancel(transaction: TTransactionMain?): AgentResponse { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun refund(transaction: TTransactionMain?): AgentResponse { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun query(transaction: TTransactionMain?): AgentResponse { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } -} \ No newline at end of file diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt index 9d923d2e..3751c401 100644 --- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt @@ -20,6 +20,7 @@ import org.springframework.context.ApplicationContext import org.springframework.http.ResponseEntity import org.springframework.validation.annotation.Validated import org.springframework.web.bind.annotation.* +import javax.servlet.http.HttpServletRequest import javax.validation.Valid @RestController @@ -548,6 +549,7 @@ class ConsumeAPIController { .fail(apiResponse, TradeErrorCode.BUSINESS_DEAL_ERROR, "支付方式<${qrcodeTrans.sourceType}>不支持匿名支付")) } + qrcodeTrans.spip = param.spip //2. 初始化交易流水 // sourcetype 资产类科目