package com.caimei.service.impl; import com.alibaba.fastjson.JSONObject; import com.caimei.components.HeliPayUtil; import com.caimei.components.WeChatService; import com.caimei.constant.Constant; import com.caimei.mapper.CollageMapper; import com.caimei.mapper.CouponMapper; import com.caimei.mapper.OrderMapper; import com.caimei.mapper.PayOrderMapper; import com.caimei.model.ResponseJson; import com.caimei.model.dto.HeliDto; import com.caimei.model.po.*; import com.caimei.model.vo.*; import com.caimei.service.HeliPayService; import com.caimei.util.HttpRequest; import com.caimei.util.MathUtil; import com.caimei.util.helipay.Disguiser; import com.caimei.util.helipay.HttpClientService; import com.caimei.util.helipay.MyBeanUtils; import lombok.extern.slf4j.Slf4j; import okhttp3.OkHttpClient; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpStatus; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.beans.IntrospectionException; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.TimeUnit; /** * Description * * @author : zzj * @date : 2021/11/11 */ @Slf4j @Service public class HeliPayServiceImpl implements HeliPayService { public static OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(3, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .build(); @Resource private OrderMapper orderMapper; @Resource private HeliPayUtil heliPayUtil; @Resource private PayOrderMapper payOrderMapper; @Resource private CouponMapper couponMapper; @Resource private CollageMapper collageMapper; @Resource private WeChatService weChatService; @Value("${caimei.cloudApi}") private String cloudApi; @Override public ResponseJson payOnline(HeliDto heliDto, HttpHeaders headers) { log.info("--------进入公众号/小程序预创建订单接口----------"); try { AppPayPublicCreateOrderVo pay = new AppPayPublicCreateOrderVo(); String splitCode = payOrderMapper.findShopOrderSplitCode(heliDto.getShopOrderId()); pay.setP3_customerNumber(splitCode); //合利宝主扫接口参数赋值 heliPayUtil.setOnlineValue(pay, heliDto, "order", headers); if ("GZH".equals(heliDto.getPayType()) || "XCX".equals(heliDto.getPayType())) { //公众号/小程序 String openId = getOpenId(heliDto, headers); if (StringUtils.isEmpty(openId)) { return ResponseJson.error("微信openId获取失败", null); } pay.setP8_openid(openId); } Map map = MyBeanUtils.convertBean(pay, new LinkedHashMap()); String oriMessage = MyBeanUtils.getSignedByPresetParameter(map, AppPayPublicCreateOrderVo.NEED_SIGN_PARAMS); oriMessage += Constant.SPLIT + Constant.SAOMA; log.info("签名原文串:" + oriMessage); String sign = Disguiser.disguiseMD5(oriMessage.trim()); log.info("签名串:" + sign); map.put("sign", sign); log.info("发送参数:" + map); Map resultMap = HttpClientService.getHttpResp(map, Constant.REQUEST_URL); log.info("响应结果:" + resultMap); if ((Integer) resultMap.get("statusCode") == HttpStatus.SC_OK) { String resultMsg = (String) resultMap.get("response"); AppPayPublicOrderResponseVo orderResponseVo = JSONObject.parseObject(resultMsg, AppPayPublicOrderResponseVo.class); String assemblyRespOriSign = MyBeanUtils.getSignedByPresetParameter(orderResponseVo, AppPayPublicOrderResponseVo.NEED_SIGN_PARAMS); assemblyRespOriSign += Constant.SPLIT + Constant.SAOMA; log.info("组装返回结果签名串:" + assemblyRespOriSign); String responseSign = orderResponseVo.getSign(); log.info("响应签名:" + responseSign); String checkSign = Disguiser.disguiseMD5(assemblyRespOriSign.trim()); if (checkSign.equals(responseSign) && "0000".equals(orderResponseVo.getRt2_retCode())) { JSONObject jsonObject = JSONObject.parseObject(resultMsg); return ResponseJson.success("请求成功", jsonObject); } else { return ResponseJson.error("请求参数有误", JSONObject.parseObject(resultMsg)); } } else { return ResponseJson.error("请求失败", null); } } catch (Exception e) { log.error("交易失败" + e); return ResponseJson.error("交易失败", null); } } @Override public String paymentCallback(NotifyResponseVo res) throws IntrospectionException, InvocationTargetException, IllegalAccessException { log.info("******************** 支付异步回调 start *******************"); // 签名验证 String sign = res.getSign(); log.info("回调签名" + sign); String oriMessage = MyBeanUtils.getSigned(res, null); String oriMessage1 = oriMessage +Constant.SPLIT + Constant.SAOMA; String oriMessage2 = oriMessage +Constant.SPLIT + Constant.FENZHANG; String oriMessage3 = oriMessage +Constant.SPLIT + Constant.XUNI; String oriMessage4 = oriMessage +Constant.SPLIT + Constant.WANGYIN; String checkSign1 = Disguiser.disguiseMD5(oriMessage1.trim()); String checkSign2 = Disguiser.disguiseMD5(oriMessage2.trim()); String checkSign3 = Disguiser.disguiseMD5(oriMessage3.trim()); String checkSign4 = Disguiser.disguiseMD5(oriMessage4.trim()); boolean b = sign.equals(checkSign1) || sign.equals(checkSign2) || sign.equals(checkSign3) || sign.equals(checkSign4); if (!b) { return "验签名失败!"; } // 订单状态 INIT:已接收 DOING:处理中 SUCCESS:成功 FAIL:失败 CLOSE:关闭 CANCEL:撤销 String orderStatus = res.getRt4_status(); // 平台唯一流水号 String mbOrderId = res.getRt3_systemSerial(); // 商户唯一订单号 String orderRequestNo = res.getRt2_orderId(); // 本次支付金额,以元为单位 BigDecimal amount = new BigDecimal(res.getRt5_orderAmount()); log.info("【支付异步回调】>>>>>>>>>>>>>>支付订单状态:" + orderStatus); if (!"SUCCESS".equals(orderStatus)) { return "支付失败"; } String[] split = res.getRt8_desc().split(","); //0位置订单id Integer orderId = Integer.valueOf(split[0]); //1位置支付类型 String payType = split[1]; //2位置子订单id Integer shopOrderId = Integer.valueOf(split[2]); // 订单信息 OrderVo order = orderMapper.findOrder(orderId); ShopOrderVo shopOrder = orderMapper.getShopOrderByOrderId(shopOrderId); if (null == order) { return "订单不存在"; } if(null == shopOrder){ return "子订单不存在"; } // 支付记录 List discernReceiptList = payOrderMapper.getDiscernReceipt(order); double receiptAmount = 0d; if (null != discernReceiptList && discernReceiptList.size() > 0) { for (DiscernReceiptVo discernReceipt : discernReceiptList) { receiptAmount = MathUtil.add(receiptAmount, discernReceipt.getAssociateAmount()).doubleValue(); } } order.setReceiptAmount(MathUtil.add(receiptAmount, amount)); Date date = new Date(); String curDateStr = (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(date); if (MathUtil.compare(order.getPayableAmount(), order.getReceiptAmount()) == 0) { /* * 订单全部支付 * 0待确认,11待收待发,12待收部发,13待收全发,21部收待发,22部收部发,23部收全发, * 31已收待发,32已收部发,33已收全发,4交易完成,5订单完成,6已关闭,7交易全退 */ if ("11".equals(order.getStatus()) || "21".equals(order.getStatus())) { order.setStatus("31"); } else if ("12".equals(order.getStatus()) || "22".equals(order.getStatus())) { order.setStatus("32"); } else { order.setStatus("33"); } order.setPayFlag(1); order.setOnlinePayFlag(0); //(收款买家)收款状态:1待收款、2部分收款、3已收款 order.setReceiptStatus(3); log.info("【支付异步回调】>>>>>>>>>>>>>>订单(全部支付),修改订单状态:" + order.getStatus() + ",orderId:" + orderId); /* * 保存好友消费券赠送记录 */ CouponSharePo couponShare = couponMapper.getCouponShareId(order.getUserId()); if (null != couponShare) { List couponIds = couponMapper.getCurrentCouponIds(5); couponIds.forEach(couponId->{ couponShare.setShareCouponId(couponId); couponMapper.insertCouponShare(couponShare); BigDecimal couponAmount = couponMapper.getCouponAmount(couponId); HashMap map = new HashMap<>(); String mobile = couponMapper.getUserMobile(couponShare.getShareUserId()); String content = "恭喜您邀请的好友已成功消费一笔订单,现赠送" + couponAmount + "元优惠券到您的领券中心,请赶紧登录呵呵商城小程序领取下单吧。退订回T"; map.put("type", 3); map.put("mobile", mobile); map.put("content", content); String url = cloudApi + "/tools/sms/send"; try { String result = HttpRequest.sendPost(url, map); log.info("【呵呵好友消费券派送】mobile:" + mobile + ",result:" + result); // 保存短信发送条数+count couponMapper.updateSmsSendCount(19, 1); } catch (Exception e) { e.printStackTrace(); } }); } // 拼团数据更新 CmHeheCollagePo collage = collageMapper.getCollageByOrderId(orderId); if (null != collage) { if (1 == collage.getLaunchFlag()) { // 拼团发起人支付订单,正式建立拼团 collage.setStatus(1); Date startTime = new Date(); collage.setStartTime(startTime); Calendar calendar = Calendar.getInstance(); calendar.setTime(startTime); calendar.add(Calendar.DAY_OF_MONTH, 1); collage.setEndTime(calendar.getTime()); collageMapper.createCollage(collage); } else { // 已拼且已支付人数 Integer memberNum = collageMapper.findCollageMemberNum(collage.getId()); if (memberNum + 1 == collage.getMemberNum()) { // 拼团成功 collage.setStatus(2); collage.setCompleteTime(new Date()); collageMapper.completeCollage(collage); // 关闭其它未支付拼团订单 List orderIdList = collageMapper.findNoPayCollageOrderIds(collage.getId()); orderIdList.forEach(noPayOrderId->{ orderMapper.cancelOrder(noPayOrderId, "拼团完成关闭其它未支付拼团订单"); }); HashMap map = new HashMap<>(); String mobile = collageMapper.getUserMobileByOrderId(orderId); List mobileList = collageMapper.getMobilesByCollageId(collage.getId()); mobileList.add(mobile); String content = "您的商品已拼团成功,请赶紧登录呵呵商城小程序查看订单吧。"; map.put("type", 1); map.put("content", content); String url = cloudApi + "/tools/sms/send"; try { for (String userMobile : mobileList) { map.put("mobile", userMobile); String result = HttpRequest.sendPost(url, map); log.info("【呵呵拼团成功短信派送】mobile:" + mobile + ",result:" + result); } } catch (Exception e) { e.printStackTrace(); } } } } } else { //部分支付 if ("11".equals(order.getStatus()) || "21".equals(order.getStatus())) { order.setStatus("21"); } else if ("12".equals(order.getStatus()) || "22".equals(order.getStatus())) { order.setStatus("22"); } else { order.setStatus("23"); } order.setOnlinePayFlag(0); //(收款买家)收款状态:1待收款、2部分收款、3已收款 order.setReceiptStatus(2); log.info("【支付异步回调】>>>>>>>>>>>>>>订单(部分支付),修改订单状态:" + order.getStatus() + ",orderId:" + orderId); } // 更新付款次数 order.setPaySuccessCounter(order.getPaySuccessCounter() + 1); order.setUpdateDate(curDateStr); payOrderMapper.updateSelective(order); // 支付记录 // todo 子订单返佣???? List shopOrderDiscernReceiptList = orderMapper.getShopOrderDiscernReceipt(shopOrderId); double shopOrderReceiptAmount = 0d; if (null != shopOrderDiscernReceiptList && shopOrderDiscernReceiptList.size() > 0) { for (DiscernReceiptVo discernReceipt : shopOrderDiscernReceiptList) { shopOrderReceiptAmount = MathUtil.add(shopOrderReceiptAmount, discernReceipt.getAssociateAmount()).doubleValue(); } } shopOrder.setReceiptAmount(MathUtil.add(shopOrderReceiptAmount,amount).doubleValue()); //均摊后needpay:已支付 if (MathUtil.compare(shopOrder.getRealPay(), shopOrder.getReceiptAmount()) == 0) { shopOrder.setReceiptStatus(3); }else{ shopOrder.setReceiptStatus(2); } // 更新子订单收款金额和收款状态 payOrderMapper.updateShopOrderByReceiptStatus(shopOrder); //保存收款记录 CmDiscernReceiptPo discernReceipt = new CmDiscernReceiptPo(); discernReceipt.setPayWay("1"); discernReceipt.setPayType(payType); discernReceipt.setReceiptType("1"); discernReceipt.setReceiptStatus("3"); discernReceipt.setReceiptAmount(amount); discernReceipt.setConfirmType("4"); discernReceipt.setRePayFlag("1"); discernReceipt.setFormData(JSONObject.toJSONString(res)); discernReceipt.setReceiptDate(curDateStr); discernReceipt.setConfirmDate(curDateStr); discernReceipt.setReviewDate(curDateStr); discernReceipt.setUpdateDate(curDateStr); discernReceipt.setDelFlag("0"); payOrderMapper.insertDiscernReceipt(discernReceipt); CmReceiptOrderRelationPo relation = new CmReceiptOrderRelationPo(); relation.setReceiptID(discernReceipt.getId().intValue()); relation.setOrderID(order.getOrderId()); relation.setAssociateAmount(amount); relation.setRelationType("2"); relation.setMbOrderId(mbOrderId); relation.setOrderRequestNo(orderRequestNo); relation.setDelFlag("0"); relation.setSplitStatus("0"); relation.setShopOrderId(shopOrderId); payOrderMapper.insertOrderRelation(relation); log.info(">>>>>>>>>>>>>>>>>>>>>>>保存付款金额到收款记录," + amount); return "SUCCESS"; } private String getOpenId(HeliDto heliDto, HttpHeaders headers) { PayParamBo payParam = new PayParamBo(); // payDto -> payParam BeanUtils.copyProperties(heliDto, payParam); // 微信线上支付 String openId = null; if (null == payParam.getState()) { // 小程序微信授权获取登录信息 ResponseJson> appletsInfo = weChatService.getInfoMapByApplets(payParam.getCode(), headers, 1); if (appletsInfo.getCode() == -1) { return null; } Map infoData = appletsInfo.getData(); openId = (String) infoData.get(WeChatService.Keys.OPEN_ID); if (StringUtils.isEmpty(openId)) { return null; } } else { try { // 微信公众号,通过code获取微信用户信息 Map map = weChatService.getInfoMapByWeb(payParam.getCode(), "crm"); openId = (String) map.get(WeChatService.Keys.OPEN_ID); } catch (Exception e) { log.error("openId获取失败", e); } if (StringUtils.isEmpty(openId)) { return null; } } return openId; } @Override public String delayedSplittingCallback(AccountResVo data) { log.info("延时分账异步回调参数-------------------》 " + data.toString()); try { String oriMessage = MyBeanUtils.getSigned(data, null); oriMessage = oriMessage +Constant.SPLIT + Constant.XUNI; String checkSign = Disguiser.disguiseMD5(oriMessage.trim()); log.info("回调签名 :" + data.getSign()); log.info("checkSign : " + checkSign); if (!checkSign.equals(data.getSign())) { log.info("延时分账异步回调验签失败------------------"); return "验签失败"; } //分账的时候防止相同订单号,前面加了FZ,切割掉2位还原 String orderRequestNo = data.getRt7_orderId().substring(5); //切2位是splict account表orderRequestNo String substring = data.getRt7_orderId().substring(2); String status = data.getRt10_orderStatus(); log.info("【延时分账回调】>>>>>>>>>>分账状态:" + status); if (!"SUCCESS".equals(status)) { return "分账失败"; } // 修改收款分账状态为1 payOrderMapper.updateBySplitStatus(orderRequestNo); List splitAccountList = payOrderMapper.findByMbOrderId(substring); if (splitAccountList != null && splitAccountList.size() > 0) { Integer orderId = splitAccountList.get(0).getOrderId(); List shopOrderList = orderMapper.findAllShopOrder(orderId); Integer shopOrderId = null; String shopOrderNo = ""; for (SplitAccountVo account : splitAccountList) { log.info("【延时分账回调】>>>>>>>>>>保存应付付供应商:" + account.getShopId()); // 本次付供应商金额(分账金额) BigDecimal splitAmount = account.getSplitAccount(); orderId = account.getOrderId(); Integer shopId = account.getShopId(); for (ShopOrderVo shopOrder : shopOrderList) { if (shopId.equals(shopOrder.getShopId())) { shopOrderId = shopOrder.getShopOrderId(); shopOrderNo = shopOrder.getShopOrderNo(); // 已付供应商金额 Double paidAmount = payOrderMapper.findPaidShop(shopOrderId); Double paidShop = MathUtil.add(paidAmount, splitAmount).doubleValue(); shopOrder.setPayedShopAmount(paidShop); if (MathUtil.compare(shopOrder.getShouldPayShopAmount(), paidShop) == 0) { shopOrder.setPayStatus(3); } else { shopOrder.setPayStatus(2); } // 修改子订单付款状态及付款金额 payOrderMapper.updateShopOrderByPayStatus(shopOrderId, paidShop, shopOrder.getPayStatus()); } } SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String currentTime = format.format(new Date()); // 保存付款单表 PayShopPo payShop = new PayShopPo(); payShop.setShopId(shopId); payShop.setName("线上支付分账"); payShop.setTotalAmount(splitAmount.doubleValue()); payShop.setWipePayment(0d); payShop.setPayType(6); payShop.setStatus(1); payShop.setDelFlag(0); payShop.setApplyTime(currentTime); payShop.setReviewTime(currentTime); payShop.setPayTime(currentTime); payOrderMapper.insertPayShop(payShop); // 保存 付供应商记录 PayShopRecordPo shopRecord = new PayShopRecordPo(); shopRecord.setShopId(shopId); shopRecord.setShopOrderId(shopOrderId); shopRecord.setShopOrderNo(shopOrderNo); shopRecord.setPayAmount(splitAmount.doubleValue()); shopRecord.setWipePayment(0d); shopRecord.setPayType(6); shopRecord.setPayTime(currentTime); shopRecord.setPayShopId(payShop.getId()); shopRecord.setStatus(1); shopRecord.setDelFlag(0); payOrderMapper.insertPayShopRecord(shopRecord); } // 子订单是否全部付款 boolean isPay = true; for (ShopOrderVo shopOrder : shopOrderList) { if (3 != shopOrder.getPayStatus()) { isPay = false; break; } } // 修改主订单付款状态 if (isPay) { payOrderMapper.updateOrderByPayStatus(orderId, 3); } else { payOrderMapper.updateOrderByPayStatus(orderId, 2); } } } catch (Exception e) { log.error("【延时分账回调】>>>>>>>>>>分账异步通知异常", e); return "分账失败"; } return "SUCCESS"; } @Override public ResponseJson getPayOrderResult(String mbOrderId) { log.info("--------进入交易订单查询接口----------"); QueryOrderVo queryOrderVo = new QueryOrderVo(); queryOrderVo.setP1_bizType("AppPayQuery"); queryOrderVo.setP2_orderId(mbOrderId); //todo 换收款账户 queryOrderVo.setP3_customerNumber(Constant.CUSTOMERNUM2); try { Map map = MyBeanUtils.convertBean(queryOrderVo, new LinkedHashMap()); String oriMessage = MyBeanUtils.getSignedByPresetParameter(map, QueryOrderVo.NEED_SIGN_PARAMS); //区分网银和其他产品 String payType = payOrderMapper.findPayType(mbOrderId); if ("12".equals(payType) || "17".equals(payType)) { oriMessage += Constant.SPLIT + Constant.WANGYIN; } else { oriMessage += Constant.SPLIT + Constant.SAOMA; } log.info("签名原文串:" + oriMessage); String sign = Disguiser.disguiseMD5(oriMessage.trim()); log.info("签名串:" + sign); map.put("sign", sign); log.info("发送参数:" + map); Map resultMap = HttpClientService.getHttpResp(map, Constant.REQUEST_URL); log.info("响应结果:" + resultMap); if ((Integer) resultMap.get("statusCode") == HttpStatus.SC_OK) { String resultMsg = (String) resultMap.get("response"); QueryOrderResponseVo queryOrderResponseVo = JSONObject.parseObject(resultMsg, QueryOrderResponseVo.class); String assemblyRespOriSign = MyBeanUtils.getSignedByPresetParameter(queryOrderResponseVo, QueryOrderResponseVo.NEED_SIGN_PARAMS); log.info("组装返回结果签名串:" + assemblyRespOriSign); if ("12".equals(payType) || "17".equals(payType)) { assemblyRespOriSign += Constant.SPLIT + Constant.WANGYIN; } else { assemblyRespOriSign += Constant.SPLIT + Constant.SAOMA; } String responseSign = queryOrderResponseVo.getSign(); log.info("响应签名:" + responseSign); String checkSign = Disguiser.disguiseMD5(assemblyRespOriSign.trim()); if (checkSign.equals(responseSign)) { if ("0000".equals(queryOrderResponseVo.getRt2_retCode())) { JSONObject jsonObject = JSONObject.parseObject(resultMsg, JSONObject.class); return ResponseJson.success("查询成功", jsonObject); } else { return ResponseJson.error("验签失败", null); } } else { return ResponseJson.error("验签失败", null); } } else { return ResponseJson.error("请求失败", null); } } catch (Exception e) { return ResponseJson.error("查询失败", null); } } }