|  |  |  | 
|---|
|  |  |  | import com.alibaba.fastjson2.JSON; | 
|---|
|  |  |  | import com.alibaba.fastjson2.JSONObject; | 
|---|
|  |  |  | import com.dy.common.multiDataSource.DataSourceContext; | 
|---|
|  |  |  | import com.dy.common.util.AES; | 
|---|
|  |  |  | import com.dy.common.webUtil.BaseResponse; | 
|---|
|  |  |  | import com.dy.common.webUtil.BaseResponseUtils; | 
|---|
|  |  |  | import com.dy.common.webUtil.ResultCodeMsg; | 
|---|
|  |  |  | import com.dy.pipIrrGlobal.cert.WxCertUtil; | 
|---|
|  |  |  | import com.dy.pipIrrGlobal.pojoSe.*; | 
|---|
|  |  |  | import com.dy.pipIrrGlobal.voSe.VoClient; | 
|---|
|  |  |  | import com.dy.pipIrrWechat.result.WechatResultCode; | 
|---|
|  |  |  | 
|---|
|  |  |  | import com.dy.pipIrrWechat.virtualCard.dto.DtoVirtualCard; | 
|---|
|  |  |  | import com.dy.pipIrrWechat.virtualCard.enums.LastOperateENUM; | 
|---|
|  |  |  | import com.dy.pipIrrWechat.virtualCard.enums.RefundItemStateENUM; | 
|---|
|  |  |  | import com.dy.pipIrrWechat.wechatpay.dto.Code2Session; | 
|---|
|  |  |  | import com.dy.pipIrrWechat.wechatpay.dto.DtoOrder; | 
|---|
|  |  |  | import com.dy.pipIrrWechat.wechatpay.dto.NotifyResource; | 
|---|
|  |  |  | import com.dy.pipIrrWechat.wechatpay.dto.OrderNotify; | 
|---|
|  |  |  | import com.dy.pipIrrWechat.wechatpay.dto.*; | 
|---|
|  |  |  | import com.dy.pipIrrWechat.wechatpay.enums.RefundStatusENUM; | 
|---|
|  |  |  | import io.swagger.v3.oas.annotations.Operation; | 
|---|
|  |  |  | import io.swagger.v3.oas.annotations.media.Content; | 
|---|
|  |  |  | 
|---|
|  |  |  | import jakarta.validation.Valid; | 
|---|
|  |  |  | import lombok.RequiredArgsConstructor; | 
|---|
|  |  |  | import lombok.extern.slf4j.Slf4j; | 
|---|
|  |  |  | import org.springframework.core.io.ResourceLoader; | 
|---|
|  |  |  | import org.springframework.http.HttpHeaders; | 
|---|
|  |  |  | import org.springframework.http.MediaType; | 
|---|
|  |  |  | import org.springframework.transaction.annotation.Transactional; | 
|---|
|  |  |  | import org.springframework.validation.BindingResult; | 
|---|
|  |  |  | import org.springframework.web.bind.annotation.*; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import javax.crypto.NoSuchPaddingException; | 
|---|
|  |  |  | import java.io.BufferedReader; | 
|---|
|  |  |  | import java.io.IOException; | 
|---|
|  |  |  | import java.security.GeneralSecurityException; | 
|---|
|  |  |  | 
|---|
|  |  |  | import java.security.SignatureException; | 
|---|
|  |  |  | import java.security.spec.InvalidKeySpecException; | 
|---|
|  |  |  | import java.text.SimpleDateFormat; | 
|---|
|  |  |  | import java.util.Date; | 
|---|
|  |  |  | import java.util.HashMap; | 
|---|
|  |  |  | import java.util.Map; | 
|---|
|  |  |  | import java.util.Objects; | 
|---|
|  |  |  | import java.util.*; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * @author ZhuBaoMin | 
|---|
|  |  |  | 
|---|
|  |  |  | @RequestMapping(path="payment") | 
|---|
|  |  |  | @RequiredArgsConstructor | 
|---|
|  |  |  | public class PaymentCtrl { | 
|---|
|  |  |  | private final ResourceLoader resourceLoader; | 
|---|
|  |  |  | private final PaymentSv paymentSv; | 
|---|
|  |  |  | private final RestTemplateUtil restTemplateUtil; | 
|---|
|  |  |  | private final PayHelper payHelper; | 
|---|
|  |  |  | private final VirtualCardSv virtualCardSv; | 
|---|
|  |  |  | private final String privateCertFileName = com.dy.pipIrrWechat.wechatpay.PayInfo.privateCertFileName; | 
|---|
|  |  |  | private final String appid = com.dy.pipIrrWechat.wechatpay.PayInfo.appid; | 
|---|
|  |  |  | private final String secret = com.dy.pipIrrWechat.wechatpay.PayInfo.secret; | 
|---|
|  |  |  | private final String mchid = com.dy.pipIrrWechat.wechatpay.PayInfo.mchid; | 
|---|
|  |  |  | private final String schema = com.dy.pipIrrWechat.wechatpay.PayInfo.schema; | 
|---|
|  |  |  | private final String signType = com.dy.pipIrrWechat.wechatpay.PayInfo.signType; | 
|---|
|  |  |  | private final String description = com.dy.pipIrrWechat.wechatpay.PayInfo.description; | 
|---|
|  |  |  | private final String loginUrl = com.dy.pipIrrWechat.wechatpay.PayInfo.loginUrl; | 
|---|
|  |  |  | private final String notifyUrl = com.dy.pipIrrWechat.wechatpay.PayInfo.notifyUrl; | 
|---|
|  |  |  | private final String grantType = com.dy.pipIrrWechat.wechatpay.PayInfo.grantType; | 
|---|
|  |  |  | //private final String appid = com.dy.pipIrrWechat.wechatpay.PayInfo.appid; | 
|---|
|  |  |  | //private final String secret = com.dy.pipIrrWechat.wechatpay.PayInfo.secret; | 
|---|
|  |  |  | //private final String mchid = com.dy.pipIrrWechat.wechatpay.PayInfo.mchid; | 
|---|
|  |  |  | //private final String schema = com.dy.pipIrrWechat.wechatpay.PayInfo.schema; | 
|---|
|  |  |  | //private final String signType = com.dy.pipIrrWechat.wechatpay.PayInfo.signType; | 
|---|
|  |  |  | //private final String description = com.dy.pipIrrWechat.wechatpay.PayInfo.description; | 
|---|
|  |  |  | //private final String loginUrl = com.dy.pipIrrWechat.wechatpay.PayInfo.loginUrl; | 
|---|
|  |  |  | //private final String notifyUrl = com.dy.pipIrrWechat.wechatpay.PayInfo.notifyUrl; | 
|---|
|  |  |  | //private final String grantType = com.dy.pipIrrWechat.wechatpay.PayInfo.grantType; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 平台证书公钥 | 
|---|
|  |  |  | private final Map CERTIFICATE_MAP = new HashMap(); | 
|---|
|  |  |  | 
|---|
|  |  |  | String jsCode = code2Session.getJs_code(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Map<String, Object> queryParams = new HashMap<>(); | 
|---|
|  |  |  | queryParams.put("appid", appid); | 
|---|
|  |  |  | queryParams.put("secret", secret); | 
|---|
|  |  |  | queryParams.put("appid", PayInfo.appid); | 
|---|
|  |  |  | queryParams.put("secret", PayInfo.secret); | 
|---|
|  |  |  | queryParams.put("js_code", jsCode); | 
|---|
|  |  |  | queryParams.put("grant_type", grantType); | 
|---|
|  |  |  | queryParams.put("grant_type", com.dy.pipIrrWechat.wechatpay.PayInfo.grantType); | 
|---|
|  |  |  | Map<String, String> headerParams = new HashMap<>(); | 
|---|
|  |  |  | JSONObject job = restTemplateUtil.get(loginUrl, queryParams, headerParams); | 
|---|
|  |  |  | JSONObject job = restTemplateUtil.get(com.dy.pipIrrWechat.wechatpay.PayInfo.loginUrl, queryParams, headerParams); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if(job.getLong("errcode") != null && job.getLong("errcode") >= -1) { | 
|---|
|  |  |  | return BaseResponseUtils.buildFail("登录凭证校验失败"); | 
|---|
|  |  |  | 
|---|
|  |  |  | String nonceStr = payHelper.generateRandomString(); | 
|---|
|  |  |  | Long timestamp = System.currentTimeMillis() / 1000; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | String header = schema + " " + payHelper.getToken(method, httpUrl, "", nonceStr, timestamp, privateCertFileName); | 
|---|
|  |  |  | byte[] certFileBs = WxCertUtil.getKey_pemBytes(resourceLoader) ; | 
|---|
|  |  |  | String header = com.dy.pipIrrWechat.wechatpay.PayInfo.schema + " " + payHelper.getToken(method, httpUrl, "", nonceStr, timestamp, certFileBs); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Map<String, String> headers = new HashMap<>(); | 
|---|
|  |  |  | headers.put("Authorization", header); | 
|---|
|  |  |  | 
|---|
|  |  |  | // 构造验签名串 | 
|---|
|  |  |  | String signatureStr = payHelper.responseSign(wechatpayTimestamp, wechatpayNonce, job_body.toJSONString()); | 
|---|
|  |  |  | // 验证签名 | 
|---|
|  |  |  | Boolean valid = payHelper.responseSignVerify(wechatpaySerial, signatureStr, wechatpaySignature); | 
|---|
|  |  |  | Boolean valid = payHelper.responseSignVerify(wechatpaySerial, signatureStr, wechatpaySignature, certFileBs); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return BaseResponseUtils.buildSuccess(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @PostMapping(path = "placeOrder") | 
|---|
|  |  |  | @Transactional(rollbackFor = Exception.class) | 
|---|
|  |  |  | public BaseResponse<Boolean> placeOrder(@RequestBody @Valid DtoOrder order, BindingResult bindingResult) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException { | 
|---|
|  |  |  | public BaseResponse<Boolean> placeOrder(@RequestBody @Valid DtoOrder order, BindingResult bindingResult) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException, Exception { | 
|---|
|  |  |  | if(bindingResult != null && bindingResult.hasErrors()){ | 
|---|
|  |  |  | return BaseResponseUtils.buildFail(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 接收参数:登录态ID、虚拟卡ID、充值金额(分) | 
|---|
|  |  |  | // 接收参数:登录态ID、虚拟卡ID、充值金额(单位元) | 
|---|
|  |  |  | Long sessionId = order.getSessionId(); | 
|---|
|  |  |  | Long virtualId = order.getVcId(); | 
|---|
|  |  |  | Integer rechargeAmount = order.getRechargeAmount(); | 
|---|
|  |  |  | //Integer rechargeAmount = (int)(order.getRechargeAmount()*100); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | String prepayId = ""; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | virtualCard.setVirtualId(virtualId); | 
|---|
|  |  |  | virtualCard.setClientId(clientId); | 
|---|
|  |  |  | virtualCard.setOrderNumber(orderNumber); | 
|---|
|  |  |  | virtualCard.setRechargeAmount(rechargeAmount); | 
|---|
|  |  |  | BaseResponse result = virtualCardSv.insertVCRecharge(virtualCard); | 
|---|
|  |  |  | if(!result.getCode().equals("0001")) { | 
|---|
|  |  |  | //virtualCard.setRechargeAmount(rechargeAmount); | 
|---|
|  |  |  | virtualCard.setRechargeAmount(order.getRechargeAmount()); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // -1:虚拟卡不存在,0:添加充值记录失败 | 
|---|
|  |  |  | Long rechargeId = virtualCardSv.insertVCRecharge(virtualCard); | 
|---|
|  |  |  | if(rechargeId.equals(-1)) { | 
|---|
|  |  |  | return BaseResponseUtils.buildFail(WechatResultCode.NO_ACCOUNT.getMessage()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if(rechargeId.equals(0)) { | 
|---|
|  |  |  | return BaseResponseUtils.buildFail(WechatResultCode.RECHARGE_FAIL.getMessage()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 生成充值操作记录,充值操作人为农户 | 
|---|
|  |  |  | SeVcOperate seVcOperate = new SeVcOperate(); | 
|---|
|  |  |  | seVcOperate.setVcId(virtualId); | 
|---|
|  |  |  | seVcOperate.setClientId(clientId); | 
|---|
|  |  |  | seVcOperate.setOperateType(LastOperateENUM.RECHARGE.getCode()); | 
|---|
|  |  |  | seVcOperate.setRechargeId(rechargeId); | 
|---|
|  |  |  | seVcOperate.setOperator(clientId); | 
|---|
|  |  |  | seVcOperate.setOperateTime(new Date()); | 
|---|
|  |  |  | Long vcOperateId = virtualCardSv.insertVcOperate(seVcOperate); | 
|---|
|  |  |  | if(vcOperateId == null) { | 
|---|
|  |  |  | return BaseResponseUtils.buildErrorMsg(WechatResultCode.RECHARGE_ADD_FAIL.getMessage()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | JSONObject job_body = new JSONObject(); | 
|---|
|  |  |  | job_body.put("appid", appid); | 
|---|
|  |  |  | job_body.put("mchid", mchid); | 
|---|
|  |  |  | job_body.put("description", description); | 
|---|
|  |  |  | job_body.put("appid", PayInfo.appid); | 
|---|
|  |  |  | job_body.put("mchid", PayInfo.mchid); | 
|---|
|  |  |  | job_body.put("description", com.dy.pipIrrWechat.wechatpay.PayInfo.description); | 
|---|
|  |  |  | job_body.put("out_trade_no", orderNumber); | 
|---|
|  |  |  | job_body.put("attach", DataSourceContext.get()); | 
|---|
|  |  |  | job_body.put("notify_url", notifyUrl); | 
|---|
|  |  |  | job_body.put("notify_url", com.dy.pipIrrWechat.wechatpay.PayInfo.notifyUrl); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //订单金额 | 
|---|
|  |  |  | JSONObject job_amount = new JSONObject(); | 
|---|
|  |  |  | job_amount.put("total", rechargeAmount); | 
|---|
|  |  |  | job_amount.put("total", (int)(order.getRechargeAmount()*100)); | 
|---|
|  |  |  | job_amount.put("currency", "CNY"); | 
|---|
|  |  |  | job_body.put("amount", job_amount); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | String httpUrl = "/v3/pay/transactions/jsapi"; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | String body = job_body.toJSONString(); | 
|---|
|  |  |  | String header = schema + " " + payHelper.getToken(method, httpUrl, body, nonceStr, timestamp, privateCertFileName); | 
|---|
|  |  |  | byte[] certFileBs = WxCertUtil.getKey_pemBytes(resourceLoader) ; | 
|---|
|  |  |  | String header = com.dy.pipIrrWechat.wechatpay.PayInfo.schema + " " + payHelper.getToken(method, httpUrl, body, nonceStr, timestamp, certFileBs); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Map<String, String> headers = new HashMap<>(); | 
|---|
|  |  |  | headers.put("Authorization", header); | 
|---|
|  |  |  | 
|---|
|  |  |  | String nonceStr = payHelper.generateRandomString(); | 
|---|
|  |  |  | String pkg = "prepay_id=" + prepayId; | 
|---|
|  |  |  | String message = payHelper.buildMessage_signAgain(appid, timeStamp, nonceStr, pkg); | 
|---|
|  |  |  | String paySign = payHelper.sign(message.getBytes("utf-8"), privateCertFileName); | 
|---|
|  |  |  | byte[] certFileBs = WxCertUtil.getKey_pemBytes(resourceLoader) ; | 
|---|
|  |  |  | String paySign = payHelper.sign(message.getBytes("utf-8"), certFileBs); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | JSONObject job_result = new JSONObject(); | 
|---|
|  |  |  | job_result.put("timeStamp", timeStamp); | 
|---|
|  |  |  | job_result.put("nonceStr", nonceStr); | 
|---|
|  |  |  | job_result.put("package", pkg); | 
|---|
|  |  |  | job_result.put("signType", signType); | 
|---|
|  |  |  | job_result.put("signType", com.dy.pipIrrWechat.wechatpay.PayInfo.signType); | 
|---|
|  |  |  | job_result.put("paySign", paySign); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return BaseResponseUtils.buildSuccess(job_result) ; | 
|---|
|  |  |  | 
|---|
|  |  |  | }) | 
|---|
|  |  |  | @PostMapping(path = "orderNotify", consumes = MediaType.APPLICATION_JSON_VALUE) | 
|---|
|  |  |  | @Transactional(rollbackFor = Exception.class) | 
|---|
|  |  |  | public JSONObject orderNotify(@RequestHeader HttpHeaders headers, HttpServletRequest request, HttpServletResponse response) throws IOException, GeneralSecurityException { | 
|---|
|  |  |  | public JSONObject orderNotify(@RequestHeader HttpHeaders headers, HttpServletRequest request, HttpServletResponse response) throws IOException, GeneralSecurityException, Exception { | 
|---|
|  |  |  | JSONObject result = new JSONObject(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 构造验签名串 | 
|---|
|  |  |  | String signatureStr = payHelper.responseSign(wechatpayTimestamp, wechatpayNonce, bodyStr); | 
|---|
|  |  |  | byte[] certFileBs = WxCertUtil.getKey_pemBytes(resourceLoader) ; | 
|---|
|  |  |  | // 验证签名 | 
|---|
|  |  |  | Boolean valid = payHelper.responseSignVerify(wechatpaySerial, signatureStr, wechatpaySignature); | 
|---|
|  |  |  | Boolean valid = payHelper.responseSignVerify(wechatpaySerial, signatureStr, wechatpaySignature, certFileBs); | 
|---|
|  |  |  | if(!valid) { | 
|---|
|  |  |  | response.setStatus(500); | 
|---|
|  |  |  | result.put("code", "FAIL"); | 
|---|
|  |  |  | 
|---|
|  |  |  | result.put("message", "成功"); | 
|---|
|  |  |  | return  result; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 添加微信支付信息 | 
|---|
|  |  |  | * @param po | 
|---|
|  |  |  | * @param bindingResult | 
|---|
|  |  |  | * @return | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @PostMapping(path = "add_wechatpay", consumes = MediaType.APPLICATION_JSON_VALUE) | 
|---|
|  |  |  | public BaseResponse<Boolean> addWechatpay(@RequestBody @Valid Wechatpay po, BindingResult bindingResult) throws Exception { | 
|---|
|  |  |  | if(bindingResult != null && bindingResult.hasErrors()){ | 
|---|
|  |  |  | return BaseResponseUtils.buildFail(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if(paymentSv.getWechatpayByAppId(po.getAppId()) != null) { | 
|---|
|  |  |  | return BaseResponseUtils.buildErrorMsg("该微信支付信息已经存在"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | SeWechatpay seWechatpay = new SeWechatpay(); | 
|---|
|  |  |  | seWechatpay.setAppId(AES.encrypt(po.getAppId())); | 
|---|
|  |  |  | seWechatpay.setAppSecret(AES.encrypt(po.getAppSecret())); | 
|---|
|  |  |  | seWechatpay.setMchId(AES.encrypt(po.getMchId())); | 
|---|
|  |  |  | seWechatpay.setMchKey(AES.encrypt(po.getMchKey())); | 
|---|
|  |  |  | seWechatpay.setSerialNo((AES.encrypt(po.getSerialNo()))); | 
|---|
|  |  |  | seWechatpay.setNotifyUrl(AES.encrypt(po.getNotifyUrl())); | 
|---|
|  |  |  | seWechatpay.setRemarks(po.getRemarks()); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Long rec = Optional.ofNullable(paymentSv.addWechatpay(seWechatpay)).orElse(0L); | 
|---|
|  |  |  | if(rec == 0) { | 
|---|
|  |  |  | return BaseResponseUtils.buildFail("添加微信支付信息失败"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return BaseResponseUtils.buildSuccess(true) ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|