ruoyi-api/ruoyi-api-integration/src/main/java/com/ruoyi/integration/api/factory/ChargingHandshakeFallbackFactory.java
New file @@ -0,0 +1,37 @@ package com.ruoyi.integration.api.factory; import com.ruoyi.common.core.domain.R; import com.ruoyi.integration.api.feignClient.ChargingHandshakeClient; import com.ruoyi.integration.api.feignClient.UploadRealTimeMonitoringDataClient; import com.ruoyi.integration.api.model.ChargingHandshake; import com.ruoyi.integration.api.model.UploadRealTimeMonitoringData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.openfeign.FallbackFactory; import org.springframework.stereotype.Component; import java.util.List; /** * 充电桩服务降级处理 * * @author ruoyi */ @Component public class ChargingHandshakeFallbackFactory implements FallbackFactory<ChargingHandshakeClient> { private static final Logger log = LoggerFactory.getLogger(ChargingHandshakeFallbackFactory.class); @Override public ChargingHandshakeClient create(Throwable throwable) { log.error("调用充电握手数据失败:{}", throwable.getMessage()); return new ChargingHandshakeClient() { @Override public R<ChargingHandshake> getDataByOrderCode(String code) { return R.fail("根据订单号查询充电握手数据失败:" + throwable.getMessage()); } }; } } ruoyi-api/ruoyi-api-integration/src/main/java/com/ruoyi/integration/api/feignClient/ChargingHandshakeClient.java
New file @@ -0,0 +1,26 @@ package com.ruoyi.integration.api.feignClient; import com.ruoyi.common.core.constant.ServiceNameConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.integration.api.factory.ChargingHandshakeFallbackFactory; import com.ruoyi.integration.api.model.ChargingHandshake; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; /** * @author zhibing.pu * @Date 2024/8/28 10:46 */ @FeignClient(contextId = "ChargingHandshakeClient", value = ServiceNameConstants.INTEGRATION_SERVICE, fallbackFactory = ChargingHandshakeFallbackFactory.class) public interface ChargingHandshakeClient { /** * 根据订单号查询充电握手数据 * @param code * @return */ @PostMapping("/chargingHandshake/getDataByOrderCode") R<ChargingHandshake> getDataByOrderCode(@RequestParam("code") String code); } ruoyi-api/ruoyi-api-integration/src/main/java/com/ruoyi/integration/api/model/ChargingHandshake.java
@@ -2,6 +2,7 @@ import lombok.Data; import lombok.experimental.Accessors; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import java.math.BigDecimal; @@ -14,7 +15,7 @@ @Document(collection = "charging_handshake") //指定要对应的文档名(表名) @Accessors(chain = true) public class ChargingHandshake extends BaseModel { @Id private String transaction_serial_number;// 交易流水号 private String charging_pile_code;// 桩编码 private String charging_gun_code;// 抢号 ruoyi-api/ruoyi-api-integration/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -1,2 +1,3 @@ com.ruoyi.integration.api.factory.IntegrationFallbackFactory com.ruoyi.integration.api.factory.UploadRealTimeMonitoringDataFallbackFactory com.ruoyi.integration.api.factory.UploadRealTimeMonitoringDataFallbackFactory com.ruoyi.integration.api.factory.ChargingHandshakeFallbackFactory ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/TShoppingOrderRefund.java
@@ -29,6 +29,14 @@ @ApiModelProperty(value = "主键") @TableField("id") private Long id; @ApiModelProperty(value = "支付时间") @TableField("pay_time") private LocalDateTime payTime; @ApiModelProperty(value = "支付流水号") @TableField("pay_code") private String payCode; @ApiModelProperty(value = "累计退款金额") @TableField("pay_amount") ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/CouponFallbackFactory.java
@@ -35,6 +35,11 @@ public R<List<Integer>> getCouponIdsByName(String name) { return R.fail("根据名称查询优惠券ids:" + throwable.getMessage()); } @Override public R updateCoupon(TCoupon coupon) { throw new RuntimeException("修改优惠券失败"); } }; } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/GoodsFallbackFactory.java
@@ -33,6 +33,11 @@ public R<List<Integer>> getGoodsIdsByName(String name) { return R.fail("根据商品名称获取商品ids失败:" + throwable.getMessage()); } @Override public R updateGoods(TGoods goods) { throw new RuntimeException("修改商品异常"); } }; } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/CouponClient.java
@@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import java.util.List; @@ -28,4 +29,13 @@ R<TCoupon> getCouponById1(@PathVariable("id") Integer id); @PostMapping("/t-coupon/getCouponIdsByName/{name}") R<List<Integer>> getCouponIdsByName(@PathVariable("name")String name); /** * 修改优惠券 * @param coupon * @return */ @PostMapping("/t-coupon/updateCoupon") R updateCoupon(@RequestBody TCoupon coupon); } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/GoodsClient.java
@@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import java.util.List; @@ -32,4 +33,13 @@ */ @PostMapping("/t-goods/getGoodsIdsByName/{name}") public R<List<Integer>> getGoodsIdsByName(@PathVariable("name")String name); /** * 修改商品 * @param goods * @return */ @PostMapping("/t-goods/updateGoods") R updateGoods(@RequestBody TGoods goods); } ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/factory/WxPaymentFallbackFactory.java
@@ -5,6 +5,7 @@ import com.ruoyi.payment.api.model.WxPaymentRefundModel; import com.ruoyi.payment.api.vo.NotifyV3PayDecodeRespBody; import com.ruoyi.payment.api.vo.PaymentOrder; import com.ruoyi.payment.api.vo.WxRefundNotifyResp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.openfeign.FallbackFactory; @@ -58,6 +59,11 @@ return R.fail("微信退款失败:" + throwable.getMessage()); } @Override public R<WxRefundNotifyResp> refundNotify(HttpServletRequest request) { return R.fail("微信退款回调失败:" + throwable.getMessage()); } }; } } ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/feignClient/WxPaymentClient.java
@@ -6,6 +6,7 @@ import com.ruoyi.payment.api.model.WxPaymentRefundModel; import com.ruoyi.payment.api.vo.NotifyV3PayDecodeRespBody; import com.ruoyi.payment.api.vo.PaymentOrder; import com.ruoyi.payment.api.vo.WxRefundNotifyResp; import io.swagger.annotations.ApiOperation; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; @@ -65,4 +66,10 @@ @ApiOperation("订单退款") @PostMapping(value = "/wx/refundOrderR") public R<String> refundOrderR(@RequestBody WxPaymentRefundModel model); @ApiOperation("订单退款回调") @PostMapping(value = "/wx/refund/notify") R<WxRefundNotifyResp> refundNotify(HttpServletRequest request); } ruoyi-api/ruoyi-api-payment/src/main/java/com/ruoyi/payment/api/vo/WxRefundNotifyResp.java
New file @@ -0,0 +1,35 @@ package com.ruoyi.payment.api.vo; import lombok.Data; /** * @author zhibing.pu * @Date 2024/8/28 14:54 */ @Data public class WxRefundNotifyResp { /** * 支付单号 */ private String out_trade_no; /** * 退款单号 */ private String out_refund_no; /** * 支付流水号 */ private String transaction_id; /** * 退款流水号 */ private String refund_id; /** * 退款状态 */ private String tradeState; /** * 退款时间 */ private String success_time; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/controller/ChargingHandshakeController.java
New file @@ -0,0 +1,35 @@ package com.ruoyi.integration.controller; import com.ruoyi.common.core.domain.R; import com.ruoyi.integration.api.model.ChargingHandshake; import com.ruoyi.integration.mongodb.service.ChargingHandshakeService; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @author zhibing.pu * @Date 2024/8/28 9:50 */ @RestController @RequestMapping("/chargingHandshake") public class ChargingHandshakeController { @Resource private ChargingHandshakeService chargingHandshakeService; /** * 根据订单编号获取充电握手数据 * @param code * @return */ @PostMapping("/getDataByOrderCode") public R<ChargingHandshake> getDataByOrderCode(@RequestParam("code") String code){ ChargingHandshake chargingHandshake = chargingHandshakeService.findById(code); return R.ok(chargingHandshake); } } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/mongodb/service/ChargingHandshakeService.java
@@ -4,4 +4,6 @@ import com.ruoyi.integration.mongodb.base.BaseService; public interface ChargingHandshakeService extends BaseService<ChargingHandshake> { } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TShoppingOrderController.java
@@ -24,6 +24,7 @@ import com.ruoyi.payment.api.model.RefundReq; import com.ruoyi.payment.api.model.RefundResp; import com.ruoyi.payment.api.model.WxPaymentRefundModel; import com.ruoyi.payment.api.vo.WxRefundNotifyResp; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.feignClient.SysUserClient; import io.swagger.annotations.Api; @@ -33,6 +34,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.Arrays; import java.util.Date; import java.util.List; @@ -228,6 +230,21 @@ return shoppingOrderService.cancelOrder(id); } /** * 商城订单取消微信退款回调 */ @PostMapping("/cancelShoppingOrderWxRefund") public void cancelShoppingOrderWxRefund(HttpServletRequest request){ WxRefundNotifyResp data = wxPaymentClient.refundNotify(request).getData(); if(null != data){ String out_refund_no = data.getOut_refund_no(); String refund_id = data.getRefund_id(); String tradeState = data.getTradeState(); String success_time = data.getSuccess_time(); shoppingOrderService.cancelShoppingOrderWxRefund(out_refund_no, refund_id, tradeState, success_time); } } @ResponseBody ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/ChargingDetails.java
@@ -26,7 +26,7 @@ @ApiModelProperty("续航") private BigDecimal endurance; @ApiModelProperty("剩余充电时间") private Long remainingChargeTime; private Integer remainingChargeTime; @ApiModelProperty("充电枪名") private String name; @ApiModelProperty("订单编号") @@ -34,9 +34,9 @@ @ApiModelProperty("已充电度数") private BigDecimal chargedDegrees; @ApiModelProperty("已充电时间") private Long chargedTime; private Integer chargedTime; @ApiModelProperty("充电费用") private BigDecimal ChargingCost; private BigDecimal chargingCost; @ApiModelProperty("充电状态(0=未知,1=等待中,2=启动中,3=充电中,4=停止中,5=已结束)") private Integer status; } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyShoppingOrderInfo.java
@@ -39,6 +39,8 @@ private String code; @ApiModelProperty("下单时间") private String createTime; @ApiModelProperty("订单金额") private BigDecimal orderAmount; @ApiModelProperty("支付金额") private BigDecimal paymentAmount; @ApiModelProperty("备注") ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyShoppingOrderList.java
@@ -19,6 +19,8 @@ private String imgUrl; @ApiModelProperty("商品名称") private String name; @ApiModelProperty("商品类型(1=商品,2=优惠券)") private Integer orderType; @ApiModelProperty("状态(1=待发货,2=待收货,3=已完成,4=已取消)") private Integer status; @ApiModelProperty("单价") @@ -27,4 +29,6 @@ private Integer number; @ApiModelProperty("支付金额") private BigDecimal paymentAmount; @ApiModelProperty("订单时间") private String createTime; } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TShoppingOrderService.java
@@ -55,6 +55,18 @@ /** * 商城订单取消订单微信退款处理 * @param out_refund_no 退款单号 * @param refund_id 退款流水号 * @param refund_status 退款状态 SUCCESS:退款成功 CLOSED:退款关闭 ABNORMAL:退款异常 * @param success_time 退款成功时间 * @return */ AjaxResult cancelShoppingOrderWxRefund(String out_refund_no, String refund_id, String refund_status, String success_time); /** * 获取未开票的订单列表 * @param query * @return ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -22,7 +22,9 @@ import com.ruoyi.common.core.web.page.PageInfo; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.integration.api.feignClient.ChargingHandshakeClient; import com.ruoyi.integration.api.feignClient.UploadRealTimeMonitoringDataClient; import com.ruoyi.integration.api.model.ChargingHandshake; import com.ruoyi.integration.api.model.UploadRealTimeMonitoringData; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TChargingOrderAccountingStrategy; @@ -100,6 +102,8 @@ @Resource private UploadRealTimeMonitoringDataClient uploadRealTimeMonitoringDataClient; @Resource private ChargingHandshakeClient chargingHandshakeClient; @@ -203,7 +207,7 @@ map.put("time", time.get(i)); //soc map.put("soc", soc.get(i)); //电压 //功率 map.put("power", po.get(i)); power.add(map); } @@ -431,7 +435,6 @@ if(null == one){ return null; } // todo 需要完善充电实时数据 ChargingDetails chargingDetails = new ChargingDetails(); chargingDetails.setId(one.getId().toString()); TChargingGun chargingGun = chargingGunClient.getChargingGunById(id).getData(); @@ -440,6 +443,27 @@ chargingDetails.setName(site.getName() + "-" + chargingPile.getName()); chargingDetails.setCode(one.getCode()); chargingDetails.setStatus(one.getStatus()); UploadRealTimeMonitoringData data = uploadRealTimeMonitoringDataClient.chargingOrderInfo(one.getCode()).getData(); if(null != data){ chargingDetails.setChargeCurrent(data.getOutput_current()); chargingDetails.setChargeVoltage(data.getOutput_voltage()); BigDecimal power = data.getOutput_current().multiply(data.getOutput_voltage()).divide(new BigDecimal(1000)); chargingDetails.setChargePower(power); chargingDetails.setCompletionRatio(data.getSoc()); chargingDetails.setRemainingChargeTime(data.getTime_remaining()); chargingDetails.setChargedDegrees(data.getCharging_degree()); chargingDetails.setChargedTime(data.getCumulative_charging_time()); chargingDetails.setChargingCost(data.getPaid_amount()); } ChargingHandshake chargingHandshake = chargingHandshakeClient.getDataByOrderCode(one.getCode()).getData(); if(null != chargingHandshake && null != data && null != one.getAppUserCarId()){ BigDecimal bms_battery_capacity = chargingHandshake.getBms_battery_capacity(); TAppUserCar appUserCar = appUserCarClient.getCarByIds(Arrays.asList(one.getAppUserCarId())).getData().get(0); // 续航 = 电池容量 / 续航里程 * soc BigDecimal divide = bms_battery_capacity.divide(new BigDecimal(appUserCar.getEndurance())); BigDecimal multiply = new BigDecimal(data.getSoc() / 100).multiply(divide); chargingDetails.setEndurance(multiply); } return chargingDetails; } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TShoppingOrderServiceImpl.java
@@ -7,11 +7,13 @@ import com.ruoyi.account.api.feignClient.AppCouponClient; import com.ruoyi.account.api.feignClient.AppUserAddressClient; import com.ruoyi.account.api.model.TAppUserAddress; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.page.PageInfo; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.order.api.model.TExchangeOrder; import com.ruoyi.order.api.model.TShoppingOrder; import com.ruoyi.order.api.model.TShoppingOrderRefund; import com.ruoyi.order.api.query.ShoppingOrderQuery; import com.ruoyi.order.api.query.TActivityStatisticsQuery; import com.ruoyi.order.api.vo.ChargingOrderVO; @@ -19,21 +21,33 @@ import com.ruoyi.order.api.vo.TActivityVO; import com.ruoyi.order.dto.*; import com.ruoyi.order.mapper.TShoppingOrderMapper; import com.ruoyi.order.service.TShoppingOrderRefundService; import com.ruoyi.order.service.TShoppingOrderService; import com.ruoyi.other.api.domain.TCoupon; import com.ruoyi.other.api.domain.TGoods; import com.ruoyi.other.api.feignClient.CouponClient; import com.ruoyi.other.api.feignClient.GoodsClient; import com.ruoyi.payment.api.feignClient.AliPaymentClient; import com.ruoyi.payment.api.feignClient.WxPaymentClient; import com.ruoyi.payment.api.model.RefundReq; import com.ruoyi.payment.api.model.RefundResp; import com.ruoyi.payment.api.model.WxPaymentRefundModel; import com.ruoyi.payment.api.vo.AliQueryOrder; import com.ruoyi.payment.api.vo.NotifyV3PayDecodeRespBody; import io.seata.spring.annotation.GlobalTransactional; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.stream.Collectors; /** * <p> @@ -59,6 +73,15 @@ private AppUserAddressClient appUserAddressClient; @Resource private AppCouponClient appCouponClient; @Resource private WxPaymentClient wxPaymentClient; @Resource private AliPaymentClient aliPaymentClient; @Resource private TShoppingOrderRefundService shoppingOrderRefundService; @@ -197,6 +220,7 @@ myShoppingOrderList.setUnitPrice(unitPrice); myShoppingOrderList.setNumber(tShoppingOrder.getPurchaseQuantity()); myShoppingOrderList.setPaymentAmount(tShoppingOrder.getPaymentAmount()); myShoppingOrderList.setOrderType(tShoppingOrder.getOrderType()); pageList.add(myShoppingOrderList); } return pageList; @@ -241,6 +265,7 @@ info.setUnitPrice(unitPrice); info.setCode(shoppingOrder.getCode()); info.setCreateTime(shoppingOrder.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); info.setOrderAmount(shoppingOrder.getOrderAmount()); info.setPaymentAmount(shoppingOrder.getPaymentAmount()); info.setRemark(shoppingOrder.getRemark()); if(null != shoppingOrder.getConsignerTime()){ @@ -267,25 +292,143 @@ if(shoppingOrder.getStatus() == 3){ return AjaxResult.error("订单已完成,不能取消"); } if(shoppingOrder.getStatus() == 4){ //退款状态并且所有金额退完 List<TShoppingOrderRefund> list = shoppingOrderRefundService.list(new LambdaQueryWrapper<TShoppingOrderRefund>().eq(TShoppingOrderRefund::getShoppingOrderId, id).eq(TShoppingOrderRefund::getRefundStatus, 2)); BigDecimal bigDecimal = list.stream().map(TShoppingOrderRefund::getRefundAmount).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_EVEN); if(shoppingOrder.getPaymentAmount().compareTo(bigDecimal) == 0 && shoppingOrder.getStatus() == 4){ return AjaxResult.error("订单已取消,不能重复操作"); } //退款金额 BigDecimal refundAmount = shoppingOrder.getPaymentAmount().subtract(bigDecimal); //先查询第三方订单状态订单是否退款 //支付方式(1=微信,2=支付宝) todo 待完善 //支付方式(1=微信,2=支付宝) Integer paymentType = shoppingOrder.getPaymentType(); if(1 == paymentType){ NotifyV3PayDecodeRespBody data = wxPaymentClient.queryOrderInfo(shoppingOrder.getCode()).getData(); String trade_state = data.getTrade_state(); if("NOTPAY".equals(trade_state) || "REVOKED".equals(trade_state) || "PAYERROR".equals(trade_state)){ return AjaxResult.error("订单还未支付,不能操作退款"); } if("CLOSED".equals(trade_state)){ return AjaxResult.error("订单支付已关闭,不能操作退款"); } if("USERPAYING".equals(trade_state)){ return AjaxResult.error("订单正在支付中,不能操作退款"); } } if(2 == paymentType){ AliQueryOrder aliQueryOrder = aliPaymentClient.query(shoppingOrder.getCode()).getData(); String tradeStatus = aliQueryOrder.getTradeStatus(); if("TRADE_CLOSED".equals(tradeStatus)){ return AjaxResult.error("订单还未支付,不能操作退款"); } if("TRADE_FINISHED".equals(tradeStatus)){ return AjaxResult.error("订单支付已关闭,不能操作退款"); } if("WAIT_BUYER_PAY".equals(tradeStatus)){ return AjaxResult.error("订单正在支付中,不能操作退款"); } } //退款成功后需要判断商品库存类型后决定是否需要回退库存 //加redis锁处理高并发 //构建退款明细 TShoppingOrderRefund shoppingOrderRefund = new TShoppingOrderRefund(); shoppingOrderRefund.setPayTime(shoppingOrder.getPayTime()); shoppingOrderRefund.setPayCode(shoppingOrder.getSerialNumber()); shoppingOrderRefund.setPayType(shoppingOrder.getPaymentType()); shoppingOrderRefund.setShoppingOrderId(shoppingOrder.getId()); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); shoppingOrderRefund.setRefundCode("GDF" + sdf.format(new Date()) + (Math.random() * 1000)); shoppingOrderRefund.setRefundAmount(refundAmount); shoppingOrderRefund.setRefundStatus(1); shoppingOrderRefund.setCode(shoppingOrder.getCode()); shoppingOrderRefund.setRefundTitle("取消订单"); shoppingOrderRefund.setRefundContent("取消订单"); shoppingOrderRefund.setRefundReason("取消订单"); shoppingOrderRefund.setRefundRemark("全额退款"); shoppingOrderRefund.setRefundTotalAmount(refundAmount.add(bigDecimal)); shoppingOrderRefund.setPayAmount(shoppingOrder.getPaymentAmount()); if(1 == paymentType){ WxPaymentRefundModel model = new WxPaymentRefundModel(); model.setOut_trade_no(shoppingOrder.getCode()); model.setOut_refund_no(shoppingOrderRefund.getRefundCode()); model.setReason("取消订单"); model.setNotify_url("http://127.0.0.1:9000/order/t-shopping-order/cancelShoppingOrderWxRefund"); WxPaymentRefundModel.RefundAmount amount = new WxPaymentRefundModel.RefundAmount(); amount.setRefund(refundAmount.multiply(new BigDecimal(100)).intValue()); amount.setTotal(shoppingOrder.getPaymentAmount().multiply(new BigDecimal(100)).intValue()); amount.setCurrency("CNY"); model.setAmount(amount); R<String> orderR = wxPaymentClient.refundOrderR(model); if(200 == orderR.getCode()){ shoppingOrderRefundService.save(shoppingOrderRefund); } } if(2 == paymentType){ RefundReq dto = new RefundReq(); dto.setOutTradeNo(shoppingOrder.getCode()); dto.setOutRequestNo(shoppingOrderRefund.getCode()); dto.setRefundAmount(refundAmount.toString()); dto.setRefundReason("取消订单"); RefundResp resp = aliPaymentClient.refund(dto).getData(); if(null != resp){ SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-DDTHH:mm:ss+TIMEZONE"); AjaxResult success = cancelShoppingOrderWxRefund(resp.getOutTradeNo(), resp.getTradeNo(), "SUCCESS", sdf1.format(new Date())); if(success.isSuccess()){ shoppingOrderRefundService.save(shoppingOrderRefund); } } } return AjaxResult.success(); } /** * 商城订单取消订单微信退款处理 * @param out_refund_no 退款单号 * @param refund_id 退款流水号 * @param refund_status 退款状态 SUCCESS:退款成功 CLOSED:退款关闭 ABNORMAL:退款异常 * @param success_time 退款成功时间 * @return */ @Override @GlobalTransactional(rollbackFor = Exception.class)//分布式事务 public AjaxResult cancelShoppingOrderWxRefund(String out_refund_no, String refund_id, String refund_status, String success_time) { if("SUCCESS".equals(refund_status)){ TShoppingOrderRefund one = shoppingOrderRefundService.getOne(new LambdaQueryWrapper<TShoppingOrderRefund>().eq(TShoppingOrderRefund::getRefundCode, out_refund_no)); one.setRefundSerialNumber(refund_id); one.setRefundTime(LocalDateTime.parse(success_time, DateTimeFormatter.ofPattern("yyyy-MM-DDTHH:mm:ss+TIMEZONE"))); shoppingOrderRefundService.updateById(one); //判断是否需要回退库存 TShoppingOrder shoppingOrder = this.getById(one.getShoppingOrderId()); //商品 if(shoppingOrder.getOrderType() == 1){ // todo 需完善redis锁 //redis锁 和支付使用同一个锁 TGoods goods = goodsClient.getGoodsById(shoppingOrder.getGoodsId()).getData(); Integer inventory = goods.getInventory(); if(-1 != inventory){ goods.setInventory(inventory + shoppingOrder.getPurchaseQuantity()); goodsClient.updateGoods(goods); } //解锁 } //优惠券 if(shoppingOrder.getOrderType() == 2){ //redis锁 TCoupon coupon = couponClient.getCouponById1(shoppingOrder.getCouponId()).getData(); Integer inventory = coupon.getInventoryQuantity(); if(-1 != inventory){ coupon.setInventoryQuantity(inventory + shoppingOrder.getPurchaseQuantity()); couponClient.updateCoupon(coupon); } //解锁 } } return AjaxResult.success(); } /** * 获取未开票的订单列表 @@ -318,6 +461,7 @@ myShoppingOrderList.setUnitPrice(unitPrice); myShoppingOrderList.setNumber(tShoppingOrder.getPurchaseQuantity()); myShoppingOrderList.setPaymentAmount(tShoppingOrder.getPaymentAmount()); myShoppingOrderList.setCreateTime(tShoppingOrder.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss"))); pageList.add(myShoppingOrderList); } return pageList; ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TCouponController.java
@@ -202,7 +202,17 @@ TCoupon coupon = tCouponService.getById(id); return R.ok(coupon); } /** * 修改优惠券 * @param coupon * @return */ @PostMapping(value = "/updateCoupon") public R updateCoupon(@RequestBody TCoupon coupon){ tCouponService.updateById(coupon); return R.ok(); } } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TGoodsController.java
@@ -318,5 +318,17 @@ TGoods goods = goodsService.getById(id); return R.ok(goods); } /** * 修改商品 * @param goods * @return */ @PostMapping("/updateGoods") public R updateGoods(@RequestBody TGoods goods){ goodsService.updateById(goods); return R.ok(); } } ruoyi-service/ruoyi-payment/src/main/java/com/ruoyi/payment/controller/WxPayController.java
@@ -4,6 +4,7 @@ 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.api.vo.WxRefundNotifyResp; import com.ruoyi.payment.wx.enums.RefundEnum; import com.ruoyi.payment.api.model.WxPaymentRefundModel; import com.ruoyi.payment.wx.resp.NotifyV3PayDecodeRespBody; @@ -149,12 +150,12 @@ * 退款回调 */ @PostMapping("refund/notify") public void refundNotify(HttpServletRequest request) throws IOException { public R<WxRefundNotifyResp> refundNotify(HttpServletRequest request) throws IOException { try { Map<String, Object> params = wxV3Pay.verifyNotify(request, new TypeReference<Map<String, Object>>() { }); // 商户订单号 String tradeNo = params.get("out_trade_no").toString(); String out_trade_no = params.get("out_trade_no").toString(); // 商户退款单号 String out_refund_no = params.get("out_refund_no").toString(); // 微信支付订单号 @@ -167,21 +168,22 @@ // 时间不对的话,可以调用 WxTimeUtils.toRfc3339Date(success_time)转换一下 String success_time = params.get("success_time").toString(); if (tradeState.equals(RefundEnum.SUCCESS.name())) { String substring = out_refund_no.substring(0, 2); switch (substring){ case "GW": break; } // TODO 退款成功处理 WxRefundNotifyResp resp = new WxRefundNotifyResp(); resp.setOut_trade_no(out_trade_no); resp.setOut_refund_no(out_refund_no); resp.setTradeState(tradeState); resp.setTransaction_id(transaction_id); resp.setRefund_id(refund_id); resp.setSuccess_time(success_time); wxV3Pay.ack(); return R.ok(resp); } else { wxV3Pay.ack(false, "不是成功的退款状态"); } } catch (Exception e) { wxV3Pay.ack(false, e.getMessage()); } return R.fail(); } /**