From 0eb6020a9a51c6061641e0b4df69d22a609c70d7 Mon Sep 17 00:00:00 2001 From: Stormeye Wu Date: Wed, 19 Dec 2018 19:41:03 +0800 Subject: [PATCH] =?UTF-8?q?[=E5=82=A8=E5=80=BC=E5=8D=A1][=E6=96=B0?= =?UTF-8?q?=E5=A2=9E]:=E8=A1=A5=E8=B4=B4=E5=8F=8A=E8=A1=A5=E8=B4=B4?= =?UTF-8?q?=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mallinkAdmin/pom.xml | 6 + .../iformall/controller/WxPayController.java | 67 ++++ .../controller/WxSubsidyController.java | 103 +++++ .../main/java/com/iformall/utils/PayUtil.java | 37 ++ .../com/iformall/domain/po/WxSubsidy.java | 152 ++++++++ .../com/iformall/mapper/WxSubsidyMapper.java | 17 + .../com/iformall/pay/WxMicroPayOrderP.java | 2 +- .../com/iformall/pay/WxMicroPayOrderSP.java | 2 +- .../com/iformall/pay/WxNativePayOrderP.java | 50 +++ .../com/iformall/pay/WxNativePayOrderSP.java | 54 +++ .../iformall/service/WxAppinfoService.java | 6 + .../iformall/service/WxSubsidyService.java | 61 +++ .../service/impl/WxAppinfoServiceImpl.java | 13 + .../service/impl/WxOrderServiceImpl.java | 12 +- .../service/impl/WxPayOrderServiceImpl.java | 14 +- .../service/impl/WxSubsidyServiceImpl.java | 368 ++++++++++++++++++ .../main/resources/mapper/WxSubsidyMapper.xml | 103 +++++ 17 files changed, 1052 insertions(+), 15 deletions(-) create mode 100644 mallinkAdmin/src/main/java/com/iformall/controller/WxSubsidyController.java create mode 100644 mallinkAdmin/src/main/java/com/iformall/utils/PayUtil.java create mode 100644 mallinkService/src/main/java/com/iformall/domain/po/WxSubsidy.java create mode 100644 mallinkService/src/main/java/com/iformall/mapper/WxSubsidyMapper.java create mode 100644 mallinkService/src/main/java/com/iformall/pay/WxNativePayOrderP.java create mode 100644 mallinkService/src/main/java/com/iformall/pay/WxNativePayOrderSP.java create mode 100644 mallinkService/src/main/java/com/iformall/service/WxSubsidyService.java create mode 100644 mallinkService/src/main/java/com/iformall/service/impl/WxSubsidyServiceImpl.java create mode 100644 mallinkService/src/main/resources/mapper/WxSubsidyMapper.xml diff --git a/mallinkAdmin/pom.xml b/mallinkAdmin/pom.xml index 3ea123daa..263c5bb2d 100644 --- a/mallinkAdmin/pom.xml +++ b/mallinkAdmin/pom.xml @@ -37,6 +37,12 @@ commons-fileupload 1.3.3 + + + com.google.zxing + core + 3.3.3 + diff --git a/mallinkAdmin/src/main/java/com/iformall/controller/WxPayController.java b/mallinkAdmin/src/main/java/com/iformall/controller/WxPayController.java index e00437a5e..7a0a02901 100644 --- a/mallinkAdmin/src/main/java/com/iformall/controller/WxPayController.java +++ b/mallinkAdmin/src/main/java/com/iformall/controller/WxPayController.java @@ -6,6 +6,7 @@ import com.iformall.exception.MallinkException; import com.iformall.pay.WxPayment; import com.iformall.service.WxPayOrderService; import com.iformall.service.WxRefundOrderService; +import com.iformall.service.WxSubsidyService; import com.iformall.utils.XmlUtil; import org.apache.commons.io.IOUtils; import org.jdom2.JDOMException; @@ -35,6 +36,9 @@ public class WxPayController extends BaseController { @Autowired private WxRefundOrderService wxRefundOrderService; + + @Autowired + private WxSubsidyService wxSubsidyService; /** * * @return 接收微信异步通知 @@ -176,5 +180,68 @@ public class WxPayController extends BaseController { return XmlUtil.getRequestXml(resultMap); } } + + /** + * + * @return 接收微信异步通知 + * @throws Exception 可能产生的任何异常 + */ + @RequestMapping(value = "/subsidyPay", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @ResponseBody + public String _subsidyPayNotify(HttpServletRequest request) throws IOException, JDOMException { + logger.info("[" +getIpAddr() + "]微信支付回调"); + InputStream inStream = request.getInputStream(); + ByteArrayOutputStream outSteam = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len = 0; + while ((len = inStream.read(buffer)) != -1) { + outSteam.write(buffer, 0, len); + } + String resultxml = new String(outSteam.toByteArray(), Charset.forName("UTF-8")); + logger.info(resultxml); + + outSteam.close(); + inStream.close(); + + Map paramMap = null; + + try { + paramMap = WxPayment.xmlToMap(resultxml); + logger.info("微信支付回调, notify, param: " + paramMap.toString() ); + String response = wxSubsidyService.notify(paramMap, EnumPayWay.PAY_WAY_WEAPP); + logger.info("微信支付回调, notify success, req : " + resultxml + ", resp: " + response.toString()); + return response; + } catch (BizMessageException e) { + if (paramMap == null) { + logger.error("微信支付回调, order create error, e: " + e.getMessage()); + } else { + logger.error("微信支付回调, order create error, req: " + resultxml + ", e: " + e.getMessage()); + } + SortedMap resultMap = new TreeMap<>(); + resultMap.put("return_code", "FAIL"); + resultMap.put("return_msg", e.getMessage()); + return XmlUtil.getRequestXml(resultMap); + } catch (MallinkException e) { + if (paramMap == null) { + logger.error("微信支付回调, order create error, e: " + e.getMessage()); + } else { + logger.error("微信支付回调, order create error, req: " + resultxml + ", e: " + e.getMessage()); + } + SortedMap resultMap = new TreeMap<>(); + resultMap.put("return_code", "FAIL"); + resultMap.put("return_msg", e.getMessage()); + return XmlUtil.getRequestXml(resultMap); + } catch (Exception e) { + if (paramMap == null) { + logger.error("微信支付回调, order create error, e: " + e.getMessage()); + } else { + logger.error("微信支付回调, order create error, req: " + resultxml + ", e: " + e.getMessage()); + } + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "FAIL"); + resultMap.put("return_msg", e.getMessage()); + return XmlUtil.getRequestXml(resultMap); + } + } } diff --git a/mallinkAdmin/src/main/java/com/iformall/controller/WxSubsidyController.java b/mallinkAdmin/src/main/java/com/iformall/controller/WxSubsidyController.java new file mode 100644 index 000000000..909c30d09 --- /dev/null +++ b/mallinkAdmin/src/main/java/com/iformall/controller/WxSubsidyController.java @@ -0,0 +1,103 @@ +package com.iformall.controller; + +import com.iformall.domain.po.MallUserInfo; +import com.iformall.exception.MallinkException; +import com.iformall.utils.PayUtil; +import io.swagger.annotations.Api; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import com.github.pagehelper.PageInfo; +import com.iformall.common.Result; +import com.iformall.common.ResultData; + +import com.iformall.domain.po.WxSubsidy; +import com.iformall.service.WxSubsidyService; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.util.Map; + +@RestController +@Api(description = "商城补贴支付接口") +@RequestMapping("wxSubsidy") +public class WxSubsidyController extends BaseController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private WxSubsidyService wxSubsidyService; + + @ApiOperation("补贴扫码支付发起") + @GetMapping("prePay") + @ApiImplicitParams({ + @ApiImplicitParam(name = "amount", value = "金额", dataType = "int", paramType = "query", required = true)}) + public void subsidyPrepay(Integer amount, HttpServletResponse response) throws Exception { + String ipStr = getIpAddr(); + logger.info("subsidyPrepay: " + ipStr + "-" + amount); + MallUserInfo userInfo = getUser(); + ResultData resultData = wxSubsidyService.createSubsidy(userInfo, ipStr, amount); + if(resultData.code == 200) { + String codeUrl = ((Map)resultData.data).get("code_url"); + BufferedImage image = PayUtil.getQRCodeImge(codeUrl); + + response.setContentType("image/jpeg"); + response.setHeader("Pragma","no-cache"); + response.setHeader("Cache-Control","no-cache"); + response.setIntHeader("Expires",-1); + ImageIO.write(image, "JPEG", response.getOutputStream()); + } else { + throw new MallinkException(resultData.code, resultData.message); + } + } + + @ApiOperation("分页列表接口") + @GetMapping("list") + @ApiImplicitParams({ + @ApiImplicitParam(name="pageNum",value="页数",dataType="int", paramType = "query",required=true), + @ApiImplicitParam(name="pageSize",value="每页条数",dataType="int", paramType = "query",required=true)}) + public ResultData list(@ModelAttribute WxSubsidy wxSubsidy,Integer pageNum, Integer pageSize) { + if (null == wxSubsidy) wxSubsidy = new WxSubsidy(); + final PageInfo page = wxSubsidyService.listAsPage(wxSubsidy, pageNum, pageSize); + return new ResultData(page); + } + + @ApiOperation("新增接口") + @PostMapping("add") + public ResultData add(@RequestBody WxSubsidy wxSubsidy) { + //Assert.notNull(wxSubsidy.getName(), "角色名不能为空"); + //Assert.isTrue(!checkUnique(sysRole.getName(), null), "重复的角色名"); + wxSubsidyService.saveOrUpdate(wxSubsidy); + return new ResultData(); + } + + @ApiOperation("根据id更新接口") + @PostMapping("update") + public ResultData update(@RequestBody WxSubsidy wxSubsidy) { + wxSubsidyService.saveOrUpdate(wxSubsidy); + return new ResultData(); + } + + @ApiOperation("根据id删除接口") + @GetMapping("/del") + @ApiImplicitParam(name="id",value="id",dataType="Long", paramType = "query",required=true) + public ResultData delete(Long id) { + wxSubsidyService.deleteById(id); + return new ResultData(Result.SUCCESS, "删除成功", null); + } + + @ApiOperation("根据id查询接口") + @GetMapping("/findById") + @ApiImplicitParam(name="id",value="id",dataType="Long", paramType = "query",required=true) + public ResultData findById(Long id) { + return new ResultData(Result.SUCCESS,"查询成功",wxSubsidyService.getById(id)); + } + + + +} diff --git a/mallinkAdmin/src/main/java/com/iformall/utils/PayUtil.java b/mallinkAdmin/src/main/java/com/iformall/utils/PayUtil.java new file mode 100644 index 000000000..9776aad04 --- /dev/null +++ b/mallinkAdmin/src/main/java/com/iformall/utils/PayUtil.java @@ -0,0 +1,37 @@ +package com.iformall.utils; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + +import java.awt.image.BufferedImage; +import java.util.Hashtable; +import java.util.Map; + +public class PayUtil { + /** + * 根据url生成二位图片对象 + * + * @param codeUrl + * @return + * @throws WriterException + */ + public static BufferedImage getQRCodeImge(String codeUrl) throws WriterException { + Map hints = new Hashtable(); + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); + hints.put(EncodeHintType.CHARACTER_SET, "UTF8"); + int width = 256; + BitMatrix bitMatrix = (new MultiFormatWriter()).encode(codeUrl, BarcodeFormat.QR_CODE, width, width, hints); + BufferedImage image = new BufferedImage(width, width, 1); + for(int x = 0; x < width; ++x) { + for(int y = 0; y < width; ++y) { + image.setRGB(x, y, bitMatrix.get(x, y) ? -16777216 : -1); + } + } + + return image; + } +} diff --git a/mallinkService/src/main/java/com/iformall/domain/po/WxSubsidy.java b/mallinkService/src/main/java/com/iformall/domain/po/WxSubsidy.java new file mode 100644 index 000000000..973447ba9 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/domain/po/WxSubsidy.java @@ -0,0 +1,152 @@ +package com.iformall.domain.po; + +import lombok.Data; +import javax.persistence.*; +import java.util.*; +import java.math.*; +import javax.persistence.Transient; +import java.util.List; +import javax.persistence.Id; +import java.io.Serializable; + +@Table(name = "wx_subsidy") +@Data +public class WxSubsidy implements Serializable { + private static final long serialVersionUID = 1L; + + @Id + protected Long id; + + @Transient + protected List ids; + @Transient + protected String sortColumns; + + /**租户ID*/ + @io.swagger.annotations.ApiModelProperty(value="租户ID",name="tenantId") + private String tenantId; + /**操作用户ID*/ + @io.swagger.annotations.ApiModelProperty(value="操作用户ID",name="operatorUserId") + private Long operatorUserId; + /**创建时间*/ + @io.swagger.annotations.ApiModelProperty(value="创建时间",name="createTime") + private Date createTime; + /**更新时间*/ + @io.swagger.annotations.ApiModelProperty(value="更新时间",name="updateTime") + private Date updateTime; + /**微信商户订单号/商品ID,同ID一致*/ + @io.swagger.annotations.ApiModelProperty(value="微信商户订单号/商品ID,同ID一致",name="orderNo") + private String orderNo; + /**商品描述*/ + @io.swagger.annotations.ApiModelProperty(value="商品描述",name="body") + private String body; + /**终端IP*/ + @io.swagger.annotations.ApiModelProperty(value="终端IP",name="ip") + private String ip; + /**支付状态: 0-支付中;1-支付成功;2-支付失败*/ + @io.swagger.annotations.ApiModelProperty(value="支付状态: 0-支付中;1-支付成功;2-支付失败",name="status") + private Integer status; + /**支付发起时间*/ + @io.swagger.annotations.ApiModelProperty(value="支付发起时间",name="payTimeStart") + private Date payTimeStart; + /**支付结束时间*/ + @io.swagger.annotations.ApiModelProperty(value="支付结束时间",name="payTimeEnd") + private Date payTimeEnd; + /**预支付交易会话标识*/ + @io.swagger.annotations.ApiModelProperty(value="预支付交易会话标识",name="prepayId") + private String prepayId; + /***/ + @io.swagger.annotations.ApiModelProperty(value="",name="codeUrl") + private String codeUrl; + /***/ + @io.swagger.annotations.ApiModelProperty(value="",name="transactionId") + private String transactionId; + /**总金额*/ + @io.swagger.annotations.ApiModelProperty(value="总金额",name="amount") + private Integer amount; + /**可分账总金额*/ + @io.swagger.annotations.ApiModelProperty(value="可分账总金额",name="shareAmount") + private Integer shareAmount; + /**可分账剩余总金额*/ + @io.swagger.annotations.ApiModelProperty(value="可分账剩余总金额",name="shareRemainAmount") + private Integer shareRemainAmount; + /**支付失败原因*/ + @io.swagger.annotations.ApiModelProperty(value="支付失败原因",name="failReason") + private String failReason; + + + + public static enum Field + { + Id_ASC("`id` ASC"),Id_DESC("`id` DESC") + ,TenantId_ASC("`tenant_id` ASC"),TenantId_DESC("`tenant_id` DESC") + ,OperatorUserId_ASC("`operator_user_id` ASC"),OperatorUserId_DESC("`operator_user_id` DESC") + ,CreateTime_ASC("`create_time` ASC"),CreateTime_DESC("`create_time` DESC") + ,UpdateTime_ASC("`update_time` ASC"),UpdateTime_DESC("`update_time` DESC") + ,OrderNo_ASC("`order_no` ASC"),OrderNo_DESC("`order_no` DESC") + ,Body_ASC("`body` ASC"),Body_DESC("`body` DESC") + ,TotalFee_ASC("`total_fee` ASC"),TotalFee_DESC("`total_fee` DESC") + ,Ip_ASC("`ip` ASC"),Ip_DESC("`ip` DESC") + ,Status_ASC("`status` ASC"),Status_DESC("`status` DESC") + ,PayTimeStart_ASC("`pay_time_start` ASC"),PayTimeStart_DESC("`pay_time_start` DESC") + ,PayTimeEnd_ASC("`pay_time_end` ASC"),PayTimeEnd_DESC("`pay_time_end` DESC") + ,PrepayId_ASC("`prepay_id` ASC"),PrepayId_DESC("`prepay_id` DESC") + ,CodeUrl_ASC("`code_url` ASC"),CodeUrl_DESC("`code_url` DESC") + ,TransactionId_ASC("`transaction_id` ASC"),TransactionId_DESC("`transaction_id` DESC") + ,Amount_ASC("`amount` ASC"),Amount_DESC("`amount` DESC") + ,ShareAmount_ASC("`share_amount` ASC"),ShareAmount_DESC("`share_amount` DESC") + ,ShareRemainAmount_ASC("`share_remain_amount` ASC"),ShareRemainAmount_DESC("`share_remain_amount` DESC") + ,FailReason_ASC("`fail_reason` ASC"),FailReason_DESC("`fail_reason` DESC") + ,OpenId_ASC("`open_id` ASC"),OpenId_DESC("`open_id` DESC") + ; + private String value; + Field(String value){ + this.value = value; + } + public String getValue() { + return value; + } + public void setCol(String value) { + this.value = value; + } + @Override + public String toString() { + return this.getValue(); + } + } + + public void setSortColumns(WxSubsidy.Field... fields) + { + if (fields == null || fields.length == 0) { + return; + } + for (int k = 0; k < fields.length; k++) { + if (fields[k] == null) { + return; + } + } + StringBuilder sb = new StringBuilder(fields[0].toString()); + for (int k = 1; k < fields.length; k++) { + sb.append(","); + sb.append(fields[k].toString()); + } + this.sortColumns = sb.toString(); + } + + public void setSortColumns(String sortColumns) + { + if (sortColumns == null || "".equals(sortColumns.trim())) { + return; + } + if (sortColumns.contains(",")) { + String[] cols = sortColumns.split(","); + java.util.List fList = new java.util.ArrayList(); + for (int k = 0; k < cols.length; k++) { + fList.add(Field.valueOf(cols[k])); + } + this.setSortColumns(fList.toArray(new Field[fList.size()])); + } else { + this.setSortColumns(Field.valueOf(sortColumns)); + } + } +} diff --git a/mallinkService/src/main/java/com/iformall/mapper/WxSubsidyMapper.java b/mallinkService/src/main/java/com/iformall/mapper/WxSubsidyMapper.java new file mode 100644 index 000000000..67adbdf13 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/mapper/WxSubsidyMapper.java @@ -0,0 +1,17 @@ +package com.iformall.mapper; + +import java.util.*; +import com.iformall.common.CommonMapper; +import org.apache.ibatis.annotations.Param; +import com.iformall.domain.po.WxSubsidy; + +public interface WxSubsidyMapper extends CommonMapper { + + List findList(WxSubsidy wxSubsidy); + + + + + + +} diff --git a/mallinkService/src/main/java/com/iformall/pay/WxMicroPayOrderP.java b/mallinkService/src/main/java/com/iformall/pay/WxMicroPayOrderP.java index 52c666ee7..5e70a556a 100644 --- a/mallinkService/src/main/java/com/iformall/pay/WxMicroPayOrderP.java +++ b/mallinkService/src/main/java/com/iformall/pay/WxMicroPayOrderP.java @@ -116,7 +116,7 @@ public class WxMicroPayOrderP { @Override public String toString() { - final StringBuilder sb = new StringBuilder("WxPayOrderP{"); + final StringBuilder sb = new StringBuilder("WxMicroPayOrderP{"); sb.append("appid='").append(appid).append('\''); sb.append(", mch_id='").append(mch_id).append('\''); sb.append(", device_info='").append(device_info).append('\''); diff --git a/mallinkService/src/main/java/com/iformall/pay/WxMicroPayOrderSP.java b/mallinkService/src/main/java/com/iformall/pay/WxMicroPayOrderSP.java index cdf617a56..1a7aea08c 100644 --- a/mallinkService/src/main/java/com/iformall/pay/WxMicroPayOrderSP.java +++ b/mallinkService/src/main/java/com/iformall/pay/WxMicroPayOrderSP.java @@ -152,7 +152,7 @@ public class WxMicroPayOrderSP { @Override public String toString() { - final StringBuilder sb = new StringBuilder("WxPayOrderSP{"); + final StringBuilder sb = new StringBuilder("WxMicroPayOrderSP {"); sb.append("appid='").append(appid).append('\''); sb.append(", sub_appid='").append(sub_appid).append('\''); sb.append(", mch_id='").append(mch_id).append('\''); diff --git a/mallinkService/src/main/java/com/iformall/pay/WxNativePayOrderP.java b/mallinkService/src/main/java/com/iformall/pay/WxNativePayOrderP.java new file mode 100644 index 000000000..d0c92eb6c --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/pay/WxNativePayOrderP.java @@ -0,0 +1,50 @@ +package com.iformall.pay; + +import lombok.Data; + +/** + * Created by Stormeye on 2018/11/7. + * 服务商模式 + */ +@Data +public class WxNativePayOrderP { + private String appid; // 小程序ID + private String mch_id; // 商户号 + private String device_info; // 终端设备号 - 门店编号 + private String nonce_str; // 随机字符串 + private String sign; // 签名 + private String sign_type; // 签名类型 + private String body; // 商品简单描述 128 + private String out_trade_no; // 商户订单号 + private Integer total_fee; // 支付金额 + private String spbill_create_ip; // 支付IP + private String time_start; // 开始时间 + private String time_expire; // 失效时间 + private String notify_url; // 通知地址 + private String trade_type; // 支付类型 + private String product_id; // 商品ID + private String profit_sharing; // 是否开启分账 + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("WxNativePayOrderP {"); + sb.append("appid='").append(appid).append('\''); + sb.append(", mch_id='").append(mch_id).append('\''); + sb.append(", device_info='").append(device_info).append('\''); + sb.append(", nonce_str='").append(nonce_str).append('\''); + sb.append(", sign='").append(sign).append('\''); + sb.append(", sign_type='").append(sign_type).append('\''); + sb.append(", body='").append(body).append('\''); + sb.append(", out_trade_no='").append(out_trade_no).append('\''); + sb.append(", total_fee=").append(total_fee); + sb.append(", spbill_create_ip='").append(spbill_create_ip).append('\''); + sb.append(", time_start='").append(time_start).append('\''); + sb.append(", time_expire='").append(time_expire).append('\''); + sb.append(", notify_url='").append(notify_url).append('\''); + sb.append(", trade_type='").append(trade_type).append('\''); + sb.append(", product_id='").append(product_id).append('\''); + sb.append(", profit_sharing='").append(profit_sharing).append('\''); + sb.append('}'); + return sb.toString(); + } +} diff --git a/mallinkService/src/main/java/com/iformall/pay/WxNativePayOrderSP.java b/mallinkService/src/main/java/com/iformall/pay/WxNativePayOrderSP.java new file mode 100644 index 000000000..1266a60e7 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/pay/WxNativePayOrderSP.java @@ -0,0 +1,54 @@ +package com.iformall.pay; + +import lombok.Data; + +/** + * Created by Stormeye on 2018/11/7. + * 服务商模式 + */ +@Data +public class WxNativePayOrderSP { + private String appid; // 公众账号ID + private String sub_appid; // 小程序ID + private String mch_id; // 服务商号 + private String sub_mch_id; // 特约商户号 + private String device_info; // 终端设备号 - 门店编号 + private String nonce_str; // 随机字符串 + private String sign; // 签名 + private String sign_type; // 签名类型 + private String body; // 商品简单描述 128 + private String out_trade_no; // 商户订单号 + private Integer total_fee; // 支付金额 + private String spbill_create_ip; // 支付IP + private String time_start; // 开始时间 + private String time_expire; // 失效时间 + private String notify_url; // 通知地址 + private String trade_type; // 支付类型 + private String product_id; // 商品ID + private String profit_sharing; // 是否开启分账 + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("WxNativePayOrderSP {"); + sb.append("appid='").append(appid).append('\''); + sb.append(", sub_appid='").append(sub_appid).append('\''); + sb.append(", mch_id='").append(mch_id).append('\''); + sb.append(", sub_mch_id='").append(sub_mch_id).append('\''); + sb.append(", device_info='").append(device_info).append('\''); + sb.append(", nonce_str='").append(nonce_str).append('\''); + sb.append(", sign='").append(sign).append('\''); + sb.append(", sign_type='").append(sign_type).append('\''); + sb.append(", body='").append(body).append('\''); + sb.append(", out_trade_no='").append(out_trade_no).append('\''); + sb.append(", total_fee=").append(total_fee); + sb.append(", spbill_create_ip='").append(spbill_create_ip).append('\''); + sb.append(", time_start='").append(time_start).append('\''); + sb.append(", time_expire='").append(time_expire).append('\''); + sb.append(", notify_url='").append(notify_url).append('\''); + sb.append(", trade_type='").append(trade_type).append('\''); + sb.append(", product_id='").append(product_id).append('\''); + sb.append(", profit_sharing='").append(profit_sharing).append('\''); + sb.append('}'); + return sb.toString(); + } +} diff --git a/mallinkService/src/main/java/com/iformall/service/WxAppinfoService.java b/mallinkService/src/main/java/com/iformall/service/WxAppinfoService.java index 5ad807b40..1149123ec 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxAppinfoService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxAppinfoService.java @@ -33,6 +33,12 @@ public interface WxAppinfoService { * @return */ WxAppinfo getByAppId(String appId); + + /** + * 获取c端小程序信息 + * @return + */ + WxAppinfo getCAppInfo(String tenantId); /** * 保存或更新实体 diff --git a/mallinkService/src/main/java/com/iformall/service/WxSubsidyService.java b/mallinkService/src/main/java/com/iformall/service/WxSubsidyService.java new file mode 100644 index 000000000..3971f5075 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/WxSubsidyService.java @@ -0,0 +1,61 @@ +package com.iformall.service; + +import com.github.pagehelper.PageInfo; +import com.iformall.common.ResultData; +import com.iformall.domain.po.MallUserInfo; +import com.iformall.domain.po.WxSubsidy; +import com.iformall.enums.EnumPayWay; + +import java.util.Map; + +public interface WxSubsidyService { + + /** + * 创建补贴订单 + * @param amount + * @return + */ + ResultData createSubsidy(MallUserInfo user, String ip, Integer amount); + + /** + * 根据实体查询分页列表 + * + * @param record + * @param pageIndex + * @param pageSize + * @return + */ + PageInfo listAsPage(WxSubsidy record, Integer pageIndex, Integer pageSize); + + /** + * 根据Id获得实体 + * + * @param id + * @return + */ + WxSubsidy getById(Long id); + + /** + * 保存或更新实体 + * + * @param record + */ + void saveOrUpdate(WxSubsidy record); + + /** + * 根据Id删除实体 + * + * @param id + */ + void deleteById(Long id); + + String notify(Map paramMap, EnumPayWay payWay); + + + + + + + + +} diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxAppinfoServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxAppinfoServiceImpl.java index a1b73ab94..0138a8c07 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxAppinfoServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxAppinfoServiceImpl.java @@ -38,6 +38,19 @@ public class WxAppinfoServiceImpl implements WxAppinfoService { @Autowired WxAppinfoMapper wxAppinfoMapper; + @Override + public WxAppinfo getCAppInfo(String tenantId) { + WxAppinfo appInfo = null; + WxAppinfo appinfoQ = new WxAppinfo(); + appinfoQ.setTenantId(tenantId); + appinfoQ.setType(EnumAppType.C.getCode()); + List appList = wxAppinfoMapper.select(appinfoQ); + if (appList.size() > 0) { + appInfo = appList.get(0); + } + return appInfo; + } + @Override public WxAppinfo getByAppId(String appId) { return wxAppinfoMapper.findByAppId(appId); diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java index a8492a4d8..f6e52e104 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java @@ -71,6 +71,9 @@ public class WxOrderServiceImpl implements WxOrderService { @Autowired WxMerchantBUserMapper wxMerchantBUserMapper; + @Autowired + WxAppinfoService wxAppinfoService; + @Autowired WxPayOrderService wxPayOrderService; @@ -870,14 +873,7 @@ public class WxOrderServiceImpl implements WxOrderService { @Override public ResultData orderClose(WxOrder order) { // 1. get c appid - WxAppinfo appInfo = null; - WxAppinfo appinfoQ = new WxAppinfo(); - appinfoQ.setTenantId(order.getTenantId()); - appinfoQ.setType(EnumAppType.C.getCode()); - List appList = wxAppinfoMapper.select(appinfoQ); - if (appList.size() > 0) { - appInfo = appList.get(0); - } + WxAppinfo appInfo = wxAppinfoService.getCAppInfo(order.getTenantId()); // 2. get pay order WxPayOrder payOrderQ = new WxPayOrder(); payOrderQ.setTenantId(order.getTenantId()); diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java index b9968df10..1576461d6 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java @@ -13,6 +13,7 @@ import com.iformall.enums.*; import com.iformall.exception.MallinkException; import com.iformall.mapper.*; import com.iformall.pay.*; +import com.iformall.service.WxAppinfoService; import com.iformall.service.WxCouponOrderService; import com.iformall.service.WxOrderService; import com.iformall.service.WxPayOrderService; @@ -70,6 +71,9 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { @Autowired WxCouponOrderService wxCouponOrderService; + @Autowired + WxAppinfoService wxAppinfoService; + JSONObject errorMap = JSON.parseObject("{" + "\"NOAUTH\":{\"detail\":\"商户无此接口权限\",\"reason\":\"商户未开通此接口权限\",\"resolution\":\"请商户前往申请此接口权限\"}," + "\"NOTENOUGH\":{\"detail\":\"余额不足\",\"reason\":\"用户帐号余额不足\",\"resolution\":\"用户帐号余额不足,请用户充值或更换支付卡后再支付\"}," + @@ -367,7 +371,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { public ResultData createMicroPayOrder(boolean isReal, WxMerchantBUser user, WxPayOrder record, EnumPayWay payWay) { final IdWorker idworker = IdWorker.get(); - WxAppinfo appInfo = getWxAppinfo(EnumOrderType.MICROPAY.getCode(), user.getTenantId()); + WxAppinfo appInfo = wxAppinfoService.getCAppInfo(user.getTenantId()); EnumPayShare isShare = EnumPayShare.NO; @@ -686,7 +690,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { return new ResultData(ErrorCode.PAY_ORDER_ERROR.getCode(), "Order not found"); } - WxAppinfo appInfo = getWxAppinfo(order.getType(), record.getTenantId()); + WxAppinfo appInfo = wxAppinfoService.getCAppInfo(record.getTenantId()); String response = wechatPayOrderQuery(appInfo, record); @@ -948,7 +952,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { @Override public ResultData payOrderReverse(WxPayOrder record) { - WxAppinfo appInfo = getWxAppinfo(EnumOrderType.MICROPAY.getCode(), record.getTenantId()); + WxAppinfo appInfo = wxAppinfoService.getCAppInfo(record.getTenantId()); try { String response = wechatPayOrderReverse(appInfo, record); @@ -1239,7 +1243,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { throw new MallinkException(ErrorCode.ORDER_IS_NOT_FIND); } - WxAppinfo appinfo = getWxAppinfo(EnumOrderType.MICROPAY.getCode(), order.getTenantId()); + WxAppinfo appinfo = wxAppinfoService.getCAppInfo(order.getTenantId()); // add c_user Date curDate = new Date(); @@ -1365,7 +1369,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { if (record.getId() > 0) { // 有价券 // 1. get appinfo - WxAppinfo appInfo = getWxAppinfo(order.getType(), order.getTenantId()); + WxAppinfo appInfo = wxAppinfoService.getCAppInfo(order.getTenantId()); if (2 == status) { // 前端支付取消, diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxSubsidyServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxSubsidyServiceImpl.java new file mode 100644 index 000000000..3630755a5 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxSubsidyServiceImpl.java @@ -0,0 +1,368 @@ +package com.iformall.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.iformall.common.ErrorCode; +import com.iformall.common.Result; +import com.iformall.common.ResultData; +import com.iformall.domain.po.*; +import com.iformall.enums.EnumPayShare; +import com.iformall.enums.EnumPayStatus; +import com.iformall.enums.EnumPayWay; +import com.iformall.exception.MallinkException; +import com.iformall.mapper.WxAppinfoMapper; +import com.iformall.mapper.WxPayAccountMapper; +import com.iformall.mapper.WxSubsidyMapper; +import com.iformall.pay.WxNativePayOrderSP; +import com.iformall.pay.WxPay; +import com.iformall.pay.WxPayment; +import com.iformall.service.WxAppinfoService; +import com.iformall.service.WxSubsidyService; +import com.iformall.utils.BeanUtils; +import com.iformall.utils.Utility; +import com.iformall.utils.XmlUtil; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.iformall.common.IdWorker; + +import java.text.ParseException; +import java.util.*; + +@Service +public class WxSubsidyServiceImpl implements WxSubsidyService { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + WxSubsidyMapper wxSubsidyMapper; + + @Autowired + WxAppinfoMapper wxAppinfoMapper; + + @Autowired + WxAppinfoService wxAppinfoService; + + @Autowired + WxPayAccountMapper wxPayAccountMapper; + + JSONObject errorMap = JSON.parseObject("{" + + "\"INVALID_REQUEST\":{\"detail\":\"参数错误\",\"reason\":\"参数格式有误或者未按规则上传\",\"resolution\":\"订单重入时,要求参数值与原请求一致,请确认参数问题\"}," + + "\"NOAUTH\":{\"detail\":\"商户无此接口权限\",\"reason\":\"商户未开通此接口权限\",\"resolution\":\"请商户前往申请此接口权限\"}," + + "\"NOTENOUGH\":{\"detail\":\"余额不足\",\"reason\":\"用户帐号余额不足\",\"resolution\":\"用户帐号余额不足,请用户充值或更换支付卡后再支付\"}," + + "\"ORDERPAID\":{\"detail\":\"商户订单已支付\",\"reason\":\"商户订单已支付,无需重复操作\",\"resolution\":\"商户订单已支付,无需更多操作\"}," + + "\"ORDERCLOSED\":{\"detail\":\"订单已关闭\",\"reason\":\"当前订单已关闭,无法支付\",\"resolution\":\"当前订单已关闭,请重新下单\"}," + + "\"SYSTEMERROR\":{\"detail\":\"系统错误\t\",\"reason\":\"系统超时\",\"resolution\":\"系统异常,请用相同参数重新调用\"}," + + "\"APPID_NOT_EXIST\":{\"detail\":\"APPID不存在\",\"reason\":\"参数中缺少APPID\",\"resolution\":\"请检查APPID是否正确\"}," + + "\"MCHID_NOT_EXIST\":{\"detail\":\"MCHID不存在\",\"reason\":\"参数中缺少MCHID\",\"resolution\":\"请检查MCHID是否正确\"}," + + "\"APPID_MCHID_NOT_MATCH\":{\"detail\":\"appid和mch_id不匹配\",\"reason\":\"appid和mch_id不匹配\",\"resolution\":\"请确认appid和mch_id是否匹配\"}," + + "\"LACK_PARAMS\":{\"detail\":\"缺少参数\t\",\"reason\":\"缺少必要的请求参数\",\"resolution\":\"请检查参数是否齐全\"}," + + "\"OUT_TRADE_NO_USED\":{\"detail\":\"商户订单号重复\",\"reason\":\"同一笔交易不能多次提交\",\"resolution\":\"请核实商户订单号是否重复提交\"}," + + "\"SIGNERROR\":{\"detail\":\"签名错误\",\"reason\":\"参数签名结果不正确\",\"resolution\":\"请检查签名参数和方法是否都符合签名算法要求\"}," + + "\"XML_FORMAT_ERROR\":{\"detail\":\"XML格式错误\t\",\"reason\":\"XML格式错误\",\"resolution\":\"请检查XML参数格式是否正确\"}," + + "\"REQUIRE_POST_METHOD\":{\"detail\":\"请使用post方法\",\"reason\":\"未使用post传递参数\",\"resolution\":\"请检查请求参数是否通过post方法提交\"}," + + "\"POST_DATA_EMPTY\":{\"detail\":\"post数据为空\",\"reason\":\"post数据不能为空\",\"resolution\":\"请检查post数据是否为空\"}," + + "\"NOT_UTF8\":{\"detail\":\"编码格式错误\",\"reason\":\"未使用指定编码格式\",\"resolution\":\"请使用UTF-8编码格式\"}}"); + + JSONObject errorMapQuery = JSON.parseObject("{" + + "\"ORDERNOTEXIST\":{\"detail\":\"此交易订单号不存在\",\"reason\":\"查询系统中不存在此交易订单号\",\"resolution\":\"该API只能查提交支付交易返回成功的订单,请商户检查需要查询的订单号是否正确\"},\n" + + "\"SYSTEMERROR\":{\"detail\":\"系统错误\t\",\"reason\":\"后台系统返回错误\",\"resolution\":\"系统异常,请再调用发起查询\"}}"); + + JSONObject errorMapClose = JSON.parseObject("{" + + "\"ORDERPAID\":{\"detail\":\"订单已支付\",\"reason\":\"订单已支付,不能发起关单\",\"resolution\":\"订单已支付,不能发起关单,请当作已支付的正常交易\"}," + + "\"SYSTEMERROR\":{\"detail\":\"系统错误\",\"reason\":\"系统错误\",\"resolution\":\"系统异常,请重新调用该API\"}," + + "\"ORDERCLOSED\":{\"detail\":\"订单已关闭\",\"reason\":\"订单已关闭,无法重复关闭\",\"resolution\":\"订单已关闭,无需继续调用\"}," + + "\"SIGNERROR\":{\"detail\":\"签名错误\",\"reason\":\"参数签名结果不正确\",\"resolution\":\"请检查签名参数和方法是否都符合签名算法要求\"}," + + "\"REQUIRE_POST_METHOD\":{\"detail\":\"请使用post方法\",\"reason\":\"未使用post传递参数\",\"resolution\":\"请检查请求参数是否通过post方法提交\"}," + + "\"XML_FORMAT_ERROR\":{\"detail\":\"XML格式错误\t\",\"reason\":\"XML格式错误\",\"reason\":\"请检查XML参数格式是否正确\"}}"); + + @Override + public ResultData createSubsidy(MallUserInfo user, String ip, Integer amount) { + final IdWorker idWorker = IdWorker.get(); + EnumPayShare isShare = EnumPayShare.NO; + Date curDate = new Date(); + // 1. 获取c端小程序 + WxAppinfo appInfo = wxAppinfoService.getCAppInfo(user.getTenantId()); + // 2. 获取payAccount + WxPayAccount payAccount = wxPayAccountMapper.selectByPrimaryKey(appInfo.getPayId()); + if (payAccount.getShare().intValue() > 0) { + isShare = EnumPayShare.YES; + } + // 3. 补贴订单 + Integer totalFee = amount * 100; // 元->分 + + Long id = idWorker.nextId(); + String payOrderNo = String.valueOf(id); + WxSubsidy record = new WxSubsidy(); + record.setId(id); + record.setTenantId(user.getTenantId()); + record.setOperatorUserId(user.getId()); + record.setCreateTime(curDate); + record.setUpdateTime(curDate); + record.setOrderNo(payOrderNo); + record.setBody("商场补贴-"+amount + "元"); + record.setIp(ip); + record.setStatus(EnumPayStatus.PAY_STATUS_WAIT.getCode()); + record.setPayTimeStart(curDate); + record.setPayTimeEnd(curDate); + record.setAmount(totalFee); + // 分账金额 + Double dChargeFee = Math.ceil(record.getAmount() * 1.0D * payAccount.getRate() / 10000); + Integer share_amount = record.getAmount() - dChargeFee.intValue(); + record.setShareAmount(share_amount); + try { + wxSubsidyMapper.insertSelective(record); + } catch (Exception e) { + logger.error("wx_subsidy save fail" + e.getMessage()); + return new ResultData(ErrorCode.DB_FAIL); + } + // 3. 支付发起 + try { + // 统一下单 // 服务商模式 + String noncestr = Utility.generate32UUID(); + WxNativePayOrderSP payOrder = new WxNativePayOrderSP(); + payOrder.setAppid(appInfo.getParentAppId()); + payOrder.setSub_appid(appInfo.getAppId()); + payOrder.setMch_id(payAccount.getMchId()); + payOrder.setSub_mch_id(payAccount.getSubMchId()); + payOrder.setDevice_info("WEB"); + payOrder.setNonce_str(noncestr); + payOrder.setBody(record.getBody()); + payOrder.setOut_trade_no(record.getOrderNo()); + payOrder.setTotal_fee(record.getAmount()); + payOrder.setSpbill_create_ip(record.getIp()); + payOrder.setTime_start(Utility.getDataFormatStringYYYYMMDDHHmmss(curDate)); + Date futureDate = new Date(); + futureDate.setTime(curDate.getTime() + 15 * 60 * 1000); + payOrder.setTime_expire(Utility.getDataFormatStringYYYYMMDDHHmmss(futureDate)); // 15分钟后结束 + payOrder.setNotify_url(payAccount.getNotifyUrl() + "/subsidyPay"); + payOrder.setTrade_type("NATIVE"); + payOrder.setProduct_id(record.getOrderNo()); + payOrder.setSign_type("HMAC-SHA256"); + payOrder.setProfit_sharing(null); + if (isShare == EnumPayShare.YES) { + payOrder.setProfit_sharing("Y"); + } + Map payOrderMap = BeanUtils.toStringMap(payOrder); + + payOrder.setSign(WxPayment.createSignHMAC(payOrderMap, payAccount.getApiKey())); + String response = WxPay.pushOrder(BeanUtils.toStringMap(payOrder)); + logger.info("wx_subsidy wechat native Pay, " + payOrder.toString() + ", response: " + response.toString()); + Map returnMap = WxPayment.xmlToMap(response); + String return_code = returnMap.get("return_code"); + String result_code = returnMap.get("result_code"); + if ("SUCCESS".equalsIgnoreCase(return_code)) { + if ("SUCCESS".equals(result_code)) { + String prepay_id = returnMap.get("prepay_id"); + String code_url = returnMap.get("code_url"); + // update payOrder with prepay_id + record.setPrepayId(prepay_id); + record.setCodeUrl(code_url); + record.setUpdateTime(new Date()); + try { + wxSubsidyMapper.updateByPrimaryKeySelective(record); + } catch (Exception e) { + logger.error("wx_subsidy update error: " + record.toString()); + throw new MallinkException(ErrorCode.DB_FAIL); + } + + Map retMap = new HashMap(); + retMap.put("code_url", code_url); + return new ResultData(Result.SUCCESS, "创建支付订单成功", retMap); + } else { + String errMsg = ""; + JSONObject errObj = errorMap.getJSONObject(result_code); + if (errObj != null) { + errMsg = errObj.toJSONString(); + record.setFailReason(errMsg); + } else { + errMsg = returnMap.get("return_msg"); + record.setFailReason(errMsg); + } + record.setUpdateTime(new Date()); + try { + wxSubsidyMapper.updateByPrimaryKeySelective(record); + } catch (Exception e) { + logger.error("pay order update error: " + record.toString()); + throw new MallinkException(ErrorCode.DB_FAIL); + } + return new ResultData(ErrorCode.PAY_ORDER_ERROR.getCode(), errMsg, returnMap); + } + } else { + String errMsg = returnMap.get("return_msg"); + record.setFailReason(errMsg); + record.setUpdateTime(new Date()); + try { + wxSubsidyMapper.updateByPrimaryKeySelective(record); + } catch (Exception e) { + logger.error("pay order update error: " + record.toString()); + throw new MallinkException(ErrorCode.DB_FAIL); + } + return new ResultData(ErrorCode.PAY_ORDER_ERROR.getCode(), errMsg, returnMap); + } + } catch (RuntimeException e) { + throw new MallinkException(ErrorCode.PAY_ORDER_ERROR.getCode(), e.getMessage()); + } catch (Exception e) { + throw new MallinkException(ErrorCode.PAY_ORDER_ERROR.getCode(), e.getMessage()); + } + } + + /** + * 提供微信支付回调调用 + * + * @param paramMap 异步通知参数 + * @param payWay 支付方式 + * @return + */ + @Override + public String notify(Map paramMap, EnumPayWay payWay) { + // how to get wechatAppId, wechatMchId, partnerKey + String appId = paramMap.get("appid"); + String subAppId = paramMap.get("sub_appid"); + String mchId = paramMap.get("mch_id"); + String subMchId = paramMap.get("sub_mch_id"); + WxAppinfo appinfo = null; + boolean isNormal = true; + if (StringUtils.isBlank(subAppId) && StringUtils.isBlank(subMchId)) { + // 普通商户号 + appinfo = wxAppinfoMapper.findByAppId(appId); + if (appinfo == null) { + logger.error("appid not found: " + appId); + throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); + } + isNormal = true; + } else { + // 服务号 现在用hmac-sha256 + appinfo = wxAppinfoMapper.findByAppId(subAppId); + if (appinfo == null) { + logger.error("subappid not found: " + subAppId); + throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); + } + isNormal = false; + } + + WxPayAccount payAccount = wxPayAccountMapper.selectByPrimaryKey(appinfo.getPayId()); + if (payAccount == null) { + throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND); + } + String partnerKey = payAccount.getApiKey(); + try { + if (payWay == EnumPayWay.PAY_WAY_WEAPP) { + boolean signVerified = false; + if (isNormal) { + // 普通商户号支付 + signVerified = WxPayment.verifyNotify(paramMap, partnerKey); + if (!signVerified) { + logger.warn("notify order, wxpay checksign error, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + throw new MallinkException(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR); + } + } else { + // 服务号 现在用hmac-sha256 + signVerified = WxPayment.verifyNotifyHMAC(paramMap, partnerKey); + if (!signVerified) { + logger.warn("notify order, wxpay checksign error, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + throw new MallinkException(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR); + } + } + + if (!"SUCCESS".equals(paramMap.get("return_code"))) { + logger.warn("notify order, wxpay status not success, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "FAIL"); + resultMap.put("return_msg", "订单状态码非SUCCESS"); + return XmlUtil.getRequestXml(resultMap); + } + + String payOrderNo = paramMap.get("out_trade_no"); + String transactionId = paramMap.get("transaction_id"); + String timEndStr = paramMap.get("time_end"); + Long payOrderId = Long.valueOf(payOrderNo); + WxSubsidy subsidy = wxSubsidyMapper.selectByPrimaryKey(payOrderId); + if (subsidy == null) { + logger.warn("notify order, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "FAIL"); + resultMap.put("return_msg", "订单不存在"); + return XmlUtil.getRequestXml(resultMap); + } + // 验证支付金额 + if (!paramMap.get("total_fee").equals(subsidy.getAmount().toString())) { + logger.warn("notify order, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "FAIL"); + resultMap.put("return_msg", "订单总金额不一致"); + return XmlUtil.getRequestXml(resultMap); + } + + Date timeEnd = null; + + try { + timeEnd = Utility.getDateFromString(timEndStr); + } catch (ParseException e) { + logger.error("解析timeEnd失败"); + timeEnd = new Date(); + } + subsidy.setPayTimeEnd(timeEnd); + subsidy.setUpdateTime(new Date()); + try { + wxSubsidyMapper.updateByPrimaryKeySelective(subsidy); + } catch (Exception e) { + logger.error("wx_subsidy update exception"); + } + logger.info("notify order, wxpay checksign success, paramMap:{}, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "SUCCESS"); + resultMap.put("return_msg", "OK"); + return XmlUtil.getRequestXml(resultMap); + } + } catch (RuntimeException e) { + logger.warn("notify order, checksign error, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); + throw new MallinkException(ErrorCode.PAY_ORDER_ERROR); + } + + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "FAIL"); + resultMap.put("return_msg", "FAILED"); + return XmlUtil.getRequestXml(resultMap); + } + + + @Override + public PageInfo listAsPage(WxSubsidy record, Integer pageIndex, Integer pageSize) { + return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxSubsidyMapper.findList(record)); + } + + @Override + public WxSubsidy getById(Long id) { + return wxSubsidyMapper.selectByPrimaryKey(id); + } + + @Override + public void saveOrUpdate(WxSubsidy record) { + if (record.getId() == null) { + //record.setId(UUID.randomUUID().toString().replaceAll("-", "")); + final IdWorker idWorker = IdWorker.get(); + record.setId(idWorker.nextId()); + wxSubsidyMapper.insertSelective(record); + } else { + wxSubsidyMapper.updateByPrimaryKeySelective(record); + } + } + + @Override + public void deleteById(Long id) { + wxSubsidyMapper.deleteByPrimaryKey(id); + } + + + + + + + + +} diff --git a/mallinkService/src/main/resources/mapper/WxSubsidyMapper.xml b/mallinkService/src/main/resources/mapper/WxSubsidyMapper.xml new file mode 100644 index 000000000..dcd877eb8 --- /dev/null +++ b/mallinkService/src/main/resources/mapper/WxSubsidyMapper.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + `id`,`tenant_id`,`operator_user_id`,`create_time`,`update_time`,`order_no`,`body`,`total_fee`,`ip`,`status`, + `pay_time_start`,`pay_time_end`,`prepay_id`,`code_url`,`transaction_id`,`amount`,`share_amount`,`share_remain_amount`,`fail_reason`,`open_id` + + + + where 1 = 1 + + and `id` = #{id} + + + and `tenant_id` = #{tenantId} + + + and `create_time` = #{createTime} + + + and `update_time` = #{updateTime} + + + and `order_no` like concat('%', #{orderNo},'%') + + + and `body` like concat('%', #{body},'%') + + + and `ip` like concat('%', #{ip},'%') + + + and `status` = #{status} + + + and `pay_time_start` = #{payTimeStart} + + + and `pay_time_end` = #{payTimeEnd} + + + and `prepay_id` like concat('%', #{prepayId},'%') + + + and `code_url` like concat('%', #{codeUrl},'%') + + + and `transaction_id` like concat('%', #{transactionId},'%') + + + and `amount` = #{amount} + + + and `share_amount` = #{shareAmount} + + + and `share_remain_amount` = #{shareRemainAmount} + + + and `fail_reason` like concat('%', #{failReason},'%') + + + and id in + + #{idItem} + + + order by ${sortColumns} + + + + + + + + + +