ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/factory/AppUserVipDetailFallbackFactory.java
New file @@ -0,0 +1,33 @@ package com.ruoyi.account.api.factory; import com.ruoyi.account.api.feignClient.AppUserVipDetailClient; import com.ruoyi.account.api.model.TAppUserVipDetail; import com.ruoyi.account.api.vo.GetAppUserVipDetail; import com.ruoyi.common.core.domain.R; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.openfeign.FallbackFactory; import org.springframework.stereotype.Component; /** * * @author ruoyi */ @Component public class AppUserVipDetailFallbackFactory implements FallbackFactory<AppUserVipDetailClient> { private static final Logger log = LoggerFactory.getLogger(AppUserVipDetailFallbackFactory.class); @Override public AppUserVipDetailClient create(Throwable throwable) { log.error("用户会员明细调用失败:{}", throwable.getMessage()); return new AppUserVipDetailClient() { @Override public R<TAppUserVipDetail> getAppUserVipDetail(GetAppUserVipDetail getAppUserVipDetail) { return R.fail("获取用户当前有效的VIP明细调用失败:" + throwable.getMessage()); } }; } } ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/feignClient/AppUserVipDetailClient.java
New file @@ -0,0 +1,27 @@ package com.ruoyi.account.api.feignClient; import com.ruoyi.account.api.factory.AppUserVipDetailFallbackFactory; import com.ruoyi.account.api.model.TAppUserVipDetail; import com.ruoyi.account.api.vo.GetAppUserVipDetail; import com.ruoyi.common.core.constant.ServiceNameConstants; import com.ruoyi.common.core.domain.R; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; /** * @author zhibing.pu * @Date 2024/8/21 10:27 */ @FeignClient(contextId = "AppUserVipDetailClient", value = ServiceNameConstants.ACCOUNT_SERVICE, fallbackFactory = AppUserVipDetailFallbackFactory.class) public interface AppUserVipDetailClient { /** * 获取用户当前有效的VIP明细 * @param getAppUserVipDetail * @return */ @PostMapping("/appUserVipDetail/getAppUserVipDetail") R<TAppUserVipDetail> getAppUserVipDetail(GetAppUserVipDetail getAppUserVipDetail); } ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TAppUserVipDetail.java
@@ -39,9 +39,11 @@ @TableField("charge_num") private Integer chargeNum; @ApiModelProperty(value = "折扣") @TableField("discount") private BigDecimal discount; @ApiModelProperty(value = "购买时折扣金额") @ApiModelProperty(value = "最高优惠金额") @TableField("discount_money") private BigDecimal discountMoney; ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/vo/GetAppUserVipDetail.java
New file @@ -0,0 +1,19 @@ package com.ruoyi.account.api.vo; import lombok.Data; /** * @author zhibing.pu * @Date 2024/8/21 10:30 */ @Data public class GetAppUserVipDetail { /** * 用户id */ private Long appUserId; /** * vipid */ private Integer vipId; } ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/ChargingPileClient.java
@@ -7,6 +7,7 @@ import com.ruoyi.common.core.domain.R; import io.swagger.annotations.ApiOperation; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -37,4 +38,8 @@ @PostMapping("/site/getSiteInfoByNumber") @ApiOperation(value = "扫一扫后通过桩编号获取电站信息", tags = {"小程序-扫一扫"}) R<SiteInfoVO> getSiteInfoByNumber(@RequestParam("number") String number); @PostMapping("/t-charging-pile/getChargingPileById/{id}") R<TChargingPile> getChargingPileById(@PathVariable("id") Integer id); } ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteInfoVO.java
@@ -14,6 +14,8 @@ private String name; @ApiModelProperty(value = "桩编号") private String number; @ApiModelProperty(value = "充电枪id") private Integer chargingGunId; @ApiModelProperty(value = "普通电价") private BigDecimal electrovalence; @ApiModelProperty(value = "会员电价") ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/ChargingOrderFallbackFactory.java
File was deleted ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/WxPaymentFallbackFactory.java
New file @@ -0,0 +1,51 @@ package com.ruoyi.payment.api.factory; import com.ruoyi.common.core.domain.R; import com.ruoyi.payment.api.feignClient.WxPaymentClient; import com.ruoyi.payment.api.vo.NotifyV3PayDecodeRespBody; import com.ruoyi.payment.api.vo.PaymentOrder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.openfeign.FallbackFactory; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.util.Map; /** * 充电订单服务降级处理 * * @author ruoyi */ @Component public class WxPaymentFallbackFactory implements FallbackFactory<WxPaymentClient> { private static final Logger log = LoggerFactory.getLogger(WxPaymentFallbackFactory.class); @Override public WxPaymentClient create(Throwable throwable) { log.error("微信支付调用失败:{}", throwable.getMessage()); return new WxPaymentClient() { @Override public R<NotifyV3PayDecodeRespBody> queryOrderInfo(String orderId) { return R.fail("查询支付订单信息失败:" + throwable.getMessage()); } @Override public R<Map<String, Object>> orderPay(PaymentOrder paymentOrder) { throw new RuntimeException("调起微信支付失败:" + throwable.getMessage()); } @Override public R<Map<String, Object>> payNotify(HttpServletRequest request) { return R.fail("微信支付回调失败:" + throwable.getMessage()); } @Override public void ack() { } }; } } ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/feignClient/ChargingOrderClient.java
File was deleted ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/feignClient/WxPaymentClient.java
New file @@ -0,0 +1,62 @@ package com.ruoyi.payment.api.feignClient; import com.ruoyi.common.core.constant.ServiceNameConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.payment.api.factory.WxPaymentFallbackFactory; import com.ruoyi.payment.api.vo.NotifyV3PayDecodeRespBody; import com.ruoyi.payment.api.vo.PaymentOrder; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import javax.servlet.http.HttpServletRequest; import java.util.Map; /** * 充电订单服务 * @author ruoyi */ @FeignClient(contextId = "WxPaymentClient", value = ServiceNameConstants.PAYMENT_SERVICE, fallbackFactory = WxPaymentFallbackFactory.class) public interface WxPaymentClient { /** * 查询支付订单信息 * @param orderId * @return */ @PostMapping("/wx/query/queryOrderInfo") R<NotifyV3PayDecodeRespBody> queryOrderInfo(String orderId); /** * 订单支付 * @param paymentOrder * @return */ @PostMapping("/wx/orderPay") R<Map<String, Object>> orderPay(@RequestBody PaymentOrder paymentOrder); /** * 支付回调 * @param request * @return */ @PostMapping("/wx/pay/notify") R<Map<String, Object>> payNotify(HttpServletRequest request); /** * 支付回调成功后的成功应答 */ @PostMapping("/wx/pay/ack") void ack(); /** * 关闭订单 * @param outTradeNo */ @PostMapping("/wx/pay/close") void close(String outTradeNo); } ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/NotifyV3PayDecodeRespBody.java
New file @@ -0,0 +1,222 @@ package com.ruoyi.payment.api.vo; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; /** * @author xiaochen * @ClassName FacilV3PayNotifyRespBody * @Description */ @Builder @NoArgsConstructor @AllArgsConstructor @Data public class NotifyV3PayDecodeRespBody implements Serializable { // 合单--开始 private String combine_appid; private String combine_mchid; private String combine_out_trade_no; private List<SubOrders> sub_orders; // 合单--结束 /** * 服务商应用ID */ private String sp_appid; /** * 服务商户号 */ private String sp_mchid; /** * 商户号 */ private String mchid; /** * 子商户应用ID */ private String sub_appid; /** * 子商户号 */ private String sub_mchid; /** * 商户订单号 */ private String out_trade_no; /** * 交易状态描述 */ private String trade_state_desc; /** * 交易类型,枚举值: * JSAPI:公众号支付 * NATIVE:扫码支付 * APP:APP支付 * MICROPAY:付款码支付 * MWEB:H5支付 * FACEPAY:刷脸支付 */ private String trade_type; /** * 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用 */ private String attach; /** * 微信支付订单号 */ private String transaction_id; /** * 交易状态,枚举值: * SUCCESS:支付成功 * REFUND:转入退款 * NOTPAY:未支付 * CLOSED:已关闭 * REVOKED:已撤销(付款码支付) * USERPAYING:用户支付中(付款码支付) * PAYERROR:支付失败(其他原因,如银行返回失败) */ private String trade_state; /** * 银行类型,采用字符串类型的银行标识。银行标识请参考《银行类型对照表》 * https://pay.weixin.qq.com/wiki/doc/apiv3_partner/terms_definition/chapter1_1_3.shtml#part-6 */ private String bank_type; /** * 支付完成时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE, * YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒, * TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。 * 例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。 * 示例值:2018-06-08T10:34:56+08:00 */ private String success_time; /** * 支付者信息 */ private Payer payer; /** * 支付者 */ private Payer combine_payer_info; /** * 订单金额信息 */ private Amount amount; /** * 场景信息 */ private SceneInfo scene_info; /** * 优惠功能,享受优惠时返回该字段 */ private List<PromotionDetail> promotion_detail; @Builder @NoArgsConstructor @AllArgsConstructor @Data public static class Amount implements Serializable{ /** * 用户支付金额 */ private int payer_total; /** * 总金额 */ private int total; /** * 标价金额 */ private int total_amount; /** * 现金支付金额 */ private int payer_amount; private String currency; private String payer_currency; } @Builder @NoArgsConstructor @AllArgsConstructor @Data public static class GoodsDetail implements Serializable{ private String goods_id; private int quantity; private int unit_price; private int discount_amount; private String goods_remark; } @Builder @NoArgsConstructor @AllArgsConstructor @Data public static class Payer implements Serializable{ private String openid; private String sp_openid; private String sub_openid; } @Builder @NoArgsConstructor @AllArgsConstructor @Data public static class PromotionDetail implements Serializable{ private String coupon_id; private String name; private String scope; private String type; private int amount; private String stock_id; private int wechatpay_contribute; private int merchant_contribute; private int other_contribute; private String currency; private List<GoodsDetail> goods_detail; } @Builder @NoArgsConstructor @AllArgsConstructor @Data public static class SceneInfo implements Serializable{ /** * 商户端设备号 */ private String device_id; } @Builder @NoArgsConstructor @AllArgsConstructor @Data public static class SubOrders implements Serializable{ private String mchid; private String trade_type; private String trade_state; private String trade_state_desc; private String bank_type; private String attach; private String success_time; private String transaction_id; private String out_trade_no; private String sub_mchid; private Amount amount; /** * 优惠功能,享受优惠时返回该字段 */ private List<PromotionDetail> promotion_detail; } } ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/PaymentOrder.java
New file @@ -0,0 +1,33 @@ package com.ruoyi.payment.api.vo; import lombok.Data; import java.math.BigDecimal; /** * @author zhibing.pu * @Date 2024/8/21 9:06 */ @Data public class PaymentOrder { /** * 订单流水号 */ private String code; /** * 支付金额 */ private BigDecimal amount; /** * openid */ private String openId; /** * 描述 */ private String description; /** * 回调地址 */ private String notifyUrl; } ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppCouponController.java
@@ -7,6 +7,9 @@ import com.ruoyi.account.api.model.TAppCoupon; import com.ruoyi.account.api.model.TAppUserCar; import com.ruoyi.account.api.query.ExchangeRecordGoodsQuery; import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient; import com.ruoyi.chargingPile.api.model.TChargingGun; import com.ruoyi.chargingPile.api.model.TChargingPile; import com.ruoyi.other.api.vo.CouponListVOVO; import com.ruoyi.account.api.vo.ExchangeRecordVO; import com.ruoyi.account.service.TAppCouponService; @@ -26,6 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; @@ -54,6 +58,11 @@ private ChargingPileClient chargingPileClient; @Autowired private ChargingOrderClient chargingOrderClient; @Resource private ChargingGunClient chargingGunClient; /** * 小程序扫一扫 添加车辆 * @param dto @@ -70,10 +79,13 @@ * 查询用户可用优惠券数量 * @return */ @ApiOperation(value = "通过桩编号和预付金额获取电站详情", tags = {"小程序-扫一扫"}) @ApiOperation(value = "通过充电枪id和预付金额获取电站详情", tags = {"小程序-扫一扫"}) @GetMapping(value = "/scan/siteInfo") public AjaxResult<SiteInfoVO> siteInfo(String number,BigDecimal money) { SiteInfoVO data = chargingPileClient.getSiteInfoByNumber(number).getData(); public AjaxResult<SiteInfoVO> siteInfo(Integer id, BigDecimal money) { TChargingGun chargingGun = chargingGunClient.getChargingGunById(id).getData(); TChargingPile chargingPile = chargingPileClient.getChargingPileById(chargingGun.getChargingPileId()).getData(); SiteInfoVO data = chargingPileClient.getSiteInfoByNumber(chargingPile.getNumber().toString()).getData(); data.setChargingGunId(id); List<TAppUserCar> cars = appUserCarService.list(new QueryWrapper<TAppUserCar>() .eq("app_user_id",tokenService.getLoginUserApplet().getUserId()) .orderByDesc("create_time")); ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserVipDetailController.java
New file @@ -0,0 +1,41 @@ package com.ruoyi.account.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.account.api.model.TAppUserVipDetail; import com.ruoyi.account.api.vo.GetAppUserVipDetail; import com.ruoyi.account.service.TAppUserVipDetailService; import com.ruoyi.common.core.domain.R; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @author zhibing.pu * @Date 2024/8/21 10:35 */ @RestController @RequestMapping("/appUserVipDetail") public class TAppUserVipDetailController { @Resource private TAppUserVipDetailService appUserVipDetailService; /** * 获取用户当前有效的vip明细 * @param getAppUserVipDetail * @return */ @PostMapping("/getAppUserVipDetail") public R<TAppUserVipDetail> getAppUserVipDetail(@RequestBody GetAppUserVipDetail getAppUserVipDetail){ TAppUserVipDetail one = appUserVipDetailService.getOne(new LambdaQueryWrapper<TAppUserVipDetail>() .eq(TAppUserVipDetail::getAppUserId, getAppUserVipDetail.getAppUserId()) .eq(TAppUserVipDetail::getVipId, getAppUserVipDetail.getVipId()) .last(" and now() between start_time and end_time")); return R.ok(one); } } ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java
@@ -162,5 +162,18 @@ PageInfo<ChargingGunMonitoring> chargingGunMonitoring = chargingPileService.getChargingGunMonitoring(query); return AjaxResult.success(chargingGunMonitoring); } /** * 根据id获取充电桩信息 * @param id * @return */ @ResponseBody @PostMapping("/getChargingPileById/{id}") public R<TChargingPile> getChargingPileById(@PathVariable Integer id){ TChargingPile chargingPile = chargingPileService.getById(id); return R.ok(chargingPile); } } ruoyi-service/ruoyi-order/pom.xml
@@ -33,6 +33,10 @@ <groupId>com.ruoyi</groupId> <artifactId>ruoyi-api-chargingPile</artifactId> </dependency> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-api-payment</artifactId> </dependency> <!-- SpringCloud Alibaba Nacos --> ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.chargingPile.api.vo.SiteVO; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.page.BasePage; @@ -17,15 +18,21 @@ import com.ruoyi.order.dto.MyChargingOrderInfo; import com.ruoyi.order.dto.MyChargingOrderList; import com.ruoyi.order.dto.OrderEvaluateVo; import com.ruoyi.order.dto.*; import com.ruoyi.order.service.TChargingOrderService; import com.ruoyi.order.service.TOrderEvaluateService; import com.ruoyi.order.service.TOrderEvaluateTagService; import com.ruoyi.payment.api.feignClient.WxPaymentClient; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import org.springframework.beans.factory.annotation.Autowired; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.List; import java.util.Map; import java.util.List; @@ -51,6 +58,15 @@ private TOrderEvaluateService orderEvaluateService; @Autowired private TOrderEvaluateTagService orderEvaluateTagService; @Resource private WxPaymentClient wxPaymentClient; @Resource private RedisService redisService; @ResponseBody @PostMapping(value = "/chargingOrder") @@ -150,10 +166,96 @@ @ResponseBody @GetMapping(value = "/getNoInvoicedOrder") @ApiOperation(value = "获取未开票的订单数据", tags = {"小程序-充电发票"}) public AjaxResult<List<MyChargingOrderList>> getNoInvoicedOrder(@RequestBody GetNoInvoicedOrder query){ public AjaxResult<List<MyChargingOrderList>> getNoInvoicedOrder(GetNoInvoicedOrder query){ List<MyChargingOrderList> list = chargingOrderService.getNoInvoicedOrder(query); return AjaxResult.success(list); } @ResponseBody @PostMapping(value = "/paymentChargingOrder") @ApiOperation(value = "支付充电充值费用", tags = {"小程序-扫一扫"}) public AjaxResult paymentChargingOrder(AddChargingOrder addChargingOrder){ return chargingOrderService.paymentChargingOrder(addChargingOrder); } /** * 充电充值支付回调 * @param request */ @ResponseBody @PostMapping(value = "/chargingOrderWXCallback") public void chargingOrderWXCallback(HttpServletRequest request){ Map<String, Object> data = wxPaymentClient.payNotify(request).getData(); if(null != data){ String out_trade_no = data.get("out_trade_no").toString(); String transaction_id = data.get("transaction_id").toString(); String attach = data.get("attach").toString(); AjaxResult ajaxResult = chargingOrderService.chargingOrderCallback(1, out_trade_no, transaction_id, attach); if(ajaxResult.isSuccess()){ wxPaymentClient.ack(); } } } /** * 支付宝支付成功后的回调 * @param request */ @ResponseBody @PostMapping(value = "/chargingOrderALICallback") public void chargingOrderALICallback(HttpServletRequest request){ Map<String, Object> data = wxPaymentClient.payNotify(request).getData(); if(null != data){ String out_trade_no = data.get("out_trade_no").toString(); String transaction_id = data.get("transaction_id").toString(); String attach = data.get("attach").toString(); AjaxResult ajaxResult = chargingOrderService.chargingOrderCallback(2, out_trade_no, transaction_id, attach); if(ajaxResult.isSuccess()){ } } } @ResponseBody @GetMapping(value = "/preChargeCheck/{id}") @ApiOperation(value = "获取安全检测数据", tags = {"小程序-扫一扫"}) @ApiImplicitParams({ @ApiImplicitParam(name = "id", value = "充电枪id", required = true) }) public AjaxResult<PreChargeCheck> preChargeCheck(@PathVariable Integer id){ String key = "AQJC_" + id; Object cacheObject = redisService.getCacheObject(key); return AjaxResult.success(cacheObject); } @ResponseBody @GetMapping(value = "/getChargingDetails/{id}") @ApiOperation(value = "获取充电中页面数据", tags = {"小程序-扫一扫"}) @ApiImplicitParams({ @ApiImplicitParam(name = "id", value = "充电枪id", required = true) }) public AjaxResult<ChargingDetails> getChargingDetails(@PathVariable Integer id){ ChargingDetails chargingDetails = chargingOrderService.getChargingDetails(id); return AjaxResult.success(chargingDetails); } @ResponseBody @PutMapping(value = "/stopCharging/{id}") @ApiOperation(value = "手动停止充电", tags = {"小程序-扫一扫"}) @ApiImplicitParams({ @ApiImplicitParam(name = "id", value = "订单id", required = true) }) public AjaxResult stopCharging(@PathVariable String id){ return chargingOrderService.stopCharging(id); } } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TExchangeOrderController.java
@@ -1,4 +1,5 @@ package com.ruoyi.order.controller; import java.text.SimpleDateFormat; import java.time.LocalDateTime; @@ -27,6 +28,7 @@ import javax.annotation.Resource; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -158,7 +160,9 @@ @PostMapping("/create") public R<Long> exchangeCreate(@RequestBody ExchangeDto exchangeDto){ TExchangeOrder tExchangeOrder = new TExchangeOrder(); tExchangeOrder.setCode(""); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); String code = "DH" + Math.random() * 1000 + sdf.format(new Date()); tExchangeOrder.setCode(code); tExchangeOrder.setAppUserId(exchangeDto.getUserId()); tExchangeOrder.setOrderType(0); tExchangeOrder.setGoodsId(0); ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/AddChargingOrder.java
New file @@ -0,0 +1,26 @@ package com.ruoyi.order.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; /** * @author zhibing.pu * @Date 2024/8/20 13:54 */ @Data @ApiModel public class AddChargingOrder { @ApiModelProperty("充电枪id") public Integer id; @ApiModelProperty("支付金额") private BigDecimal paymentAmount; @ApiModelProperty("优惠券id") private Long appUserCouponId; @ApiModelProperty("车辆id") private Long appUserCarId; @ApiModelProperty("支付方式(1=微信,2=支付宝)") private Integer paymentType; } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/ChargingDetails.java
New file @@ -0,0 +1,42 @@ package com.ruoyi.order.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; /** * @author zhibing.pu * @Date 2024/8/21 14:09 */ @Data @ApiModel public class ChargingDetails { @ApiModelProperty("订单id") private String id; @ApiModelProperty("充电电流") private BigDecimal chargeCurrent; @ApiModelProperty("充电电压") private BigDecimal ChargeVoltage; @ApiModelProperty("充电功率") private BigDecimal ChargePower; @ApiModelProperty("完成比例") private Integer completionRatio; @ApiModelProperty("续航") private BigDecimal endurance; @ApiModelProperty("剩余充电时间") private Long remainingChargeTime; @ApiModelProperty("充电枪名") private String name; @ApiModelProperty("订单编号") private String code; @ApiModelProperty("已充电度数") private BigDecimal chargedDegrees; @ApiModelProperty("已充电时间") private Long chargedTime; @ApiModelProperty("充电费用") private BigDecimal ChargingCost; @ApiModelProperty("充电状态(0=未知,1=等待中,2=启动中,3=充电中,4=停止中,5=已结束)") private Integer status; } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyChargingOrderList.java
@@ -21,6 +21,8 @@ private String title; @ApiModelProperty("充电度数") private BigDecimal chargingDegree; @ApiModelProperty("充电枪id") private Integer chargingGunId; @ApiModelProperty("充电桩枪名称") private String name; @ApiModelProperty("结束方式(0=异常终止,1=主动终止,2=满电终止,3=费用不足终止)") ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/PreChargeCheck.java
New file @@ -0,0 +1,20 @@ package com.ruoyi.order.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * @author zhibing.pu * @Date 2024/8/21 13:47 */ @Data @ApiModel public class PreChargeCheck { @ApiModelProperty("安全连接检测") private Boolean secureConnectionDetection; @ApiModelProperty("绝缘检测") private Boolean insulationTesting; @ApiModelProperty("电子锁锁止") private Boolean electronicLockLock; } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TChargingOrderService.java
@@ -1,12 +1,10 @@ package com.ruoyi.order.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.page.BasePage; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.dto.GetMyChargingOrderList; import com.ruoyi.order.dto.GetNoInvoicedOrder; import com.ruoyi.order.dto.MyChargingOrderInfo; import com.ruoyi.order.dto.MyChargingOrderList; import com.ruoyi.order.dto.*; import org.springframework.web.bind.annotation.RequestBody; import java.util.List; @@ -45,4 +43,39 @@ * @return */ List<MyChargingOrderList> getNoInvoicedOrder(GetNoInvoicedOrder query); /** * 充电支付 * @param addChargingOrder * @return */ AjaxResult paymentChargingOrder(AddChargingOrder addChargingOrder); /** * 支付成功后的回调处理逻辑 * @param paymentType 支付方式:1=微信,2=支付宝 * @param out_trade_no 业务流水号 * @param transaction_id 三方支付流水号 * @param attach 附加数据 * @return */ AjaxResult chargingOrderCallback(Integer paymentType, String out_trade_no, String transaction_id, String attach); /** * 获取充电中的详情 * @param id * @return */ ChargingDetails getChargingDetails(Integer id); /** * 停止充电 * @param id * @return */ AjaxResult stopCharging(String id); } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -3,24 +3,33 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.account.api.feignClient.AppUserCarClient; import com.ruoyi.account.api.feignClient.AppUserClient; import com.ruoyi.account.api.feignClient.AppUserVipDetailClient; import com.ruoyi.account.api.model.TAppUser; import com.ruoyi.account.api.model.TAppUserCar; import com.ruoyi.account.api.model.TAppUserVipDetail; import com.ruoyi.account.api.vo.GetAppUserVipDetail; import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient; import com.ruoyi.chargingPile.api.feignClient.ChargingPileClient; import com.ruoyi.chargingPile.api.feignClient.SiteClient; import com.ruoyi.chargingPile.api.model.Site; import com.ruoyi.chargingPile.api.model.TChargingGun; import com.ruoyi.chargingPile.api.model.TChargingPile; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.page.BasePage; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TChargingOrderAccountingStrategy; import com.ruoyi.order.dto.GetMyChargingOrderList; import com.ruoyi.order.dto.GetNoInvoicedOrder; import com.ruoyi.order.dto.MyChargingOrderInfo; import com.ruoyi.order.dto.MyChargingOrderList; import com.ruoyi.order.dto.*; import com.ruoyi.order.mapper.TChargingOrderMapper; import com.ruoyi.order.service.TChargingOrderAccountingStrategyService; import com.ruoyi.order.service.TChargingOrderService; import com.ruoyi.payment.api.feignClient.WxPaymentClient; import com.ruoyi.payment.api.vo.NotifyV3PayDecodeRespBody; import com.ruoyi.payment.api.vo.PaymentOrder; import io.seata.spring.annotation.GlobalTransactional; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -29,6 +38,7 @@ import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; /** * <p> @@ -56,6 +66,21 @@ @Resource private TokenService tokenService; @Resource private WxPaymentClient wxPaymentClient; @Resource private ChargingPileClient chargingPileClient; @Resource private AppUserClient appUserClient; @Resource private AppUserVipDetailClient appUserVipDetailClient; @Resource private RedisService redisService; @@ -80,6 +105,7 @@ myChargingOrderList.setTitle(site.getName()); myChargingOrderList.setChargingDegree(tChargingOrder.getChargingCapacity()); String name = chargingGunClient.getAllName(tChargingOrder.getChargingGunId()).getData(); myChargingOrderList.setChargingGunId(tChargingOrder.getChargingGunId()); myChargingOrderList.setName(name); myChargingOrderList.setEndMode(tChargingOrder.getEndMode()); BigDecimal payMoney = tChargingOrder.getStatus() < 4 ? tChargingOrder.getRechargeAmount() : tChargingOrder.getPaymentAmount(); @@ -167,4 +193,197 @@ } return list; } /** * 充电支付 * @param addChargingOrder * @return */ @Override @GlobalTransactional(rollbackFor = Exception.class) public AjaxResult paymentChargingOrder(AddChargingOrder addChargingOrder) { Long userId = tokenService.getLoginUserApplet().getUserId(); TAppUser appUser = appUserClient.getUserById(userId).getData(); //查询待支付状态的订单,没有支付则删除订单 List<TChargingOrder> list = this.list(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getAppUserId, userId) .eq(TChargingOrder::getRechargePaymentStatus, 1).eq(TChargingOrder::getDelFlag, 0)); for (TChargingOrder tChargingOrder : list) { Integer rechargePaymentType = tChargingOrder.getRechargePaymentType(); if(1 == rechargePaymentType){ NotifyV3PayDecodeRespBody data = wxPaymentClient.queryOrderInfo(tChargingOrder.getCode()).getData(); if(null != data){ String trade_state = data.getTrade_state(); //支付失败,删除无效的订单 if(trade_state.equals("REFUND") || trade_state.equals("NOTPAY") || trade_state.equals("REVOKED") || trade_state.equals("PAYERROR")){ this.removeById(tChargingOrder.getId()); } } } if(2 == rechargePaymentType){ } } //检查当前枪是否是正在使用中 TChargingOrder one = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getChargingGunId, addChargingOrder.getId()) .in(TChargingOrder::getStatus, Arrays.asList(1, 2, 3)).eq(TChargingOrder::getDelFlag, 0)); if(null != one){ return AjaxResult.error("充电枪正在充电桩中,启动失败"); } //查询当前充电枪是否有正在支付的订单 one = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getChargingGunId, addChargingOrder.getId()) .eq(TChargingOrder::getAppUserCarId, userId).eq(TChargingOrder::getRechargePaymentStatus, 1).eq(TChargingOrder::getDelFlag, 0)); if(null != one){ //查询三方支付数据,支付中直接结束三方订单 if(1 == one.getRechargePaymentType()){ NotifyV3PayDecodeRespBody data = wxPaymentClient.queryOrderInfo(one.getCode()).getData(); if(null != data){ String trade_state = data.getTrade_state(); //支付失败,删除无效的订单 if(trade_state.equals("REFUND") || trade_state.equals("NOTPAY") || trade_state.equals("REVOKED") || trade_state.equals("PAYERROR")){ this.removeById(one.getId()); }else{ //结束第三方支付,删除订单 wxPaymentClient.close(one.getCode()); this.removeById(one.getId()); } } } if(2 == one.getRechargePaymentType()){ } } //构建新的待支付订单 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); TChargingOrder chargingOrder = new TChargingOrder(); String code = "CD" + Math.random() * 1000 + sdf.format(new Date()); chargingOrder.setCode(code); chargingOrder.setOrderType(1); chargingOrder.setOrderClassification(1); chargingOrder.setAppUserId(userId); chargingOrder.setAppUserCarId(addChargingOrder.getAppUserCarId()); TChargingGun tChargingGun = chargingGunClient.getChargingGunById(addChargingOrder.getId()).getData(); chargingOrder.setSiteId(tChargingGun.getSiteId()); chargingOrder.setChargingPileId(tChargingGun.getChargingPileId()); chargingOrder.setChargingGunId(addChargingOrder.getId()); chargingOrder.setRechargePaymentType(addChargingOrder.getPaymentType()); chargingOrder.setRechargePaymentStatus(1); chargingOrder.setRechargeAmount(addChargingOrder.getPaymentAmount()); chargingOrder.setAppCouponId(addChargingOrder.getAppUserCouponId()); if(null != appUser.getVipId()){ GetAppUserVipDetail getAppUserVipDetail = new GetAppUserVipDetail(); getAppUserVipDetail.setAppUserId(appUser.getId()); getAppUserVipDetail.setVipId(appUser.getVipId()); TAppUserVipDetail vipDetail = appUserVipDetailClient.getAppUserVipDetail(getAppUserVipDetail).getData(); if(null != vipDetail){ Integer chargeNum = vipDetail.getChargeNum(); if(0 > chargeNum){ chargingOrder.setVipDiscount(vipDetail.getDiscount()); BigDecimal discountAmount = addChargingOrder.getPaymentAmount().multiply((new BigDecimal(10) .subtract(vipDetail.getDiscount())).divide(new BigDecimal(10))).setScale(4, BigDecimal.ROUND_HALF_EVEN); chargingOrder.setVipDiscountAmount(discountAmount); } } } this.save(chargingOrder); //会员优惠折扣将其计入增加充电时长(增加总充电金额) //如果充电总金额未使用完,则需要退回费用=(原金额/总金额)*(总金额-实际充电金额) if(1 == addChargingOrder.getPaymentType()){ PaymentOrder paymentOrder = new PaymentOrder(); paymentOrder.setCode(chargingOrder.getCode()); paymentOrder.setAmount(addChargingOrder.getPaymentAmount()); paymentOrder.setOpenId(appUser.getWxOpenid()); paymentOrder.setDescription("充电充值"); paymentOrder.setNotifyUrl("/order/t-charging-order/chargingOrderWXCallback"); Map<String, Object> data = wxPaymentClient.orderPay(paymentOrder).getData(); return AjaxResult.success(data); } if(2 == addChargingOrder.getPaymentType()){ } throw new RuntimeException("无效的支付方式"); } /** * 支付成功后的回调处理逻辑 * @param paymentType 支付方式:1=微信,2=支付宝 * @param out_trade_no 业务流水号 * @param transaction_id 三方支付流水号 * @param attach 附加数据 * @return */ @Override public AjaxResult chargingOrderCallback(Integer paymentType, String out_trade_no, String transaction_id, String attach) { TChargingOrder chargingOrder = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getCode, out_trade_no)); if(chargingOrder.getRechargePaymentStatus() == 2){ return AjaxResult.success(); } chargingOrder.setRechargePaymentStatus(2); chargingOrder.setRechargeSerialNumber(transaction_id); this.updateById(chargingOrder); //添加安全检测数据到缓存中,每步安全检测完成后需要更新缓存数据 PreChargeCheck preChargeCheck = new PreChargeCheck(); preChargeCheck.setElectronicLockLock(false); preChargeCheck.setInsulationTesting(false); preChargeCheck.setSecureConnectionDetection(false); String key = "AQJC_" + chargingOrder.getChargingGunId(); redisService.setCacheObject(key, preChargeCheck); //开始检测充电桩状,将检查状态写入缓存。检测完成后开始开启充电 //充电结束后需要计算退款剩余金额 // todo 需要完善 return AjaxResult.success(); } /** * 获取充电中的详情 * @param id * @return */ @Override public ChargingDetails getChargingDetails(Integer id) { Long userId = tokenService.getLoginUserApplet().getUserId(); TChargingOrder one = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getAppUserId, userId).eq(TChargingOrder::getChargingGunId, id) .in(TChargingOrder::getStatus, Arrays.asList(1, 2, 3)).eq(TChargingOrder::getRechargePaymentStatus, 2).eq(TChargingOrder::getDelFlag, 0)); if(null == one){ return null; } // todo 需要完善充电实时数据 ChargingDetails chargingDetails = new ChargingDetails(); chargingDetails.setId(one.getId().toString()); TChargingGun chargingGun = chargingGunClient.getChargingGunById(id).getData(); TChargingPile chargingPile = chargingPileClient.getChargingPileById(chargingGun.getChargingPileId()).getData(); Site site = siteClient.getSiteByIds(Arrays.asList(chargingPile.getSiteId())).getData().get(0); chargingDetails.setName(site.getName() + "-" + chargingPile.getName()); chargingDetails.setCode(one.getCode()); chargingDetails.setStatus(one.getStatus()); return chargingDetails; } /** * 停止充电操作 * @param id 订单id * @return */ @Override public AjaxResult stopCharging(String id) { TChargingOrder chargingOrder = this.getById(id); Integer status = chargingOrder.getStatus(); if(status == 4 || status == 5){ return AjaxResult.error("不能重复操作"); } chargingOrder.setStatus(4); chargingOrder.setEndMode(1); this.updateById(chargingOrder); //调用硬件停止充电,停止成功后开始计算费用退款 // todo 待完善 return AjaxResult.success(); } } ruoyi-service/ruoyi-payment/pom.xml
@@ -112,6 +112,11 @@ <artifactId>joda-time</artifactId> <version>2.10.10</version> </dependency> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-api-payment</artifactId> </dependency> </dependencies> <build> ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/controller/WxPayController.java
@@ -1,9 +1,12 @@ package com.ruoyi.payment.wx.controller; import com.fasterxml.jackson.core.type.TypeReference; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.payment.api.vo.PaymentOrder; import com.ruoyi.payment.wx.enums.RefundEnum; import com.ruoyi.payment.wx.model.WxPaymentRefundModel; import com.ruoyi.payment.wx.resp.NotifyV3PayDecodeRespBody; import com.ruoyi.payment.wx.utils.WxV3Pay; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -13,6 +16,7 @@ import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.math.BigDecimal; import java.util.Map; import java.util.Objects; @@ -32,22 +36,22 @@ /** * 按实际修改 */ @PostMapping("order") @PostMapping("orderPay") @ApiOperation("订单支付") public AjaxResult<Map<String, Object>> orderPay(@RequestParam Long orderId) { public R<Map<String, Object>> orderPay(@RequestBody PaymentOrder paymentOrder) { // 查询订单 // 0元订单不走支付 // 价格 Integer totalPrice = 0; Integer totalPrice = paymentOrder.getAmount().multiply(new BigDecimal(100)).intValue(); // 生成订单号 String orderNo = ""; String orderNo = paymentOrder.getCode(); // 查询用户信息 用户openid String openId = ""; String openId = paymentOrder.getOpenId(); // 订单做修改 // 调用支付方法 Map<String, Object> result = wxV3Pay.jsApi(orderNo, totalPrice, openId,""); Map<String, Object> result = wxV3Pay.jsApi(orderNo, totalPrice, openId, paymentOrder.getNotifyUrl(),paymentOrder.getDescription()); log.info("支付参数:{}", result); return AjaxResult.ok(result); return R.ok(result); } /** @@ -80,31 +84,33 @@ * 支付回调 */ @PostMapping("pay/notify") public void payNotify(HttpServletRequest request) throws IOException { public R<Map<String, Object>> payNotify(HttpServletRequest request) throws Exception { try { Map<String, Object> params = wxV3Pay.verifyNotify(request, new TypeReference<Map<String, Object>>() { }); Map<String, Object> params = wxV3Pay.verifyNotify(request, new TypeReference<Map<String, Object>>() {}); log.info("支付回调:{}", params); // 商户订单号 String tradeNo = params.get("out_trade_no").toString(); // 交易状态 String trade_state = params.get("trade_state").toString(); // 交易状态描述 String trade_state_desc = params.get("trade_state_desc").toString(); // 微信支付订单号 String transaction_id = params.get("transaction_id").toString(); // 支付完成时间 // 时间不对的话,可以调用 WxTimeUtils.toRfc3339Date(success_time)转换一下 String success_time = params.get("success_time").toString(); // 附加数据 Integer attach = Integer.parseInt(params.get("attach").toString()); // TODO 业务处理 return R.ok(params); } catch (Exception e) { log.error("支付回调异常:{}", e, e); wxV3Pay.ack(false, e.getMessage()); return R.fail("回调异常"); } } /** * 支付回调成功后 */ @PostMapping("pay/ack") public void ack(){ try { wxV3Pay.ack(); } catch (IOException e) { throw new RuntimeException(e); } } /** * 退款回调 @@ -139,4 +145,24 @@ } /** * 查询订单信息 * @param orderId * @return */ @PostMapping("query/queryOrderInfo") public R<NotifyV3PayDecodeRespBody> queryOrderInfo(@RequestParam("orderId") String orderId){ NotifyV3PayDecodeRespBody query = wxV3Pay.query(orderId); return R.ok(query); } /** * 关闭订单 * @param outTradeNo */ @PostMapping("pay/close") public void close(@RequestParam("outTradeNo") String outTradeNo){ wxV3Pay.close(outTradeNo); } } ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/model/WxCloseOrderModel.java
New file @@ -0,0 +1,22 @@ package com.ruoyi.payment.wx.model; import lombok.*; import java.util.List; /** * @author xiaochen * @ClassName WxPaymentRefundModel * @Description */ @Builder @AllArgsConstructor @NoArgsConstructor @Getter @Setter @ToString public class WxCloseOrderModel { private String mchid; private String out_trade_no; } ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/utils/WxAbstractPay.java
@@ -2,6 +2,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.ruoyi.common.core.utils.WebUtils; import com.ruoyi.payment.wx.model.WxCloseOrderModel; import com.ruoyi.payment.wx.model.WxPaymentInfoModel; import com.ruoyi.payment.wx.model.WxPaymentRefundModel; import com.ruoyi.payment.wx.resp.NotifyV3PayDecodeRespBody; @@ -210,7 +211,7 @@ * @param mchid * @return */ public abstract NotifyV3PayDecodeRespBody query(String out_trade_no, String mchid); public abstract NotifyV3PayDecodeRespBody query(String out_trade_no); /** @@ -220,6 +221,10 @@ * @return */ public abstract Map<String, Object> refund(WxPaymentRefundModel refundModel); public abstract String close(String out_trade_no); /** * 订单退款 @@ -330,4 +335,29 @@ } } /** * 关闭订单 * @param httpClient * @param uri * @param httpReadTimeoutMs * @param httpConnectTimeoutMs * @param closeModel * @return */ public String close(CloseableHttpClient httpClient, String uri, int httpReadTimeoutMs, int httpConnectTimeoutMs, WxCloseOrderModel closeModel) { String reqBody = WxJsonUtils.toJsonString(closeModel); //请求URL HttpEntityEnclosingRequestBase httpPost = requestPost( uri , httpReadTimeoutMs , httpConnectTimeoutMs, reqBody); String repBody = result(httpClient, httpPost); return repBody; } } ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/wx/utils/WxV3Pay.java
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.ruoyi.payment.wx.model.WeixinProperties; import com.ruoyi.payment.wx.model.WxCloseOrderModel; import com.ruoyi.payment.wx.model.WxPaymentInfoModel; import com.ruoyi.payment.wx.model.WxPaymentRefundModel; import com.ruoyi.payment.wx.resp.NotifyV3PayDecodeRespBody; @@ -120,12 +121,13 @@ * @author xiaochen * @date 2022-03-22 12:47 */ public Map<String, Object> jsApi(String tradeNo, Integer amount, String openid, String description) { public Map<String, Object> jsApi(String tradeNo, Integer amount, String openid, String notify_url, String description) { WxPaymentInfoModel requestBody = WxPaymentInfoModel.builder() .mchid(this.config.getMchId()) .appid(this.config.getAppId()) .description(description) .out_trade_no(tradeNo) .notify_url(notify_url) // .attach("") .amount(WxPaymentInfoModel.Amount.builder().total(amount).build()) .payer(WxPaymentInfoModel.Payer.builder().openid(openid).build()) @@ -169,15 +171,14 @@ * 订单查询 * * @param out_trade_no * @param mchid * @return com.abl.biz.center.payment.wx.v3.NotifyV3PayDecodeRespBody * @author xiaochen * @date 2021-12-20 16:47 */ @Override public NotifyV3PayDecodeRespBody query(String out_trade_no, String mchid) { public NotifyV3PayDecodeRespBody query(String out_trade_no) { String url = String.format("/v3/pay/transactions/out-trade-no/%s", out_trade_no) + String.format("?mchid=%s", mchid); String.format("/v3/pay/transactions/out-trade-no/%s", out_trade_no) + String.format("?mchid=%s", this.getConfig().getMchId()); return query(this.httpClient, this.config.getHttpReadTimeoutMs(), this.config.getHttpConnectTimeoutMs(), url); } @@ -194,4 +195,17 @@ return refund(this.httpClient, "/v3/refund/domestic/refunds", this.config.getHttpReadTimeoutMs(), this.config.getHttpConnectTimeoutMs(), refundModel); } /** * 关闭订单 * @param out_trade_no * @return */ @Override public String close(String out_trade_no) { String uri = String.format("/v3/pay/transactions/out-trade-no/%s/close", out_trade_no); WxCloseOrderModel wxCloseOrderModel = new WxCloseOrderModel(); wxCloseOrderModel.setMchid(this.config.getMchId()); return close(this.httpClient, uri, this.config.getHttpReadTimeoutMs(), this.config.getHttpConnectTimeoutMs(), wxCloseOrderModel); } }