| @@ -37,6 +37,12 @@ | |||
| <artifactId>commons-fileupload</artifactId> | |||
| <version>1.3.3</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.google.zxing</groupId> | |||
| <artifactId>core</artifactId> | |||
| <version>3.3.3</version> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| @@ -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<String, String> 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); | |||
| } | |||
| } | |||
| } | |||
| @@ -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<String, String>)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<WxSubsidy> 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)); | |||
| } | |||
| } | |||
| @@ -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<EncodeHintType, Object> 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; | |||
| } | |||
| } | |||
| @@ -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<Long> 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<Field> 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)); | |||
| } | |||
| } | |||
| } | |||
| @@ -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<WxSubsidy, Long> { | |||
| List<WxSubsidy> findList(WxSubsidy wxSubsidy); | |||
| } | |||
| @@ -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('\''); | |||
| @@ -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('\''); | |||
| @@ -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(); | |||
| } | |||
| } | |||
| @@ -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(); | |||
| } | |||
| } | |||
| @@ -33,6 +33,12 @@ public interface WxAppinfoService { | |||
| * @return | |||
| */ | |||
| WxAppinfo getByAppId(String appId); | |||
| /** | |||
| * 获取c端小程序信息 | |||
| * @return | |||
| */ | |||
| WxAppinfo getCAppInfo(String tenantId); | |||
| /** | |||
| * 保存或更新实体 | |||
| @@ -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<WxSubsidy> 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<String, String> paramMap, EnumPayWay payWay); | |||
| } | |||
| @@ -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<WxAppinfo> appList = wxAppinfoMapper.select(appinfoQ); | |||
| if (appList.size() > 0) { | |||
| appInfo = appList.get(0); | |||
| } | |||
| return appInfo; | |||
| } | |||
| @Override | |||
| public WxAppinfo getByAppId(String appId) { | |||
| return wxAppinfoMapper.findByAppId(appId); | |||
| @@ -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<WxAppinfo> 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()); | |||
| @@ -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) { | |||
| // 前端支付取消, | |||
| @@ -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<String, String> 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<String, String> 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<String, String> retMap = new HashMap<String, String>(); | |||
| 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<String, String> 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<WxSubsidy> 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); | |||
| } | |||
| } | |||
| @@ -0,0 +1,103 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||
| <mapper namespace="com.iformall.mapper.WxSubsidyMapper"> | |||
| <resultMap id="BaseResultMap" type="com.iformall.domain.po.WxSubsidy"> | |||
| <id column="id" jdbcType="BIGINT" property="id" /> | |||
| <result column="tenant_id" jdbcType="VARCHAR" property="tenantId" /> | |||
| <result column="operator_user_id" jdbcType="VARCHAR" property="operatorUserId" /> | |||
| <result column="create_time" jdbcType="TIMESTAMP" property="createTime" /> | |||
| <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" /> | |||
| <result column="order_no" jdbcType="VARCHAR" property="orderNo" /> | |||
| <result column="body" jdbcType="VARCHAR" property="body" /> | |||
| <result column="ip" jdbcType="VARCHAR" property="ip" /> | |||
| <result column="status" jdbcType="INTEGER" property="status" /> | |||
| <result column="pay_time_start" jdbcType="TIMESTAMP" property="payTimeStart" /> | |||
| <result column="pay_time_end" jdbcType="TIMESTAMP" property="payTimeEnd" /> | |||
| <result column="prepay_id" jdbcType="VARCHAR" property="prepayId" /> | |||
| <result column="code_url" jdbcType="VARCHAR" property="codeUrl" /> | |||
| <result column="transaction_id" jdbcType="VARCHAR" property="transactionId" /> | |||
| <result column="amount" jdbcType="INTEGER" property="amount" /> | |||
| <result column="share_amount" jdbcType="INTEGER" property="shareAmount" /> | |||
| <result column="share_remain_amount" jdbcType="INTEGER" property="shareRemainAmount" /> | |||
| <result column="fail_reason" jdbcType="VARCHAR" property="failReason" /> | |||
| <result column="open_id" jdbcType="VARCHAR" property="openId" /> | |||
| </resultMap> | |||
| <sql id="allColumns"> | |||
| `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` | |||
| </sql> | |||
| <sql id="dynamicWhereConditions"> | |||
| where 1 = 1 | |||
| <if test=" null != id "> | |||
| and `id` = #{id} | |||
| </if> | |||
| <if test=" null != tenantId "> | |||
| and `tenant_id` = #{tenantId} | |||
| </if> | |||
| <if test=" null != createTime "> | |||
| and `create_time` = #{createTime} | |||
| </if> | |||
| <if test=" null != updateTime "> | |||
| and `update_time` = #{updateTime} | |||
| </if> | |||
| <if test=" null != orderNo "> | |||
| and `order_no` like concat('%', #{orderNo},'%') | |||
| </if> | |||
| <if test=" null != body "> | |||
| and `body` like concat('%', #{body},'%') | |||
| </if> | |||
| <if test=" null != ip "> | |||
| and `ip` like concat('%', #{ip},'%') | |||
| </if> | |||
| <if test=" null != status "> | |||
| and `status` = #{status} | |||
| </if> | |||
| <if test=" null != payTimeStart "> | |||
| and `pay_time_start` = #{payTimeStart} | |||
| </if> | |||
| <if test=" null != payTimeEnd "> | |||
| and `pay_time_end` = #{payTimeEnd} | |||
| </if> | |||
| <if test=" null != prepayId "> | |||
| and `prepay_id` like concat('%', #{prepayId},'%') | |||
| </if> | |||
| <if test=" null != codeUrl "> | |||
| and `code_url` like concat('%', #{codeUrl},'%') | |||
| </if> | |||
| <if test=" null != transactionId "> | |||
| and `transaction_id` like concat('%', #{transactionId},'%') | |||
| </if> | |||
| <if test=" null != amount "> | |||
| and `amount` = #{amount} | |||
| </if> | |||
| <if test=" null != shareAmount "> | |||
| and `share_amount` = #{shareAmount} | |||
| </if> | |||
| <if test=" null != shareRemainAmount "> | |||
| and `share_remain_amount` = #{shareRemainAmount} | |||
| </if> | |||
| <if test=" null != failReason "> | |||
| and `fail_reason` like concat('%', #{failReason},'%') | |||
| </if> | |||
| <if test=" null != ids "> | |||
| and id in | |||
| <foreach collection="ids" index="index" item="idItem" open="(" separator="," close=")"> | |||
| #{idItem} | |||
| </foreach> | |||
| </if> | |||
| <if test=" null != sortColumns"> order by ${sortColumns} </if> | |||
| </sql> | |||
| <select id="findList" parameterType="com.iformall.domain.po.WxSubsidy" resultMap="BaseResultMap"> | |||
| select <include refid="allColumns" /> from wx_subsidy | |||
| <include refid="dynamicWhereConditions" /> | |||
| </select> | |||
| </mapper> | |||