package com.cweb.controller; import com.alibaba.fastjson.JSONObject; import com.cweb.config.SysConst; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.hai.common.exception.ErrorCode; import com.hai.common.exception.ErrorHelp; import com.hai.common.exception.SysCode; import com.hai.common.pay.WechatPayUtil; import com.hai.common.pay.entity.WeChatPayReqInfo; import com.hai.common.pay.util.HttpReqUtil; import com.hai.common.pay.util.MD5Util; import com.hai.common.pay.util.XmlUtil; import com.hai.common.pay.util.sdk.WXPayConstants; import com.hai.common.security.SessionObject; import com.hai.common.security.UserCenter; import com.hai.common.utils.*; import com.hai.dao.SecDictionaryMapper; import com.hai.entity.*; import com.hai.model.HighUserModel; import com.hai.model.OrderRefundModel; import com.hai.model.ResponseData; import com.hai.model.ResultProfitSharing; import com.hai.service.CommonService; import com.hai.service.OutRechargeOrderService; import com.hai.service.SecConfigService; import com.hai.service.TelApiService; import com.hai.service.pay.impl.GoodsOrderServiceImpl; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @Controller @RequestMapping(value = "/outRechargeOrder") @Api(value = "充值订单接口") public class OutRechargeOrderController { private static Logger log = LoggerFactory.getLogger(HighMerchantStoreController.class); @Autowired private UserCenter userCenter; @Resource private OutRechargeOrderService outRechargeOrderService; @Resource private TelApiService telApiService; @Resource private WechatPayUtil wechatPayUtil; @Resource private GoodsOrderServiceImpl goodsOrderService; @Resource private CommonService commonService; @Resource private SecConfigService secConfigService; @RequestMapping(value="/addOrder",method = RequestMethod.POST) @ResponseBody @ApiOperation(value = "增加订单") public ResponseData addOrder(@RequestBody OutRechargeOrder outRechargeOrder, HttpServletRequest request) { try { // 用户 SessionObject sessionObject = userCenter.getSessionObject(request); HighUserModel userInfoModel = (HighUserModel) sessionObject.getObject(); if (StringUtils.isBlank(outRechargeOrder.getRechargeContent()) || outRechargeOrder.getPayPrice() == null || outRechargeOrder.getObjectId() == null || outRechargeOrder.getOrderPrice() == null ) { log.error("addOrder error!"); throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, ""); } if (!secConfigService.isConfig("RECHARGE" , "1")) { log.error("addOrder error!"); throw ErrorHelp.genException(SysCode.System, ErrorCode.RECHARGE_CLOSE, ""); } String remarks = ""; // 支付类型 1.微信支付 outRechargeOrder.setPayType(1); // 判断充值模式:1 话费充值 2. 中石化 3. 中石油 if (outRechargeOrder.getRechargeModel() == 1) { JSONObject telObject = telApiService.outApiTel(outRechargeOrder.getRechargeContent()); if (telObject.get("status").equals(0)) { JSONObject o = telObject.getObject("result",JSONObject.class); // 拼接内容 remarks = o.get("province").toString() + o.get("company").toString() + "充值" + outRechargeOrder.getOrderPrice() + "元"; } else { log.error("orderToPay error!"); throw ErrorHelp.genException(SysCode.System, ErrorCode.PHONE_NUM_IS_ERROR); } } else if (outRechargeOrder.getRechargeModel() == 2) { remarks = "中石化充值" + outRechargeOrder.getOrderPrice() + "元"; } else if (outRechargeOrder.getRechargeModel() == 3 ) { // 中石油需要姓名和身份证号 if (StringUtils.isBlank(outRechargeOrder.getRechargeName()) || StringUtils.isBlank(outRechargeOrder.getIdCard()) ) { log.error("orderToPay error!"); throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, ""); } remarks = "中石油充值" + outRechargeOrder.getOrderPrice() + "元"; } else { log.error("orderToPay error!"); throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, ""); } outRechargeOrder.setRemarks(remarks); outRechargeOrder.setOrderNo("CZ" + DateUtil.date2String(new Date(),"yyyyMMddHHmmss") + IDGenerator.nextId(5)); outRechargeOrder.setUserId(userInfoModel.getHighUser().getId()); outRechargeOrder.setUserName(userInfoModel.getHighUser().getName()); outRechargeOrder.setUserPhone(userInfoModel.getHighUser().getPhone()); outRechargeOrder.setCreateTimed(new Date()); outRechargeOrder.setStatus(1); outRechargeOrderService.insertOrder(outRechargeOrder); return ResponseMsgUtil.success(outRechargeOrder); } catch (Exception e) { log.error("HighOrderController -> addOrder() error!",e); return ResponseMsgUtil.exception(e); } } @RequestMapping(value = "/getOrderById", method = RequestMethod.GET) @ResponseBody @ApiOperation(value = "根据id查询订单详情") public ResponseData getOrderById(@RequestParam(name = "orderId", required = true) Long orderId) { try { return ResponseMsgUtil.success(outRechargeOrderService.findByOrderId(orderId)); } catch (Exception e) { log.error("HighOrderController --> getOrderById() error!", e); return ResponseMsgUtil.exception(e); } } @RequestMapping(value = "/cancelOrder", method = RequestMethod.GET) @ResponseBody @ApiOperation(value = "取消订单") public ResponseData cancelOrder(@RequestParam(name = "orderId", required = true) Long orderId) { try { OutRechargeOrder outRechargeOrder = outRechargeOrderService.findByOrderId(orderId); if (outRechargeOrder.getStatus() == 1) { outRechargeOrderService.cancelOrder(orderId); } else { log.error("orderToPay error!"); throw ErrorHelp.genException(SysCode.System, ErrorCode.STATUS_ERROR, ""); } return ResponseMsgUtil.success("操作成功"); } catch (Exception e) { log.error("HighOrderController --> cancelOrder() error!", e); return ResponseMsgUtil.exception(e); } } @RequestMapping(value = "/getUserOrderList", method = RequestMethod.GET) @ResponseBody @ApiOperation(value = "获取用户订单") public ResponseData getUserOrderList( @RequestParam(name = "status", required = false) Integer status, @RequestParam(name = "orderNo", required = false) String orderNo, @RequestParam(name = "rechargeModel", required = false) String rechargeModel, @RequestParam(name = "pageNum", required = true) Integer pageNum, @RequestParam(name = "pageSize", required = true) Integer pageSize, HttpServletRequest request) { try { // 用户 SessionObject sessionObject = userCenter.getSessionObject(request); HighUserModel userInfoModel = (HighUserModel) sessionObject.getObject(); Map map = new HashMap<>(); map.put("userId", userInfoModel.getHighUser().getId().toString()); if (status != null) { map.put("status", status.toString()); } if (StringUtils.isNotBlank(orderNo)) { map.put("orderNo", orderNo); } if (StringUtils.isNotBlank(rechargeModel)) { map.put("rechargeModel", rechargeModel); } PageHelper.startPage(pageNum,pageSize); return ResponseMsgUtil.success(new PageInfo<>(outRechargeOrderService.getListRechargeOrder(map))); } catch (Exception e) { log.error("HighOrderController --> getUserOrderList() error!", e); return ResponseMsgUtil.exception(e); } } @RequestMapping(value="/orderToPay",method = RequestMethod.POST) @ResponseBody @ApiOperation(value = "订单支付发起支付") public ResponseData orderToPay(@RequestBody String reqBodyStr) { try { if (StringUtils.isBlank(reqBodyStr)) { log.error("orderToPay error!", "参数错误"); throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, ""); } JSONObject jsonObject = JSONObject.parseObject(reqBodyStr); Long orderId = jsonObject.getLong("orderId"); String openId = jsonObject.getString("openId"); // openId if (orderId == null || StringUtils.isBlank(openId)) { log.error("orderToPay error!", "参数错误"); throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, ""); } // 订单 OutRechargeOrder order = outRechargeOrderService.findByOrderId(orderId); if (order == null) { log.error("orderToPay error!", "未找到订单信息"); throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到订单信息"); } // 订单状态 : 1.待支付 2.已支付 3.已完成 4.已退款 5.已取消 if (order.getStatus() != 1) { log.error("orderToPay error!", "无法支付,订单不处于待支付状态"); throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "无法支付,订单不处于待支付状态"); } Map map = new HashMap<>(); map.put("orderNo", order.getOrderNo()); map.put("payPrice", order.getPayPrice()); map.put("orderScene", "RECHARGE_ORDER"); map.put("body","购买产品"); map.put("subject","购买产品"); //微信支付 String nonce_str = MD5Util.MD5Encode(String.valueOf(ThreadLocalRandom.current().nextInt(10000)), "UTF-8"); int total_fee = MathUtils.objectConvertBigDecimal(map.get("payPrice")).multiply(new BigDecimal("100")).intValue(); WeChatPayReqInfo weChatPayReqInfo = new WeChatPayReqInfo(); weChatPayReqInfo.setAppid(SysConst.getSysConfig().getWxMchAppId()); //公众号id weChatPayReqInfo.setMch_id(SysConst.getSysConfig().getWxMchId()); //商户号 weChatPayReqInfo.setSub_appid(SysConst.getSysConfig().getWxSubAppId()); //商户号 weChatPayReqInfo.setSub_mch_id(SysConst.getSysConfig().getWxSubMchId()); //子商户号 // weChatPayReqInfo.setOpenid(openId); weChatPayReqInfo.setSub_openid(openId); weChatPayReqInfo.setNonce_str(nonce_str); //随机字符串 weChatPayReqInfo.setBody(map.get("body").toString()); //商品描述 weChatPayReqInfo.setOut_trade_no(map.get("orderNo").toString()); //商户订单号 weChatPayReqInfo.setTotal_fee(total_fee); //总金额 weChatPayReqInfo.setSpbill_create_ip("139.159.177.244"); //终端ip weChatPayReqInfo.setNotify_url(SysConst.getSysConfig().getNotifyUrl()); //通知url weChatPayReqInfo.setTrade_type("JSAPI"); //交易类型 weChatPayReqInfo.setAttach(map.get("orderScene").toString()); weChatPayReqInfo.setProfit_sharing("Y"); //附加数据,区分订单类型 Map payMap = new HashMap<>(); payMap.put("app_id",SysConst.getSysConfig().getWxSubAppId()); payMap.put("api_key",SysConst.getSysConfig().getWxApiKey()); payMap.put("unified_order_url",SysConst.getSysConfig().getWxUnifiedOrderUrl()); SortedMap sortedMap = wechatPayUtil.goWechatPay(weChatPayReqInfo,payMap); return ResponseMsgUtil.success(sortedMap); } catch (Exception e) { log.error("orderToPay error!", e); return ResponseMsgUtil.exception(e); } } @RequestMapping(value = "/orderToRefund", method = RequestMethod.GET) @ResponseBody @ApiOperation(value = "订单退款") public ResponseData orderToRefund(@RequestParam(name = "orderId", required = false) Long orderId, HttpServletRequest request) { try { OutRechargeOrder order = outRechargeOrderService.findByOrderId(orderId); if (order == null) { log.error("orderToPay error!", "未找到充值订单"); throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到充值订单"); } // 订单状态 : 1.待支付 2.已支付 3.已完成 4.已取消 5.已退款 if (order.getStatus() != 2) { log.error("orderToPay error!", "无法退款,订单不处于已支付状态"); throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "无法退款,订单不处于已支付状态"); } Map param = new HashMap<>(); param.put("appid", "wx637bd6f7314daa46"); param.put("mch_id", "1289663601"); param.put("sub_mch_id" , "1609882817"); param.put("nonce_str", WxUtils.makeNonStr()); param.put("transaction_id", order.getPaySerialNo()); param.put("out_refund_no", "HFR"+new Date().getTime()); param.put("total_fee", String.valueOf(order.getPayRealPrice().multiply(new BigDecimal("100")).intValue())); param.put("refund_fee", String.valueOf(order.getPayRealPrice().multiply(new BigDecimal("100")).intValue())); param.put("sign_type", "HMAC-SHA256"); String signStr = WxUtils.generateSignature(param, "Skufk5oi85wDFGl888i6wsRSTkdd5df5" , WXPayConstants.SignType.HMACSHA256); param.put("sign", signStr); String resultXmL = doRefundRequest(param.get("mch_id"), null, WxUtils.mapToXml(param)); OrderRefundModel orderRefundModel = XmlUtil.getObjectFromXML(resultXmL, OrderRefundModel.class); if(orderRefundModel.getResult_code().equals("SUCCESS")) { order.setStatus(5); order.setRefundTime(new Date()); order.setOutRefundNo(orderRefundModel.getOut_refund_no()); order.setRefundId(orderRefundModel.getRefund_id()); order.setRefundFee(new BigDecimal(orderRefundModel.getRefund_fee()).divide(new BigDecimal("100"))); outRechargeOrderService.updateOrder(order); return ResponseMsgUtil.success("退款成功"); } return ResponseMsgUtil.success("退款失败!错误代码:"+orderRefundModel.getErr_code()+",错误描述"+orderRefundModel.getErr_code_des()); } catch (Exception e) { log.error("HighOrderController --> getUserOrderList() error!", e); return ResponseMsgUtil.exception(e); } } @RequestMapping(value = "/wxProfitsharing", method = RequestMethod.GET) @ResponseBody @ApiOperation(value = "分账") public ResponseData wxProfitsharing(String transaction_id,String out_order_no, BigDecimal amount) { try { Map param = new LinkedHashMap<>(); param.put("appid", "wx637bd6f7314daa46"); param.put("mch_id", "1289663601"); //param.put("sub_mch_id" , "1289663601"); param.put("sub_mch_id" , "1609882817"); // 个体户黎杨珍 param.put("transaction_id" , "4200001148202106176001512773"); param.put("out_order_no" , String.valueOf(new Date().getTime())); param.put("nonce_str" , WxUtils.makeNonStr()); BigDecimal rake = new BigDecimal("0.01"); // 计算微信收取的手续费 支付金额 * 0.002 // 向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为上舍入的舍入模式。 BigDecimal wxHandlingFee = amount.multiply(new BigDecimal("0.002")).setScale(2,BigDecimal.ROUND_HALF_DOWN); BigDecimal price = amount.subtract(wxHandlingFee); // 计算分账金额 手续费后的价格 * 0.01 // 向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为上舍入的舍入模式。 BigDecimal profitSharingAmount = price.multiply(rake).setScale(2,BigDecimal.ROUND_DOWN); List> receiversList = new ArrayList<>(); Map receiversMap = new LinkedHashMap<>(); receiversMap.put("type", "MERCHANT_ID"); // receiversMap.put("account", "1604968055");// 个体户方涛 receiversMap.put("account", "1603942866"); // 重庆慧听石化有限责任公司 receiversMap.put("amount", profitSharingAmount.multiply(new BigDecimal("100")).intValue()); receiversMap.put("description", "分给商户【重庆慧听石化有限责任公司】"); receiversList.add(receiversMap); param.put("receivers" , JSONObject.toJSONString(receiversList)); String signStr = WxUtils.generateSignature(param, "Skufk5oi85wDFGl888i6wsRSTkdd5df5" , WXPayConstants.SignType.HMACSHA256); param.put("sign" , signStr); String resultXmL = this.doRefundRequest2(param.get("mch_id"),"https://api.mch.weixin.qq.com/secapi/pay/profitsharing", WxUtils.mapToXml(param)); // 请求分账返回的结果 ResultProfitSharing resultProfitSharing = XmlUtil.getObjectFromXML(resultXmL, ResultProfitSharing.class); return ResponseMsgUtil.success(resultProfitSharing); /* HighProfitSharingRecord sharingRecord = new HighProfitSharingRecord(); sharingRecord.setOutOrderNo(resultProfitSharing.getOut_order_no()); sharingRecord.setTransactionId(resultProfitSharing.getTransaction_id()); sharingRecord.setOrderId(resultProfitSharing.getOrder_id()); sharingRecord.setStatus(resultProfitSharing.getResult_code()); sharingRecord.setPrice(amount); sharingRecord.setCreateTime(new Date()); sharingRecord.setContent(resultXmL); highProfitSharingRecordService.insert(sharingRecord);*/ } catch (Exception e) { log.error("CmsContentController --> getCorporateAdvertising() error!", e); return ResponseMsgUtil.success(e); } } @RequestMapping(value = "/wxEndProfitsharing", method = RequestMethod.GET) @ResponseBody @ApiOperation(value = "完结分账") public ResponseData wxEndProfitsharing(String transaction_id,String out_order_no, BigDecimal amount) { try { Map param = new LinkedHashMap<>(); param.put("appid", "wx637bd6f7314daa46"); param.put("mch_id", "1289663601"); param.put("sub_mch_id" , "1609882817"); // 个体户黎杨珍 param.put("nonce_str" , WxUtils.makeNonStr()); param.put("transaction_id" , "4200001148202106176001512773"); param.put("out_order_no" , "HF2021061710360517203"); param.put("description" , "系统自动完结分账"); String signStr = WxUtils.generateSignature(param, "Skufk5oi85wDFGl888i6wsRSTkdd5df5" , WXPayConstants.SignType.HMACSHA256); param.put("sign" , signStr); String resultXmL = this.doRefundRequest2(param.get("mch_id"),"https://api.mch.weixin.qq.com/secapi/pay/profitsharingfinish", WxUtils.mapToXml(param)); // 请求分账返回的结果 ResultProfitSharing resultProfitSharing = XmlUtil.getObjectFromXML(resultXmL, ResultProfitSharing.class); return ResponseMsgUtil.success(resultXmL); } catch (Exception e) { log.error("CmsContentController --> getCorporateAdvertising() error!", e); return ResponseMsgUtil.success(e); } } @RequestMapping(value = "/wxSelectProfitsharing", method = RequestMethod.GET) @ResponseBody @ApiOperation(value = "查询剩余分账金额") public ResponseData wxSelectProfitsharing(String transaction_id,String out_order_no, BigDecimal amount) { try { Map param = new LinkedHashMap<>(); param.put("mch_id", "1289663601"); //param.put("sub_mch_id" , "1609882817"); // 个体户黎杨珍 param.put("transaction_id" , "4200001152202106114622919776"); ///param.put("out_order_no" , String.valueOf(new Date().getTime())); param.put("nonce_str" , WxUtils.makeNonStr()); String signStr = WxUtils.generateSignature(param, "Skufk5oi85wDFGl888i6wsRSTkdd5df5" , WXPayConstants.SignType.HMACSHA256); param.put("sign", signStr); String unifiedXmL = WxUtils.mapToXml(param); return ResponseMsgUtil.success(HttpReqUtil.HttpsDefaultExecute("POST", "https://api.mch.weixin.qq.com/pay/profitsharingorderamountquery", null, unifiedXmL, null)); } catch (Exception e) { log.error("CmsContentController --> getCorporateAdvertising() error!", e); return ResponseMsgUtil.success(e); } } public String doRefundRequest(String mchId, String url, String data) throws Exception { //小程序退款需要调用双向证书的认证 CloseableHttpClient httpClient = goodsOrderService.readCertificate(mchId); try { HttpPost httpost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund"); // 设置响应头信息 httpost.addHeader("Connection", "keep-alive"); httpost.addHeader("Accept", "*/*"); httpost.addHeader("Content-Type", "text/xml"); httpost.addHeader("Host", "api.mch.weixin.qq.com"); httpost.addHeader("X-Requested-With", "XMLHttpRequest"); httpost.addHeader("Cache-Control", "max-age=0"); httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) "); httpost.setEntity(new StringEntity(data, "UTF-8")); CloseableHttpResponse response = httpClient.execute(httpost); try { HttpEntity entity = response.getEntity(); String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8"); EntityUtils.consume(entity); return jsonStr; } finally { response.close(); } } catch (Exception e){ throw new RuntimeException(e); } finally { httpClient.close(); } } public String doRefundRequest2(String mchId, String url, String data) throws Exception { //小程序退款需要调用双向证书的认证 CloseableHttpClient httpClient = goodsOrderService.readCertificate(mchId); try { HttpPost httpost = new HttpPost(url); // 设置响应头信息 httpost.addHeader("Connection", "keep-alive"); httpost.addHeader("Accept", "*/*"); httpost.addHeader("Content-Type", "text/xml"); httpost.addHeader("Host", "api.mch.weixin.qq.com"); httpost.addHeader("X-Requested-With", "XMLHttpRequest"); httpost.addHeader("Cache-Control", "max-age=0"); httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) "); httpost.setEntity(new StringEntity(data, "UTF-8")); CloseableHttpResponse response = httpClient.execute(httpost); try { HttpEntity entity = response.getEntity(); String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8"); EntityUtils.consume(entity); return jsonStr; } finally { response.close(); } } catch (Exception e){ throw new RuntimeException(e); } finally { httpClient.close(); } } }