package com.lyms.talkonlineweb.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.lyms.talkonlineweb.annotation.Resubmit;
import com.lyms.talkonlineweb.domain.LymsGoods;
import com.lyms.talkonlineweb.domain.LymsOrder;
import com.lyms.talkonlineweb.domain.LymsPatient;
import com.lyms.talkonlineweb.enums.PayStatus;
import com.lyms.talkonlineweb.result.BaseResponse;
import com.lyms.talkonlineweb.service.*;
import com.lyms.talkonlineweb.util.*;
import lombok.extern.log4j.Log4j2;
import org.apache.catalina.util.IOTools;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
/**
* @ProjectName: talkonline
* @Package: com.lyms.talkonlineweb.controller
* @ClassName: OrderController
* @Author: lqy
* @Description: 支付订单类
* @Date: 2021-09-11 09:57
* @Version:
*/
@RestController
@RequestMapping("order")
@Log4j2
public class OrderController {
/**
* 问诊卡信息
*/
@Autowired
private LymsGoodsService lymsGoodsService;
/**
* 患者
*/
@Autowired
private LymsPatientService lymsPatientService;
/**
* 订单
*/
@Autowired
private LymsOrderService lymsOrderService;
/**
* 微信回调通知接口
*/
@Value("${notify.url}")
private String notifyUrl;
/**
* 创建支付订单,并把订单提交到微信平台
* 传入患者id和购买数量
* https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1 微信统一下单api文档地址
* @param lymsOrder
* @param request
* @param response
*/
@PostMapping("createPayOrder")
@Resubmit
public BaseResponse createPayOrder(@RequestBody LymsOrder lymsOrder,
HttpServletRequest request, HttpServletResponse response) {
log.info("create pay order request info : {}",lymsOrder.toString());
BaseResponse baseResponse = new BaseResponse();
//参数校验
if (lymsOrder.getPid() == null || lymsOrder.getCnt() == null)
{
baseResponse.setErrorcode(1);
baseResponse.setErrormsg("创建订单参数错误");
return baseResponse;
}
LymsPatient patient = lymsPatientService.getById(lymsOrder.getPid());
if (patient == null)
{
baseResponse.setErrorcode(1);
baseResponse.setErrormsg("用户不存在");
return baseResponse;
}
LambdaQueryWrapper<LymsGoods> wrapper = new QueryWrapper().lambda();
wrapper.eq(LymsGoods::getType, "card");
LymsGoods goods = lymsGoodsService.getOne(wrapper);
if (goods == null || goods.getPrice() <= 0)
{
baseResponse.setErrorcode(1);
baseResponse.setErrormsg("商品价格配置不存在");
return baseResponse;
}
if (goods.getPrice() != lymsOrder.getPrice() && lymsOrder.getPrice() > 0)
{
baseResponse.setErrorcode(1);
baseResponse.setErrormsg("支付价格不一致!");
return baseResponse;
}
try
{
//生成系统订单号
String orderNo = StringUtil.getUniqueNo();
log.info("create order pid {} ,orderNo {}",lymsOrder.getPid(),orderNo);
lymsOrder.setCreatedtime(new Date());
lymsOrder.setOrderno(orderNo);
lymsOrder.setStatus(PayStatus.CREATED.getCode());
lymsOrder.setOpenid(patient.getOpenid());
lymsOrderService.save(lymsOrder);
//创建微信订单
Map<String,String> data = createWxOrder(lymsOrder);
if (data != null)
{
LymsOrder updateOrder = new LymsOrder();
updateOrder.setId(lymsOrder.getId());
updateOrder.setPayorderid(data.get("payId"));
//根据订单号更新支付订单号
lymsOrderService.updateById(updateOrder);
data.put("orderNo",orderNo);
baseResponse.setObject(data);
return baseResponse;
}
}catch (Exception e){
log.error("create order error.",e);
}
baseResponse.setErrorcode(1);
baseResponse.setErrormsg("创建订单失败");
return baseResponse;
}
/**
* 创建微信订单
*/
private Map<String,String> createWxOrder(LymsOrder lymsOrder) throws Exception
{
try {
String xml = buildRequestXml(lymsOrder);
log.info("create order pid : {},buildRequestMap xml : {}",lymsOrder.getPid(),xml);
//调用微信统一下单接口
String result = HttpUtil.postData(Constant.PAY_URL, xml);
log.info("wx create order result : {}" ,result);
return parseWxResult(result);
} catch (Exception e) {
log.error("createWxOrder error.",e);
throw e;
}
}
/**
* 解析微信创建订单的结果
* @param resultXml
* @throws Exception
*/
private Map<String,String> parseWxResult(String resultXml) throws Exception{
try
{
Map<String,String> data = new HashMap(5);
Map<String,String> retMap = XmlUtil.xmlToMap(resultXml);
System.out.println("retMap:"+retMap);
String success = "SUCCESS";
if (retMap != null && retMap.size() > 0 && success.equals(retMap.get("return_code")) && success.equals(retMap.get("result_code")))
{
data.put("payId",retMap.get("prepay_id"));
data.put("nonce_str",retMap.get("nonce_str"));
data.put("sign",retMap.get("sign"));
data.put("timestamp",System.currentTimeMillis()/1000+"");
return data;
}
}
catch (Exception e)
{
log.error("parse wx result error.",e);
throw e;
}
return null;
}
/**
* 构建微信订单参数
* @param lymsOrder
* @return
* @throws Exception
*/
public String buildRequestXml(LymsOrder lymsOrder) throws Exception {
Map<String,String> paramMap = new TreeMap((key1,key2) -> {
return key1.toString().compareTo(key2.toString());
}
);
//小程序ID
paramMap.put("appid", Constant.PAT_APP_ID);
//商户号
paramMap.put("mch_id", Constant.MCHID);
//随机字符串
paramMap.put("nonce_str", NumberUtil.getRandomString(16));
//签名类型
paramMap.put("sign_type", "MD5");
//商户订单号
paramMap.put("out_trade_no", lymsOrder.getOrderno());
//标价金额
paramMap.put("total_fee", String.valueOf(lymsOrder.getCnt() * lymsOrder.getPrice()));
//终端IP
paramMap.put("spbill_create_ip", "119.90.57.26");
//通知地址
paramMap.put("notify_url", notifyUrl);
//交易类型
paramMap.put("trade_type", "JSAPI");
//用户标识
paramMap.put("openid", lymsOrder.getOpenid());
//商品描述
paramMap.put("body", "问诊支付");
String reqSign = PayDigestUtil.getSign(paramMap, Constant.REQ_KEY);
// 签名
paramMap.put("sign", reqSign);
return XmlUtil.mapToXml(paramMap);
}
/**
* 微信支付成功后回调接口
* https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7&index=8
* @param request
* @param response
* @return
*/
@PostMapping("payNotify")
public void payNotify(HttpServletRequest request, HttpServletResponse response) {
Map<String,String> result = new HashMap<>(2);
result.put("return_code","<![CDATA[FAIL]]>");
result.put("return_msg","参数错误");
try {
Map<String, String> paramMap = getPayNotifyParamMap(request);
//验证支付通知的参数合法性
if (!verifyPayNotify(paramMap)) {
//微信支付订单号
String payOrderId = paramMap.get("transaction_id");
//商户订单号
String mchOrderNo = paramMap.get("out_trade_no");
boolean flag = lymsOrderService.handleOrder(payOrderId,mchOrderNo);
if (flag)
{
result.put("return_code","<![CDATA[SUCCESS]]>");
result.put("return_msg","<![CDATA[OK]]>");
}
}
outResult(response, XmlUtil.mapToXml(result));
}catch (Exception e){
log.error("pay notify error.",e);
try
{
outResult(response, XmlUtil.mapToXml(result));
}catch (Exception e1) {
}
}
}
/**
* 回调接口响应微信
* @param response
* @param content
*/
private void outResult(HttpServletResponse response, String content) {
response.setContentType("text/html");
PrintWriter pw;
try {
pw = response.getWriter();
pw.print(content);
log.info("response pay complete.");
} catch (IOException e) {
log.error("response pay write exception.", e);
}
}
/**
* 解析支付通知参数为map
* @param request
* @return
* @throws Exception
*/
public Map<String, String> getPayNotifyParamMap(HttpServletRequest request) throws Exception{
try
{
String resultXml = IOUtils.toString(request.getInputStream(),"utf-8");
log.info("pay notify info : {}",resultXml);
if (StringUtil.isNotEmpty(resultXml))
{
Map<String, String> retMap = XmlUtil.xmlToMap(resultXml);
String success = "SUCCESS";
if (retMap != null && retMap.size() > 0 && success.equals(retMap.get("return_code")) && success.equals(retMap.get("result_code")))
{
return retMap;
}
}
}catch (Exception e)
{
log.error("get pay notify error.",e);
throw e;
}
return null;
}
/**
* 微信回调参数验证
* @param map
* @return
*/
public boolean verifyPayNotify(Map<String, String> map) {
//商户id
String mchId = map.get("mch_id");
//微信支付订单号
String payOrderId = map.get("transaction_id");
//商户订单号
String mchOrderNo = map.get("out_trade_no");
//现金支付金额
String amount = map.get("cash_fee");
//签名
String sign = map.get("sign");
if (StringUtil.isEmpty(mchId)) {
log.warn("Params error. mchId : {}", mchId);
return false;
}
if (StringUtil.isEmpty(payOrderId)) {
log.warn("Params error. payOrderId : {}", payOrderId);
return false;
}
if (StringUtil.isEmpty(amount)) {
log.warn("Params error. amount : {}", amount);
return false;
}
if (StringUtil.isEmpty(sign)) {
log.warn("Params error. sign : {}", sign);
return false;
}
// 验证签名
if (!verifySign(map)) {
log.warn("verify params sign failed. payOrderId={}", payOrderId);
return false;
}
// 根据payOrderId查询业务订单,验证订单是否存在
LambdaQueryWrapper<LymsOrder> wrapper = new QueryWrapper().lambda();
wrapper.eq(LymsOrder::getOrderno, mchOrderNo);
List<LymsOrder> lymsOrders = lymsOrderService.list(wrapper);
if (CollectionUtils.isNotEmpty(lymsOrders)) {
log.warn("local orderno not exists,payOrderId : {},orderno : {}", payOrderId, mchOrderNo);
return false;
}
// 核对金额
if (lymsOrders.get(0).getPrice() != Integer.parseInt(amount)) {
log.warn("Inconsistent payment amount ,dbPayPrice : {},payPrice : {}", lymsOrders.get(0).getPrice(), amount);
return false;
}
return true;
}
/**
* 回调参数的签名验证
* @param map
* @return
*/
public boolean verifySign(Map<String, String> map) {
String mchId = map.get("mch_id");
//检查商户id
if (!Constant.MCHID.equals(mchId) ) {
return false;
}
String localSign = PayDigestUtil.getSign(map, Constant.REQ_KEY, "sign");
String sign = map.get("sign");
return localSign.equalsIgnoreCase(sign);
}
}