1 文件已重命名
6个文件已添加
19个文件已修改
| New file |
| | |
| | | package com.ruoyi.web.controller.api; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.system.model.THtmlConfig; |
| | | import com.ruoyi.system.service.THtmlConfigService; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import io.swagger.annotations.ApiParam; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * 协议、富文本配置相关接口 |
| | | * |
| | | * @author mitao |
| | | * @since 2025-12-16 |
| | | */ |
| | | @Slf4j |
| | | @RestController |
| | | @RequestMapping("/html-config") |
| | | @Api(tags = "协议、富文本配置相关接口") |
| | | @Validated |
| | | @RequiredArgsConstructor(onConstructor_ = {@Lazy}) |
| | | public class HtmlConfigController { |
| | | |
| | | private final THtmlConfigService htmlConfigService; |
| | | |
| | | /** |
| | | * 根据类型获取富文本配置 |
| | | * |
| | | * @param type 配置类型 |
| | | * 1=用户注册隐私协议 |
| | | * 2=大礼包购买协议 |
| | | * 3=实物商品购买协议 |
| | | * 4=关于我们 |
| | | * 5=积分规则 |
| | | * 6=金币兑换图文说明 |
| | | * 7=普通商品模块展示配置 |
| | | * 8=实物商品展示 |
| | | * @return 富文本配置信息 |
| | | */ |
| | | @ApiOperation(value = "根据类型获取富文本配置", response = THtmlConfig.class) |
| | | @GetMapping("/{type}") |
| | | public R<THtmlConfig> getByType( |
| | | @ApiParam(name = "type", value = "配置类型:1=用户注册隐私协议,2=大礼包购买协议,3=实物商品购买协议,4=关于我们,5=积分规则,6=金币兑换图文说明,7=普通商品模块展示配置,8=实物商品展示", required = true) |
| | | @PathVariable @NotNull(message = "配置类型不能为空") Integer type) { |
| | | LambdaQueryWrapper<THtmlConfig> queryWrapper = new LambdaQueryWrapper<>(); |
| | | queryWrapper.eq(THtmlConfig::getConfigType, type); |
| | | THtmlConfig htmlConfig = htmlConfigService.getOne(queryWrapper); |
| | | return R.ok(htmlConfig); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.web.controller.api; |
| | | |
| | | import com.ruoyi.system.service.ICBCNotifyService; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | | /** |
| | | * 工商银行支付回调接口 |
| | | * |
| | | * @author mitao |
| | | * @since 2025-12-16 |
| | | */ |
| | | @Slf4j |
| | | @RestController |
| | | @RequestMapping("/icbc-notify") |
| | | @Api(tags = "工商银行支付回调接口") |
| | | @RequiredArgsConstructor(onConstructor_ = {@Lazy}) |
| | | public class ICBCPayNotifyController { |
| | | |
| | | private final ICBCNotifyService icbcNotifyService; |
| | | |
| | | /** |
| | | * 大礼包商品订单支付回调(定金或全款) |
| | | * |
| | | * @param request HTTP请求对象 |
| | | * @param response HTTP响应对象 |
| | | */ |
| | | @ApiOperation(value = "大礼包商品订单支付回调") |
| | | @PostMapping("/big-gift/pay-notify") |
| | | public void bigGiftPayNotify(HttpServletRequest request, HttpServletResponse response) { |
| | | log.info("【工商银行】收到大礼包支付回调请求"); |
| | | icbcNotifyService.bigGiftPayNotify(request, response); |
| | | } |
| | | |
| | | /** |
| | | * 大礼包商品尾款支付回调 |
| | | * |
| | | * @param request HTTP请求对象 |
| | | * @param response HTTP响应对象 |
| | | */ |
| | | @ApiOperation(value = "大礼包商品尾款支付回调") |
| | | @PostMapping("/big-gift/final-pay-notify") |
| | | public void bigGiftFinalPayNotify(HttpServletRequest request, HttpServletResponse response) { |
| | | log.info("【工商银行】收到大礼包尾款支付回调请求"); |
| | | icbcNotifyService.bigGiftFinalPayNotify(request, response); |
| | | } |
| | | |
| | | /** |
| | | * 实物商品订单支付回调 |
| | | * |
| | | * @param request HTTP请求对象 |
| | | * @param response HTTP响应对象 |
| | | */ |
| | | @ApiOperation(value = "实物商品订单支付回调") |
| | | @PostMapping("/physical/pay-notify") |
| | | public void physicalPayNotify(HttpServletRequest request, HttpServletResponse response) { |
| | | log.info("【工商银行】收到实物商品支付回调请求"); |
| | | icbcNotifyService.physicalPayNotify(request, response); |
| | | } |
| | | } |
| | |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * 首页相关接口 |
| | | */ |
| | | @Slf4j |
| | | @RestController |
| | | @RequestMapping("/index") |
| | | @Api(tags = "首页模块") |
| | | @Api(tags = "首页相关接口") |
| | | @Validated |
| | | @RequiredArgsConstructor(onConstructor_ = {@Lazy}) |
| | | public class IndexController { |
| | |
| | | @GetMapping(value = "/getBannerDetail/{id}") |
| | | public R<TBanner> getBannerDetail(@PathVariable String id) { |
| | | TBanner tBanner = tBannerService.getById(id); |
| | | //增加阅读量 |
| | | tBanner.setReadCount(tBanner.getReadCount() + 1); |
| | | tBannerService.updateById(tBanner); |
| | | return R.ok(tBanner); |
| | | } |
| | | @ApiOperation("获取大礼包列表") |
| New file |
| | |
| | | package com.ruoyi.web.controller.api; |
| | | |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.framework.web.service.TokenService; |
| | | import com.ruoyi.system.dto.BigGiftPlaceOrderDTO; |
| | | import com.ruoyi.system.dto.FinalPaymentDTO; |
| | | import com.ruoyi.system.dto.PhysicalGoodsPlaceOrderDTO; |
| | | import com.ruoyi.system.model.TAppUser; |
| | | import com.ruoyi.system.service.TAppUserService; |
| | | import com.ruoyi.system.service.TBigGiftPackageOrderService; |
| | | import com.ruoyi.system.service.TPhysicalGoodsOrderService; |
| | | import com.ruoyi.system.vo.PlaceOrderVO; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.validation.annotation.Validated; |
| | | 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.validation.Valid; |
| | | |
| | | /** |
| | | * 下单接口 |
| | | * |
| | | * @author mitao |
| | | * @since 2025-12-16 |
| | | */ |
| | | @Slf4j |
| | | @RestController |
| | | @RequestMapping("/order") |
| | | @Api(tags = "下单模块") |
| | | @Validated |
| | | @RequiredArgsConstructor(onConstructor_ = {@Lazy}) |
| | | public class OrderController { |
| | | |
| | | private final TokenService tokenService; |
| | | private final TAppUserService appUserService; |
| | | private final TBigGiftPackageOrderService bigGiftPackageOrderService; |
| | | private final TPhysicalGoodsOrderService physicalGoodsOrderService; |
| | | |
| | | /** |
| | | * 大礼包商品下单 |
| | | * |
| | | * @param dto 下单请求参数 |
| | | * @return 下单结果(包含订单信息和支付参数) |
| | | */ |
| | | @ApiOperation(value = "大礼包商品下单", response = PlaceOrderVO.class) |
| | | @PostMapping("/big-gift/place") |
| | | public R<PlaceOrderVO> placeBigGiftOrder(@Valid @RequestBody BigGiftPlaceOrderDTO dto) { |
| | | // 获取当前登录用户 |
| | | Integer userId = tokenService.getLoginUserApplet().getUserId(); |
| | | TAppUser appUser = appUserService.getById(userId); |
| | | if (appUser == null) { |
| | | return R.fail("用户不存在"); |
| | | } |
| | | if (appUser.getOpenid() == null || appUser.getOpenid().isEmpty()) { |
| | | return R.fail("用户未绑定微信"); |
| | | } |
| | | |
| | | PlaceOrderVO result = bigGiftPackageOrderService.placeOrder(dto, userId, appUser.getOpenid()); |
| | | return R.ok(result); |
| | | } |
| | | |
| | | /** |
| | | * 实物商品下单 |
| | | * |
| | | * @param dto 下单请求参数 |
| | | * @return 下单结果(包含订单信息和支付参数) |
| | | */ |
| | | @ApiOperation(value = "实物商品下单", response = PlaceOrderVO.class) |
| | | @PostMapping("/physical/place") |
| | | public R<PlaceOrderVO> placePhysicalGoodsOrder(@Valid @RequestBody PhysicalGoodsPlaceOrderDTO dto) { |
| | | // 获取当前登录用户 |
| | | Integer userId = tokenService.getLoginUserApplet().getUserId(); |
| | | TAppUser appUser = appUserService.getById(userId); |
| | | if (appUser == null) { |
| | | return R.fail("用户不存在"); |
| | | } |
| | | if (appUser.getOpenid() == null || appUser.getOpenid().isEmpty()) { |
| | | return R.fail("用户未绑定微信"); |
| | | } |
| | | |
| | | PlaceOrderVO result = physicalGoodsOrderService.placeOrder(dto, userId, appUser.getOpenid()); |
| | | return R.ok(result); |
| | | } |
| | | |
| | | /** |
| | | * 大礼包尾款支付 |
| | | * |
| | | * @param dto 尾款支付请求参数 |
| | | * @return 支付结果(包含订单信息和支付参数) |
| | | */ |
| | | @ApiOperation(value = "大礼包尾款支付", response = PlaceOrderVO.class) |
| | | @PostMapping("/big-gift/pay-final") |
| | | public R<PlaceOrderVO> payFinalPayment(@Valid @RequestBody FinalPaymentDTO dto) { |
| | | // 获取当前登录用户 |
| | | Integer userId = tokenService.getLoginUserApplet().getUserId(); |
| | | TAppUser appUser = appUserService.getById(userId); |
| | | if (appUser == null) { |
| | | return R.fail("用户不存在"); |
| | | } |
| | | if (appUser.getOpenid() == null || appUser.getOpenid().isEmpty()) { |
| | | return R.fail("用户未绑定微信"); |
| | | } |
| | | |
| | | PlaceOrderVO result = bigGiftPackageOrderService.payFinalPayment(dto.getOrderId(), userId, appUser.getOpenid()); |
| | | return R.ok(result); |
| | | } |
| | | } |
| | |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | /** |
| | | * 个人中心相关接口 |
| | | */ |
| | | @Slf4j |
| | | @RestController |
| | | @RequestMapping("/userIndex") |
| | |
| | | // 生成令牌 |
| | | LoginUserApplet loginUser = loginService.loginCodeApplet(loginBody.getUsername(), loginBody.getCode()); |
| | | ajax.put(Constants.TOKEN, tokenService.createTokenApplet(loginUser)); |
| | | ajax.put("userInfo",loginUser); |
| | | ajax.put("info",loginUser); |
| | | return ajax; |
| | | } |
| | | |
| | |
| | | prefix: https://xzgt.test.591taxi.cn:${server.port}${server.servlet.context-path} |
| | | wx: |
| | | conf: |
| | | appId: wxe91f1af7638aa5dd |
| | | secretId: a787e1a462715604e0c9528b6d8960d1 |
| | | appId: wx87744e4e4094a829 |
| | | secretId: c322159083d844e63dff458b5e54c4c9 |
| | | #OSS及短信配置 |
| | | code: |
| | | config: |
| | |
| | | notify-url: "" |
| | | |
| | | # 回调方法的路径 |
| | | notify-url-method: "/icbc/icbcNotify" |
| | | notify-url-method: "/icbc-notify/" |
| | | |
| | | |
| | | |
| | |
| | | wx-gzh-app-id: "" |
| | | |
| | | # 订单超时时间,单位为分钟 |
| | | expire-time: "300" |
| | | expire-time: "60" |
| | | |
| | | |
| | |
| | | devtools: |
| | | restart: |
| | | # 热部署开关 |
| | | enabled: true |
| | | enabled: false |
| | | # redis 配置 |
| | | redis: |
| | | # 地址 |
| | |
| | | allowExt: .jpg|.png|.gif|.jpeg|.doc|.docx|.apk|.MP4|.mp4|.pdf|.PDF|.xls|.xlsx|.rar|.zip|.rar|.m4a |
| | | wx: |
| | | conf: |
| | | appId: wx618aa69186bf2ed6 |
| | | secretId: d4af107e0b11236c1db24c1453f28bb3 |
| | | appId: wx87744e4e4094a829 |
| | | secretId: c322159083d844e63dff458b5e54c4c9 |
| | | payment: |
| | | wx: |
| | | # 微信appid |
| | |
| | | order-refund-url: "https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/refundqry/V1" |
| | | |
| | | # 完整的回调通知地址,支付完成后通知商户的URL |
| | | notify-url: "" |
| | | notify-url: "/icbc-notify/" |
| | | |
| | | # 回调方法的路径 |
| | | notify-url-method: "/icbc/icbcNotify" |
| | | notify-url-method: "/icbc-notify/" |
| | | |
| | | |
| | | |
| | |
| | | wx-gzh-app-id: "" |
| | | |
| | | # 订单超时时间,单位为分钟 |
| | | expire-time: "300" |
| | | expire-time: "60" |
| | | |
| | | |
| | | |
| | |
| | | @ApiModelProperty(value = "状态 1=启用 2=禁用") |
| | | private Integer status; |
| | | |
| | | @ApiModelProperty(value = "角色(1=游客,2=营销员,3=合伙人)") |
| | | private Integer userType; |
| | | |
| | | } |
| | |
| | | "/login","/open/login","/applet/queryProtocolConfigByType", |
| | | "/register","/applet/getCode","/applet/loginCode", |
| | | "/applet/changepwd", "/captchaImage","/getCode","/loginCode", |
| | | "/operations/getBySingleNum/**", |
| | | "/user/getUserInfoByNumber/**", |
| | | "/index/**", |
| | | "/employment/**", |
| | | "/partyBuilding/**", |
| | | "/convenience/**", |
| | | "/merchant/**", |
| | | "/openIdByJsCode", |
| | | "/t-appeal-services/pageListLarge","/t-large-dept/list", |
| | | "/t-large-key-grid-user/pageListLarge","/t-large-key-personnel-type/pageListLarge", |
| | | "/t-large-organization/pageListLarge","/t-large-resource/pageListLarge", |
| | | "/t-large-resource-type/list","/t-large-social-worker/pageListLarge", |
| | | "/t-large-user/pageListLarge","/t-large-volunteer/pageListLarge", |
| | | "/pension/getAssistedDiningList", |
| | | "/pension/getAssistedDiningDetail", |
| | | "/statistics/**","/course/**","/wx/**" |
| | | "/openIdByJsCode","/wx/**","/html-config/*","/icbc-notify/**" |
| | | ).permitAll() |
| | | // 静态资源,可匿名访问 |
| | | .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() |
| File was renamed from ruoyi-system/src/main/java/com/ruoyi/system/config/IcbcConfig.java |
| | |
| | | * @author: yangchuan |
| | | * @create: 2024-11-18 17:10 |
| | | */ |
| | | //@Component |
| | | @Component |
| | | @Data |
| | | public class IcbcConfig { |
| | | public class ICBCConfig { |
| | | |
| | | /** |
| | | * 聚合支付B2C线上消费下单接口url (无界面) |
| | |
| | | |
| | | private volatile static DefaultIcbcClient instance = null; |
| | | |
| | | public static DefaultIcbcClient getInstance(IcbcConfig icbcConfig) { |
| | | public static DefaultIcbcClient getInstance(ICBCConfig icbcConfig) { |
| | | if (instance == null) { |
| | | synchronized (IcbcConfig.class) { |
| | | synchronized (ICBCConfig.class) { |
| | | if (instance == null) { |
| | | instance = new DefaultIcbcClient(icbcConfig.appId, IcbcConstants.SIGN_TYPE_RSA2, icbcConfig.myPrivateKey, icbcConfig.apiGwPublicKey); |
| | | } |
| New file |
| | |
| | | package com.ruoyi.system.enums; |
| | | |
| | | import lombok.Getter; |
| | | |
| | | @Getter |
| | | public enum UnionPayStatusEnum { |
| | | |
| | | TRADE_SUCCESS("TRADE_SUCCESS", "支付成功"), |
| | | TRADE_FAIL("TRADE_FAIL", "支付失败"), |
| | | TRADE_REFUND("TRADE_REFUND", "退款成功") |
| | | ; |
| | | |
| | | private final String code; |
| | | private final String name; |
| | | |
| | | UnionPayStatusEnum(String code, String name) { |
| | | this.code = code; |
| | | this.name = name; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return this.name; |
| | | } |
| | | |
| | | public static UnionPayStatusEnum fromCode(String code) { |
| | | for (UnionPayStatusEnum action : UnionPayStatusEnum.values()) { |
| | | if (action.getCode().equals(code)) { |
| | | return action; |
| | | } |
| | | } |
| | | throw new IllegalArgumentException("No matching action for code " + code); |
| | | } |
| | | |
| | | } |
| | |
| | | package com.ruoyi.system.mapper; |
| | | |
| | | import com.ruoyi.system.model.TBigGiftPackage; |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.ruoyi.system.model.TBigGiftPackage; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Update; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | */ |
| | | public interface TBigGiftPackageMapper extends BaseMapper<TBigGiftPackage> { |
| | | |
| | | /** |
| | | * 使用乐观锁扣减库存 |
| | | * |
| | | * @param id 商品ID |
| | | * @param quantity 扣减数量 |
| | | * @return 更新行数(0表示库存不足或并发冲突) |
| | | */ |
| | | @Update("UPDATE t_big_gift_package SET inventory = inventory - #{quantity} WHERE id = #{id} AND inventory >= #{quantity} AND status = 1") |
| | | int deductInventory(@Param("id") Integer id, @Param("quantity") Integer quantity); |
| | | |
| | | } |
| | |
| | | package com.ruoyi.system.model; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.*; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.ruoyi.common.core.domain.BaseModel; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import java.io.Serializable; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | @TableField("banner_detail") |
| | | private String bannerDetail; |
| | | |
| | | @ApiModelProperty(value = "阅读数量") |
| | | @TableField("read_count") |
| | | private Integer readCount; |
| | | |
| | | } |
| | |
| | | package com.ruoyi.system.model; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | import cn.afterturn.easypoi.excel.annotation.Excel; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import java.time.LocalDateTime; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import java.io.Serializable; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | @TableField("final_payment_serial_number") |
| | | private String finalPaymentSerialNumber; |
| | | |
| | | @ApiModelProperty(value = "支付订单号(用于工行支付,多订单合并支付时共用同一个支付订单号)") |
| | | @TableField("pay_order_code") |
| | | private String payOrderCode; |
| | | |
| | | @ApiModelProperty(value = "删除状态(0=否,1=是)") |
| | | @TableField("del_flag") |
| | | private Integer delFlag; |
| | |
| | | @Excel(name = "审核状态",replace = {"待审核_1","已通过_2","已驳回_3"}) |
| | | private Integer auditStatus; |
| | | |
| | | @ApiModelProperty(value = "是否启用生效日") |
| | | @TableField("effect_day_flag") |
| | | private Boolean effectDayFlag; |
| | | |
| | | @ApiModelProperty(value = "商品封面") |
| | | @TableField(exist = false) |
| | | private String bigGiftPackageCover; |
| | |
| | | @TableField("order_id") |
| | | private Integer orderId; |
| | | |
| | | @ApiModelProperty(value = "订单类型(1=大礼包,2=实物商品)") |
| | | @TableField("order_type") |
| | | private Integer orderType; |
| | | |
| | | @ApiModelProperty(value = "订单金额") |
| | | @TableField("order_price") |
| | | private BigDecimal orderPrice; |
| New file |
| | |
| | | package com.ruoyi.system.service; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | | /** |
| | | * 工商银行支付回调服务 |
| | | * |
| | | * @author mitao |
| | | * @since 2025-12-16 |
| | | */ |
| | | public interface ICBCNotifyService { |
| | | |
| | | /** |
| | | * 大礼包商品订单支付回调(定金或全款) |
| | | * |
| | | * @param request HTTP请求对象 |
| | | * @param response HTTP响应对象 |
| | | */ |
| | | void bigGiftPayNotify(HttpServletRequest request, HttpServletResponse response); |
| | | |
| | | /** |
| | | * 大礼包商品尾款支付回调 |
| | | * |
| | | * @param request HTTP请求对象 |
| | | * @param response HTTP响应对象 |
| | | */ |
| | | void bigGiftFinalPayNotify(HttpServletRequest request, HttpServletResponse response); |
| | | |
| | | /** |
| | | * 实物商品订单支付回调 |
| | | * |
| | | * @param request HTTP请求对象 |
| | | * @param response HTTP响应对象 |
| | | */ |
| | | void physicalPayNotify(HttpServletRequest request, HttpServletResponse response); |
| | | |
| | | } |
| | |
| | | package com.ruoyi.system.service; |
| | | |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.system.model.TBigGiftPackageOrder; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.system.dto.BigGiftPlaceOrderDTO; |
| | | import com.ruoyi.system.model.TBigGiftPackageOrder; |
| | | import com.ruoyi.system.query.BigGiftPackageOrderQuery; |
| | | import com.ruoyi.system.vo.PlaceOrderVO; |
| | | |
| | | import java.util.List; |
| | | |
| | |
| | | |
| | | List<TBigGiftPackageOrder> export(BigGiftPackageOrderQuery query); |
| | | |
| | | /** |
| | | * 大礼包下单 |
| | | * |
| | | * @param dto 下单请求参数 |
| | | * @param appUserId 用户ID |
| | | * @param openid 用户微信openid |
| | | * @return 下单结果(包含订单信息和支付参数) |
| | | */ |
| | | PlaceOrderVO placeOrder(BigGiftPlaceOrderDTO dto, Integer appUserId, String openid); |
| | | |
| | | /** |
| | | * 大礼包尾款支付 |
| | | * |
| | | * @param orderId 订单ID |
| | | * @param appUserId 用户ID |
| | | * @param openid 用户微信openid |
| | | * @return 支付结果(包含订单信息和支付参数) |
| | | */ |
| | | PlaceOrderVO payFinalPayment(Integer orderId, Integer appUserId, String openid); |
| | | |
| | | } |
| | |
| | | package com.ruoyi.system.service; |
| | | |
| | | import com.ruoyi.system.model.TCommissionTransactionFlow; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.system.model.TCommissionTransactionFlow; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | */ |
| | | public interface TCommissionTransactionFlowService extends IService<TCommissionTransactionFlow> { |
| | | |
| | | /** |
| | | * 计算并保存分佣 |
| | | * |
| | | * @param orderId 订单ID |
| | | * @param orderType 订单类型(1=大礼包,2=实物商品) |
| | | * @param orderPrice 订单金额 |
| | | * @param appUserId 购买用户ID |
| | | */ |
| | | void calculateAndSaveCommission(Integer orderId, Integer orderType, BigDecimal orderPrice, Integer appUserId); |
| | | |
| | | } |
| | |
| | | package com.ruoyi.system.service; |
| | | |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.system.model.TPhysicalGoodsOrder; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.system.dto.PhysicalGoodsPlaceOrderDTO; |
| | | import com.ruoyi.system.model.TPhysicalGoodsOrder; |
| | | import com.ruoyi.system.query.BigGiftPackageQuery; |
| | | import com.ruoyi.system.vo.PlaceOrderVO; |
| | | |
| | | import java.util.List; |
| | | |
| | |
| | | |
| | | List<TPhysicalGoodsOrder> export(BigGiftPackageQuery query); |
| | | |
| | | /** |
| | | * 实物商品下单 |
| | | * |
| | | * @param dto 下单请求参数 |
| | | * @param appUserId 用户ID |
| | | * @param openid 用户微信openid |
| | | * @return 下单结果(包含订单信息和支付参数) |
| | | */ |
| | | PlaceOrderVO placeOrder(PhysicalGoodsPlaceOrderDTO dto, Integer appUserId, String openid); |
| | | |
| | | } |
| New file |
| | |
| | | package com.ruoyi.system.service.impl; |
| | | |
| | | |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.icbc.api.IcbcApiException; |
| | | import com.icbc.api.IcbcConstants; |
| | | import com.icbc.api.utils.IcbcSignature; |
| | | import com.icbc.api.utils.WebUtils; |
| | | import com.ruoyi.system.config.ICBCConfig; |
| | | import com.ruoyi.system.model.TBigGiftPackageOrder; |
| | | import com.ruoyi.system.model.TPhysicalGoodsOrder; |
| | | import com.ruoyi.system.service.ICBCNotifyService; |
| | | import com.ruoyi.system.service.TBigGiftPackageOrderService; |
| | | import com.ruoyi.system.service.TCommissionTransactionFlowService; |
| | | import com.ruoyi.system.service.TPhysicalGoodsOrderService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.time.LocalDateTime; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 工商银行支付回调服务实现 |
| | | * |
| | | * @author mitao |
| | | * @since 2025-12-16 |
| | | */ |
| | | @Service |
| | | @Slf4j |
| | | public class ICBCNotifyServiceImpl implements ICBCNotifyService { |
| | | |
| | | @Resource |
| | | private ICBCConfig icbcConfig; |
| | | |
| | | @Resource |
| | | private TBigGiftPackageOrderService bigGiftPackageOrderService; |
| | | |
| | | @Resource |
| | | private TPhysicalGoodsOrderService physicalGoodsOrderService; |
| | | |
| | | @Resource |
| | | private TCommissionTransactionFlowService commissionTransactionFlowService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void bigGiftPayNotify(HttpServletRequest request, HttpServletResponse response) { |
| | | boolean signResult = false; |
| | | String msgId = null; |
| | | try { |
| | | JSONObject bizContent = parseRequest(request); |
| | | if (bizContent == null) { |
| | | log.error("【工商银行】大礼包支付回调参数解析失败"); |
| | | sendResponse(response, false, null); |
| | | return; |
| | | } |
| | | log.info("【工商银行】大礼包支付回调参数:{}", bizContent.toJSONString()); |
| | | |
| | | String payOrderCode = bizContent.getString("out_trade_no"); |
| | | String returnCode = bizContent.getString("return_code"); |
| | | msgId = bizContent.getString("msg_id"); |
| | | |
| | | // 验签 |
| | | if (validateSignature(request, icbcConfig.getNotifyUrlMethod() + "/big-gift/pay-notify")) { |
| | | signResult = true; |
| | | log.info("支付订单号{}【工商银行】大礼包支付回调签名验证成功", payOrderCode); |
| | | |
| | | if ("0".equals(returnCode)) { |
| | | log.info("支付订单号{}【工商银行】大礼包支付成功", payOrderCode); |
| | | |
| | | // 根据支付订单号查询所有订单 |
| | | LambdaQueryWrapper<TBigGiftPackageOrder> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(TBigGiftPackageOrder::getPayOrderCode, payOrderCode); |
| | | List<TBigGiftPackageOrder> orders = bigGiftPackageOrderService.list(wrapper); |
| | | |
| | | if (orders == null || orders.isEmpty()) { |
| | | log.error("支付订单号{}未找到对应的大礼包订单", payOrderCode); |
| | | sendResponse(response, signResult, msgId); |
| | | return; |
| | | } |
| | | |
| | | // 处理每个订单 |
| | | for (TBigGiftPackageOrder order : orders) { |
| | | processBigGiftPayment(order); |
| | | } |
| | | } else { |
| | | log.error("支付订单号{}【工商银行】大礼包支付失败,错误信息:{}", payOrderCode, bizContent.getString("return_msg")); |
| | | } |
| | | } else { |
| | | log.error("支付订单号{}【工商银行】大礼包支付回调签名验证失败", payOrderCode); |
| | | } |
| | | |
| | | sendResponse(response, signResult, msgId); |
| | | } catch (Exception e) { |
| | | log.error("【工商银行】大礼包支付回调处理失败: {}", e.getMessage(), e); |
| | | sendResponse(response, false, msgId); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void bigGiftFinalPayNotify(HttpServletRequest request, HttpServletResponse response) { |
| | | boolean signResult = false; |
| | | String msgId = null; |
| | | try { |
| | | JSONObject bizContent = parseRequest(request); |
| | | if (bizContent == null) { |
| | | log.error("【工商银行】大礼包尾款支付回调参数解析失败"); |
| | | sendResponse(response, false, null); |
| | | return; |
| | | } |
| | | log.info("【工商银行】大礼包尾款支付回调参数:{}", bizContent.toJSONString()); |
| | | |
| | | String finalPayOrderCode = bizContent.getString("out_trade_no"); |
| | | String returnCode = bizContent.getString("return_code"); |
| | | msgId = bizContent.getString("msg_id"); |
| | | |
| | | // 验签 |
| | | if (validateSignature(request, icbcConfig.getNotifyUrlMethod() + "/big-gift/final-pay-notify")) { |
| | | signResult = true; |
| | | log.info("尾款支付订单号{}【工商银行】大礼包尾款支付回调签名验证成功", finalPayOrderCode); |
| | | |
| | | if ("0".equals(returnCode)) { |
| | | log.info("尾款支付订单号{}【工商银行】大礼包尾款支付成功", finalPayOrderCode); |
| | | |
| | | // 根据尾款支付订单号查询订单(尾款支付是单个订单) |
| | | // 注意:这里需要根据实际业务逻辑查询订单,可能需要在订单表中添加尾款支付订单号字段 |
| | | // 暂时使用订单编码查询 |
| | | LambdaQueryWrapper<TBigGiftPackageOrder> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(TBigGiftPackageOrder::getFinalPaymentSerialNumber, finalPayOrderCode); |
| | | TBigGiftPackageOrder order = bigGiftPackageOrderService.getOne(wrapper); |
| | | |
| | | if (order == null) { |
| | | log.error("尾款支付订单号{}未找到对应的大礼包订单", finalPayOrderCode); |
| | | sendResponse(response, signResult, msgId); |
| | | return; |
| | | } |
| | | |
| | | // 更新订单状态为"完成支付" |
| | | order.setStatus(3); |
| | | order.setFinalPaymentTime(LocalDateTime.now()); |
| | | order.setFinalPaymentSerialNumber(finalPayOrderCode); |
| | | bigGiftPackageOrderService.updateById(order); |
| | | log.info("订单{}状态更新为完成支付", order.getCode()); |
| | | |
| | | // 尾款支付完成后,必须计算分佣 |
| | | commissionTransactionFlowService.calculateAndSaveCommission( |
| | | order.getId(), |
| | | 1, // 订单类型:1=大礼包 |
| | | order.getOrderPrice(), |
| | | order.getAppUserId() |
| | | ); |
| | | log.info("订单{}分佣计算完成", order.getCode()); |
| | | } else { |
| | | log.error("尾款支付订单号{}【工商银行】大礼包尾款支付失败,错误信息:{}", finalPayOrderCode, bizContent.getString("return_msg")); |
| | | } |
| | | } else { |
| | | log.error("尾款支付订单号{}【工商银行】大礼包尾款支付回调签名验证失败", finalPayOrderCode); |
| | | } |
| | | |
| | | sendResponse(response, signResult, msgId); |
| | | } catch (Exception e) { |
| | | log.error("【工商银行】大礼包尾款支付回调处理失败: {}", e.getMessage(), e); |
| | | sendResponse(response, false, msgId); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void physicalPayNotify(HttpServletRequest request, HttpServletResponse response) { |
| | | boolean signResult = false; |
| | | String msgId = null; |
| | | try { |
| | | JSONObject bizContent = parseRequest(request); |
| | | if (bizContent == null) { |
| | | log.error("【工商银行】实物商品支付回调参数解析失败"); |
| | | sendResponse(response, false, null); |
| | | return; |
| | | } |
| | | log.info("【工商银行】实物商品支付回调参数:{}", bizContent.toJSONString()); |
| | | |
| | | String orderCode = bizContent.getString("out_trade_no"); |
| | | String returnCode = bizContent.getString("return_code"); |
| | | msgId = bizContent.getString("msg_id"); |
| | | |
| | | // 验签 |
| | | if (validateSignature(request, icbcConfig.getNotifyUrlMethod() + "/physical/pay-notify")) { |
| | | signResult = true; |
| | | log.info("订单{}【工商银行】实物商品支付回调签名验证成功", orderCode); |
| | | |
| | | if ("0".equals(returnCode)) { |
| | | log.info("订单{}【工商银行】实物商品支付成功", orderCode); |
| | | |
| | | // 根据订单编码查询订单 |
| | | LambdaQueryWrapper<TPhysicalGoodsOrder> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(TPhysicalGoodsOrder::getCode, orderCode); |
| | | TPhysicalGoodsOrder order = physicalGoodsOrderService.getOne(wrapper); |
| | | |
| | | if (order == null) { |
| | | log.error("订单{}未找到对应的实物商品订单", orderCode); |
| | | sendResponse(response, signResult, msgId); |
| | | return; |
| | | } |
| | | |
| | | // 更新订单状态为"完成支付" |
| | | order.setStatus(2); |
| | | order.setPaymentTime(LocalDateTime.now()); |
| | | order.setPaymentSerialNumber(orderCode); |
| | | physicalGoodsOrderService.updateById(order); |
| | | log.info("订单{}状态更新为完成支付", orderCode); |
| | | |
| | | // 实物商品支付完成后,立即计算分佣 |
| | | commissionTransactionFlowService.calculateAndSaveCommission( |
| | | order.getId(), |
| | | 2, // 订单类型:2=实物商品 |
| | | order.getOrderPrice(), |
| | | order.getAppUserId() |
| | | ); |
| | | log.info("订单{}分佣计算完成", orderCode); |
| | | } else { |
| | | log.error("订单{}【工商银行】实物商品支付失败,错误信息:{}", orderCode, bizContent.getString("return_msg")); |
| | | } |
| | | } else { |
| | | log.error("订单{}【工商银行】实物商品支付回调签名验证失败", orderCode); |
| | | } |
| | | |
| | | sendResponse(response, signResult, msgId); |
| | | } catch (Exception e) { |
| | | log.error("【工商银行】实物商品支付回调处理失败: {}", e.getMessage(), e); |
| | | sendResponse(response, false, msgId); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 处理大礼包支付(定金或全款) |
| | | */ |
| | | private void processBigGiftPayment(TBigGiftPackageOrder order) { |
| | | Integer paymentType = order.getPaymentType(); |
| | | |
| | | if (paymentType == 1) { |
| | | // 订金+尾款模式,更新状态为"已付订金" |
| | | order.setStatus(2); |
| | | order.setDepositTime(LocalDateTime.now()); |
| | | order.setDepositPaymentSerialNumber(order.getPayOrderCode()); |
| | | bigGiftPackageOrderService.updateById(order); |
| | | log.info("订单{}状态更新为已付订金,不计算分佣", order.getCode()); |
| | | } else if (paymentType == 2) { |
| | | // 全款模式,更新状态为"完成支付" |
| | | order.setStatus(3); |
| | | order.setDepositTime(LocalDateTime.now()); |
| | | order.setDepositPaymentSerialNumber(order.getPayOrderCode()); |
| | | bigGiftPackageOrderService.updateById(order); |
| | | log.info("订单{}状态更新为完成支付", order.getCode()); |
| | | |
| | | // 判断是否启用生效日 |
| | | Boolean effectDayFlag = order.getEffectDayFlag(); |
| | | if (effectDayFlag == null || !effectDayFlag) { |
| | | // 未启用生效日,立即计算分佣 |
| | | commissionTransactionFlowService.calculateAndSaveCommission( |
| | | order.getId(), |
| | | 1, // 订单类型:1=大礼包 |
| | | order.getOrderPrice(), |
| | | order.getAppUserId() |
| | | ); |
| | | log.info("订单{}未启用生效日,立即计算分佣", order.getCode()); |
| | | } else { |
| | | // 启用生效日,不计算分佣(由定时任务处理) |
| | | log.info("订单{}启用生效日,延迟计算分佣", order.getCode()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 解析请求中的回调参数 |
| | | * |
| | | * @param request HTTP请求对象 |
| | | * @return 解析后的JSON对象 |
| | | */ |
| | | private JSONObject parseRequest(HttpServletRequest request) { |
| | | try { |
| | | String bizContentStr = request.getParameter("biz_content"); |
| | | return JSON.parseObject(bizContentStr); |
| | | } catch (Exception e) { |
| | | log.error("【工商银行】解析回调参数失败: {}", e.getMessage()); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 验证签名 |
| | | * |
| | | * @param request 回调请求 |
| | | * @param path 回调URL路径 |
| | | * @return 签名验证结果 |
| | | */ |
| | | private boolean validateSignature(HttpServletRequest request, String path) { |
| | | Map<String, String> params = new HashMap<>(); |
| | | params.put("from", request.getParameter("from")); |
| | | params.put("api", request.getParameter("api")); |
| | | params.put("app_id", request.getParameter("app_id")); |
| | | params.put("charset", request.getParameter("charset")); |
| | | params.put("format", request.getParameter("format")); |
| | | params.put("timestamp", request.getParameter("timestamp")); |
| | | params.put("biz_content", request.getParameter("biz_content")); |
| | | params.put("sign_type", request.getParameter("sign_type")); |
| | | String sign = request.getParameter("sign"); |
| | | String signStr = WebUtils.buildOrderedSignStr(path, params); |
| | | try { |
| | | return IcbcSignature.verify(signStr, IcbcConstants.SIGN_TYPE_RSA, icbcConfig.getApiGwPublicKey(), params.get("charset"), sign); |
| | | } catch (IcbcApiException e) { |
| | | log.error("【工商银行】签名验证异常: {}", e.getMessage(), e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 发送回调响应 |
| | | * |
| | | * @param response HTTP响应对象 |
| | | * @param checkResult 签名验证结果 |
| | | * @param msgId 消息ID |
| | | */ |
| | | private void sendResponse(HttpServletResponse response, boolean checkResult, String msgId) { |
| | | String responseContent = buildNotifyResponse(checkResult, msgId); |
| | | response.setContentType("application/json; charset=utf-8"); |
| | | try { |
| | | response.getWriter().write(responseContent); |
| | | log.info("【工商银行】支付回调应答成功"); |
| | | } catch (IOException e) { |
| | | log.error("【工商银行】支付回调应答失败: {}", e.getMessage(), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 构建回调响应内容 |
| | | * 工行要求保证返回参数的绝对顺序,故直接返回固定字符串不定义对象 |
| | | * 接口文档地址 https://open.icbc.com.cn/icbc/apip/api_detail.html?apiId=10000000000000137000&baseUrl=%2Fcardbusiness%2Faggregatepay%2Fb2c%2Fonline&resUrl=%2Fconsumepurchase&version=V1&apiName=%E8%81%9A%E5%90%88%E6%94%AF%E4%BB%98B2C%E7%BA%BF%E4%B8%8A%E6%B6%88%E8%B4%B9%E4%B8%8B%E5%8D%95&serviceId=P0067&resourceId=10000000000000009800 |
| | | * |
| | | * @param checkResult 签名验证结果 |
| | | * @param msgId 消息ID |
| | | * @return 回调响应字符串 |
| | | */ |
| | | private String buildNotifyResponse(boolean checkResult, String msgId) { |
| | | String responseBizContent = checkResult |
| | | ? "{\"return_code\":0,\"return_msg\":\"success\",\"msg_id\":\"" + msgId + "\"}" |
| | | : "{\"return_code\":-1,\"return_msg\":\"icbc sign not pass.\"}"; |
| | | String signStr = "\"response_biz_content\":" + responseBizContent + ",\"sign_type\":\"RSA2\""; |
| | | try { |
| | | String sign = IcbcSignature.sign(signStr, IcbcConstants.SIGN_TYPE_RSA2, icbcConfig.getMyPrivateKey(), "UTF-8", ""); |
| | | return "{" + signStr + ",\"sign\":\"" + sign + "\"}"; |
| | | } catch (IcbcApiException e) { |
| | | log.error("【工商银行】回调应答签名失败: {}", e.getMessage(), e); |
| | | return "{\"response_biz_content\":{\"return_code\":-1,\"return_msg\":\"response sign error\"},\"sign_type\":\"RSA2\",\"sign\":\"\"}"; |
| | | } |
| | | } |
| | | |
| | | } |
| | |
| | | package com.ruoyi.system.service.impl; |
| | | |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.system.config.ICBCConfig; |
| | | import com.ruoyi.system.dto.BigGiftPlaceOrderDTO; |
| | | import com.ruoyi.system.mapper.TBigGiftPackageMapper; |
| | | import com.ruoyi.system.mapper.TBigGiftPackageOrderMapper; |
| | | import com.ruoyi.system.mapper.TCompanyMapper; |
| | | import com.ruoyi.system.model.TBigGiftPackage; |
| | | import com.ruoyi.system.model.TBigGiftPackageOrder; |
| | | import com.ruoyi.system.mapper.TBigGiftPackageOrderMapper; |
| | | import com.ruoyi.system.model.TCompany; |
| | | import com.ruoyi.system.query.BigGiftPackageOrderQuery; |
| | | import com.ruoyi.system.service.TBigGiftPackageOrderService; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.system.utils.ICBCPayUtil; |
| | | import com.ruoyi.system.utils.OrderCodeGenerator; |
| | | import com.ruoyi.system.vo.PlaceOrderVO; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | |
| | | * @author xiaochen |
| | | * @since 2025-12-08 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class TBigGiftPackageOrderServiceImpl extends ServiceImpl<TBigGiftPackageOrderMapper, TBigGiftPackageOrder> implements TBigGiftPackageOrderService { |
| | | |
| | |
| | | @Resource |
| | | private TBigGiftPackageMapper bigGiftPackageMapper; |
| | | |
| | | @Autowired |
| | | private ICBCPayUtil icbcPayUtil; |
| | | |
| | | @Autowired |
| | | private ICBCConfig icbcConfig; |
| | | |
| | | @Override |
| | | public List<TBigGiftPackageOrder> pageList(Page<TBigGiftPackageOrder> tBigGiftPackageOrderPage, BigGiftPackageOrderQuery query) { |
| | |
| | | } |
| | | return tBigGiftPackageOrders ; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public PlaceOrderVO placeOrder(BigGiftPlaceOrderDTO dto, Integer appUserId, String openid) { |
| | | // 1. 校验商品是否存在 |
| | | TBigGiftPackage bigGiftPackage = bigGiftPackageMapper.selectById(dto.getBigGiftPackageId()); |
| | | if (bigGiftPackage == null) { |
| | | throw new ServiceException("商品不存在"); |
| | | } |
| | | |
| | | // 2. 校验库存是否充足 |
| | | if (bigGiftPackage.getInventory() == null || bigGiftPackage.getInventory() < dto.getQuantity()) { |
| | | throw new ServiceException("商品库存不足"); |
| | | } |
| | | |
| | | // 3. 校验支付方式 |
| | | if (dto.getPaymentType() != 1 && dto.getPaymentType() != 2) { |
| | | throw new ServiceException("支付方式不正确"); |
| | | } |
| | | |
| | | // 4. 使用乐观锁扣减库存(防止超卖) |
| | | int updatedRows = bigGiftPackageMapper.deductInventory(dto.getBigGiftPackageId(), dto.getQuantity()); |
| | | if (updatedRows == 0) { |
| | | throw new ServiceException("商品库存不足,请稍后重试"); |
| | | } |
| | | |
| | | // 5. 计算支付金额 |
| | | BigDecimal paymentAmount; |
| | | if (dto.getPaymentType() == 1) { |
| | | // 订金+尾款模式,先支付订金 |
| | | paymentAmount = bigGiftPackage.getDeposit().multiply(new BigDecimal(dto.getQuantity())); |
| | | } else { |
| | | // 全款模式 |
| | | paymentAmount = bigGiftPackage.getTotalPrice().multiply(new BigDecimal(dto.getQuantity())); |
| | | } |
| | | |
| | | // 6. 先生成支付订单号(所有订单共用同一个支付订单号,便于支付回调时查询) |
| | | String payOrderCode = OrderCodeGenerator.generateBigGiftPayOrderCode(); |
| | | |
| | | // 7. 批量创建订单 |
| | | List<TBigGiftPackageOrder> orderList = new ArrayList<>(); |
| | | List<String> orderCodes = new ArrayList<>(); |
| | | String goodsJson = JSON.toJSONString(bigGiftPackage); |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | |
| | | for (int i = 0; i < dto.getQuantity(); i++) { |
| | | TBigGiftPackageOrder order = new TBigGiftPackageOrder(); |
| | | String orderCode = OrderCodeGenerator.generateBigGiftOrderCode(); |
| | | order.setCode(orderCode); |
| | | order.setPayOrderCode(payOrderCode); |
| | | order.setAppUserId(appUserId); |
| | | order.setCreateTime(now); |
| | | order.setBigGiftPackageId(dto.getBigGiftPackageId()); |
| | | order.setBigGiftPackage(goodsJson); |
| | | order.setOrderPrice(bigGiftPackage.getTotalPrice()); |
| | | order.setDeposit(bigGiftPackage.getDeposit()); |
| | | order.setFinalPayment(bigGiftPackage.getTotalPrice().subtract(bigGiftPackage.getDeposit())); |
| | | order.setPaymentType(dto.getPaymentType()); |
| | | order.setEffectDayFlag(dto.getEffectDayFlag()); |
| | | // 订单状态:1=待付款 |
| | | order.setStatus(1); |
| | | order.setDelFlag(0); |
| | | |
| | | orderList.add(order); |
| | | orderCodes.add(orderCode); |
| | | } |
| | | |
| | | // 批量插入订单 |
| | | this.saveBatch(orderList); |
| | | |
| | | // 获取订单ID列表 |
| | | List<Integer> orderIds = orderList.stream() |
| | | .map(TBigGiftPackageOrder::getId) |
| | | .collect(Collectors.toList()); |
| | | |
| | | // 8. 调用工行支付 |
| | | log.info("大礼包下单,支付订单号:{},业务订单号:{},支付金额:{},用户ID:{}", payOrderCode, orderCodes, paymentAmount, appUserId); |
| | | JSONObject paymentParams = icbcPayUtil.wechatPay(payOrderCode, paymentAmount, bigGiftPackage.getName(), openid, |
| | | icbcConfig.getNotifyUrl() + "/big-gift/pay-notify"); |
| | | |
| | | // 9. 构建返回结果 |
| | | PlaceOrderVO vo = new PlaceOrderVO(); |
| | | vo.setOrderIds(orderIds); |
| | | vo.setOrderCodes(orderCodes); |
| | | vo.setPaymentParams(paymentParams); |
| | | return vo; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public PlaceOrderVO payFinalPayment(Integer orderId, Integer appUserId, String openid) { |
| | | // 1. 查询订单 |
| | | TBigGiftPackageOrder order = this.getById(orderId); |
| | | if (order == null) { |
| | | throw new ServiceException("订单不存在"); |
| | | } |
| | | |
| | | // 2. 校验订单归属 |
| | | if (!order.getAppUserId().equals(appUserId)) { |
| | | throw new ServiceException("无权操作此订单"); |
| | | } |
| | | |
| | | // 3. 校验支付方式(必须是订金+尾款模式) |
| | | if (order.getPaymentType() != 1) { |
| | | throw new ServiceException("该订单不支持尾款支付"); |
| | | } |
| | | |
| | | // 4. 校验订单状态(必须是已付订金状态) |
| | | if (order.getStatus() != 2) { |
| | | throw new ServiceException("订单状态不正确,无法支付尾款"); |
| | | } |
| | | |
| | | // 5. 获取尾款金额 |
| | | BigDecimal finalPayment = order.getFinalPayment(); |
| | | if (finalPayment == null || finalPayment.compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw new ServiceException("尾款金额异常"); |
| | | } |
| | | |
| | | // 6. 生成尾款支付订单号 |
| | | String finalPayOrderCode = OrderCodeGenerator.generateBigGiftFinalPayOrderCode(); |
| | | |
| | | // 7. 调用工行支付 |
| | | log.info("大礼包尾款支付,订单ID:{},支付订单号:{},尾款金额:{},用户ID:{}", orderId, finalPayOrderCode, finalPayment, appUserId); |
| | | JSONObject paymentParams = icbcPayUtil.wechatPay(finalPayOrderCode, finalPayment, "大礼包尾款", openid, |
| | | icbcConfig.getNotifyUrl() + "/big-gift/final-pay-notify"); |
| | | |
| | | // 8. 构建返回结果 |
| | | PlaceOrderVO vo = new PlaceOrderVO(); |
| | | vo.setOrderIds(Collections.singletonList(orderId)); |
| | | vo.setOrderCodes(Collections.singletonList(order.getCode())); |
| | | vo.setPaymentParams(paymentParams); |
| | | return vo; |
| | | } |
| | | } |
| | |
| | | package com.ruoyi.system.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.ruoyi.system.model.TAppUser; |
| | | import com.ruoyi.system.model.TCommissionTransactionFlow; |
| | | import com.ruoyi.system.mapper.TCommissionTransactionFlowMapper; |
| | | import com.ruoyi.system.model.THtmlConfig; |
| | | import com.ruoyi.system.service.TAppUserService; |
| | | import com.ruoyi.system.service.TCommissionTransactionFlowService; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.system.service.THtmlConfigService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | * @author xiaochen |
| | | * @since 2025-12-08 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class TCommissionTransactionFlowServiceImpl extends ServiceImpl<TCommissionTransactionFlowMapper, TCommissionTransactionFlow> implements TCommissionTransactionFlowService { |
| | | |
| | | @Resource |
| | | private TAppUserService appUserService; |
| | | |
| | | @Resource |
| | | private THtmlConfigService htmlConfigService; |
| | | |
| | | @Override |
| | | public void calculateAndSaveCommission(Integer orderId, Integer orderType, BigDecimal orderPrice, Integer appUserId) { |
| | | try { |
| | | log.info("开始计算分佣,订单ID:{},订单类型:{},订单金额:{},用户ID:{}", orderId, orderType, orderPrice, appUserId); |
| | | |
| | | // 获取购买用户信息 |
| | | TAppUser buyer = appUserService.getById(appUserId); |
| | | if (buyer == null) { |
| | | log.error("用户不存在,用户ID:{}", appUserId); |
| | | return; |
| | | } |
| | | |
| | | // 获取分佣比例配置 |
| | | CommissionRate commissionRate = getCommissionRate(); |
| | | if (commissionRate == null) { |
| | | log.error("分佣比例配置不存在"); |
| | | return; |
| | | } |
| | | |
| | | log.info("分佣比例配置:营销员={}%,合伙人={}%", commissionRate.getSalesRate(), commissionRate.getPartnerRate()); |
| | | |
| | | // 根据用户类型计算分佣 |
| | | Integer buyerType = buyer.getUserType(); |
| | | Integer referrerUserId = buyer.getReferrerUserId(); |
| | | |
| | | if (buyerType == null || buyerType == 1) { |
| | | // 顾客(无身份)购买 |
| | | calculateForCustomer(orderId, orderType, orderPrice, referrerUserId, commissionRate); |
| | | } else if (buyerType == 2) { |
| | | // 营销员本人购买 |
| | | calculateForSales(orderId, orderType, orderPrice, appUserId, referrerUserId, commissionRate); |
| | | } else if (buyerType == 3) { |
| | | // 合伙人本人购买 |
| | | calculateForPartner(orderId, orderType, orderPrice, appUserId, commissionRate); |
| | | } |
| | | |
| | | log.info("分佣计算完成,订单ID:{}", orderId); |
| | | } catch (Exception e) { |
| | | log.error("分佣计算失败,订单ID:{},错误信息:{}", orderId, e.getMessage(), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 顾客购买的分佣计算 |
| | | */ |
| | | private void calculateForCustomer(Integer orderId, Integer orderType, BigDecimal orderPrice, |
| | | Integer referrerUserId, CommissionRate commissionRate) { |
| | | if (referrerUserId == null) { |
| | | log.info("顾客无推荐人,无需分佣"); |
| | | return; |
| | | } |
| | | |
| | | // 获取推荐人信息 |
| | | TAppUser referrer = appUserService.getById(referrerUserId); |
| | | if (referrer == null) { |
| | | log.error("推荐人不存在,推荐人ID:{}", referrerUserId); |
| | | return; |
| | | } |
| | | |
| | | Integer referrerType = referrer.getUserType(); |
| | | if (referrerType == null || referrerType == 1) { |
| | | log.info("推荐人不是营销员或合伙人,无需分佣"); |
| | | return; |
| | | } |
| | | |
| | | if (referrerType == 2) { |
| | | // 直接营销员 |
| | | saveCommissionFlow(orderId, orderType, orderPrice, referrerUserId, 2, |
| | | commissionRate.getSalesRate()); |
| | | log.info("顾客购买,直接营销员分佣:{}%", commissionRate.getSalesRate()); |
| | | |
| | | // 查找直接合伙人 |
| | | Integer partnerUserId = findDirectPartner(referrer); |
| | | if (partnerUserId != null) { |
| | | saveCommissionFlow(orderId, orderType, orderPrice, partnerUserId, 3, |
| | | commissionRate.getPartnerRate()); |
| | | log.info("顾客购买,直接合伙人分佣:{}%", commissionRate.getPartnerRate()); |
| | | } |
| | | } else if (referrerType == 3) { |
| | | // 直接合伙人(无直接营销员) |
| | | BigDecimal totalRate = commissionRate.getSalesRate().add(commissionRate.getPartnerRate()); |
| | | saveCommissionFlow(orderId, orderType, orderPrice, referrerUserId, 3, totalRate); |
| | | log.info("顾客购买,直接合伙人(无营销员)分佣:{}%", totalRate); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 营销员本人购买的分佣计算 |
| | | */ |
| | | private void calculateForSales(Integer orderId, Integer orderType, BigDecimal orderPrice, |
| | | Integer salesUserId, Integer referrerUserId, CommissionRate commissionRate) { |
| | | // 营销员本人获得 8% |
| | | saveCommissionFlow(orderId, orderType, orderPrice, salesUserId, 2, |
| | | commissionRate.getSalesRate()); |
| | | log.info("营销员本人购买,本人分佣:{}%", commissionRate.getSalesRate()); |
| | | |
| | | // 查找直接合伙人 |
| | | TAppUser sales = appUserService.getById(salesUserId); |
| | | if (sales != null) { |
| | | Integer partnerUserId = findDirectPartner(sales); |
| | | if (partnerUserId != null) { |
| | | saveCommissionFlow(orderId, orderType, orderPrice, partnerUserId, 3, |
| | | commissionRate.getPartnerRate()); |
| | | log.info("营销员本人购买,直接合伙人分佣:{}%", commissionRate.getPartnerRate()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 合伙人本人购买的分佣计算 |
| | | */ |
| | | private void calculateForPartner(Integer orderId, Integer orderType, BigDecimal orderPrice, |
| | | Integer partnerUserId, CommissionRate commissionRate) { |
| | | // 合伙人本人获得 10% + 8% = 18% |
| | | BigDecimal totalRate = commissionRate.getSalesRate().add(commissionRate.getPartnerRate()); |
| | | saveCommissionFlow(orderId, orderType, orderPrice, partnerUserId, 3, totalRate); |
| | | log.info("合伙人本人购买,本人分佣:{}%", totalRate); |
| | | } |
| | | |
| | | /** |
| | | * 查找直接合伙人 |
| | | */ |
| | | private Integer findDirectPartner(TAppUser user) { |
| | | Integer referrerUserId = user.getReferrerUserId(); |
| | | if (referrerUserId == null) { |
| | | return null; |
| | | } |
| | | |
| | | TAppUser referrer = appUserService.getById(referrerUserId); |
| | | if (referrer == null) { |
| | | return null; |
| | | } |
| | | |
| | | // 如果推荐人是合伙人,直接返回 |
| | | if (referrer.getUserType() != null && referrer.getUserType() == 3) { |
| | | return referrerUserId; |
| | | } |
| | | |
| | | // 如果推荐人是营销员,继续向上查找 |
| | | if (referrer.getUserType() != null && referrer.getUserType() == 2) { |
| | | return findDirectPartner(referrer); |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 保存佣金流水记录 |
| | | */ |
| | | private void saveCommissionFlow(Integer orderId, Integer orderType, BigDecimal orderPrice, |
| | | Integer userId, Integer userType, BigDecimal commissionRate) { |
| | | // 计算佣金金额 |
| | | BigDecimal commissionAmount = orderPrice.multiply(commissionRate) |
| | | .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP); |
| | | |
| | | TCommissionTransactionFlow flow = new TCommissionTransactionFlow(); |
| | | flow.setAppUserId(userId); |
| | | flow.setAppUserType(userType); |
| | | flow.setCommissionRate(commissionRate); |
| | | flow.setOrderId(orderId); |
| | | flow.setOrderType(orderType); |
| | | flow.setOrderPrice(orderPrice); |
| | | flow.setCommissionAmount(commissionAmount); |
| | | flow.setCreateTime(LocalDateTime.now()); |
| | | |
| | | save(flow); |
| | | log.info("保存佣金流水成功,用户ID:{},佣金金额:{}", userId, commissionAmount); |
| | | } |
| | | |
| | | /** |
| | | * 获取分佣比例配置 |
| | | */ |
| | | private CommissionRate getCommissionRate() { |
| | | LambdaQueryWrapper<THtmlConfig> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(THtmlConfig::getConfigType, 5); |
| | | THtmlConfig config = htmlConfigService.getOne(wrapper); |
| | | |
| | | if (config == null || config.getContent() == null || config.getContent().isEmpty()) { |
| | | return null; |
| | | } |
| | | |
| | | try { |
| | | String[] rates = config.getContent().split(","); |
| | | if (rates.length != 2) { |
| | | log.error("分佣比例配置格式错误:{}", config.getContent()); |
| | | return null; |
| | | } |
| | | |
| | | BigDecimal salesRate = new BigDecimal(rates[0].trim()); |
| | | BigDecimal partnerRate = new BigDecimal(rates[1].trim()); |
| | | |
| | | return new CommissionRate(salesRate, partnerRate); |
| | | } catch (Exception e) { |
| | | log.error("解析分佣比例配置失败:{}", config.getContent(), e); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 分佣比例配置类 |
| | | */ |
| | | private static class CommissionRate { |
| | | private final BigDecimal salesRate; |
| | | private final BigDecimal partnerRate; |
| | | |
| | | public CommissionRate(BigDecimal salesRate, BigDecimal partnerRate) { |
| | | this.salesRate = salesRate; |
| | | this.partnerRate = partnerRate; |
| | | } |
| | | |
| | | public BigDecimal getSalesRate() { |
| | | return salesRate; |
| | | } |
| | | |
| | | public BigDecimal getPartnerRate() { |
| | | return partnerRate; |
| | | } |
| | | } |
| | | } |
| | |
| | | package com.ruoyi.system.service.impl; |
| | | |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.system.model.TPhysicalGoodsOrder; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.system.config.ICBCConfig; |
| | | import com.ruoyi.system.dto.PhysicalGoodsPlaceOrderDTO; |
| | | import com.ruoyi.system.mapper.TPhysicalGoodsMapper; |
| | | import com.ruoyi.system.mapper.TPhysicalGoodsOrderMapper; |
| | | import com.ruoyi.system.model.TPhysicalGoods; |
| | | import com.ruoyi.system.model.TPhysicalGoodsOrder; |
| | | import com.ruoyi.system.query.BigGiftPackageQuery; |
| | | import com.ruoyi.system.service.TPhysicalGoodsOrderService; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.system.utils.ICBCPayUtil; |
| | | import com.ruoyi.system.utils.OrderCodeGenerator; |
| | | import com.ruoyi.system.vo.PlaceOrderVO; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.time.LocalDateTime; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | |
| | | * @author xiaochen |
| | | * @since 2025-12-08 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class TPhysicalGoodsOrderServiceImpl extends ServiceImpl<TPhysicalGoodsOrderMapper, TPhysicalGoodsOrder> implements TPhysicalGoodsOrderService { |
| | | |
| | | @Resource |
| | | private TPhysicalGoodsMapper physicalGoodsMapper; |
| | | |
| | | @Resource |
| | | private ICBCPayUtil icbcPayUtil; |
| | | |
| | | @Autowired |
| | | private ICBCConfig icbcConfig; |
| | | |
| | | @Override |
| | | public Page<TPhysicalGoodsOrder> pageList(BigGiftPackageQuery query) { |
| | |
| | | public List<TPhysicalGoodsOrder> export(BigGiftPackageQuery query) { |
| | | return this.baseMapper.export(query); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public PlaceOrderVO placeOrder(PhysicalGoodsPlaceOrderDTO dto, Integer appUserId, String openid) { |
| | | // 1. 校验商品是否存在 |
| | | TPhysicalGoods physicalGoods = physicalGoodsMapper.selectById(dto.getPhysicalGoodsId()); |
| | | if (physicalGoods == null) { |
| | | throw new ServiceException("商品不存在"); |
| | | } |
| | | |
| | | // 2. 创建订单 |
| | | TPhysicalGoodsOrder order = new TPhysicalGoodsOrder(); |
| | | String orderCode = OrderCodeGenerator.generatePhysicalGoodsOrderCode(); |
| | | order.setCode(orderCode); |
| | | order.setAppUserId(appUserId); |
| | | order.setCreateTime(LocalDateTime.now()); |
| | | order.setPhysicalGoodsId(dto.getPhysicalGoodsId()); |
| | | order.setPhysicalGoods(JSON.toJSONString(physicalGoods)); |
| | | order.setOrderPrice(physicalGoods.getTotalPrice()); |
| | | order.setPaymentPrice(physicalGoods.getTotalPrice()); |
| | | // 支付方式:1=微信 |
| | | order.setPaymentMethod(1); |
| | | // 订单状态:1=待付款 |
| | | order.setStatus(1); |
| | | order.setDelFlag(0); |
| | | |
| | | this.save(order); |
| | | |
| | | // 3. 更新商品销量 |
| | | Integer currentSales = physicalGoods.getSales() == null ? 0 : physicalGoods.getSales(); |
| | | physicalGoods.setSales(currentSales + 1); |
| | | physicalGoodsMapper.updateById(physicalGoods); |
| | | |
| | | // 4. 调用工行支付 |
| | | log.info("实物商品下单,订单号:{},支付金额:{},用户ID:{}", orderCode, physicalGoods.getTotalPrice(), appUserId); |
| | | JSONObject paymentParams = icbcPayUtil.wechatPay(orderCode, physicalGoods.getTotalPrice(), physicalGoods.getName(), openid,icbcConfig.getNotifyUrl()+"/physical/pay-notify"); |
| | | |
| | | // 5. 构建返回结果 |
| | | PlaceOrderVO vo = new PlaceOrderVO(); |
| | | vo.setOrderIds(Collections.singletonList(order.getId())); |
| | | vo.setOrderCodes(Collections.singletonList(orderCode)); |
| | | vo.setPaymentParams(paymentParams); |
| | | return vo; |
| | | } |
| | | } |
| | |
| | | import com.ruoyi.system.model.TPhysicalGoods; |
| | | import com.ruoyi.system.query.AppletPhysicalGoodsQuery; |
| | | import com.ruoyi.system.service.TPhysicalGoodsService; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | /** |
| | |
| | | public class TPhysicalGoodsServiceImpl extends ServiceImpl<TPhysicalGoodsMapper, TPhysicalGoods> implements TPhysicalGoodsService { |
| | | @Override |
| | | public IPage<TPhysicalGoods> getPageList(AppletPhysicalGoodsQuery query) { |
| | | return this.lambdaQuery().like(TPhysicalGoods::getName, query.getName()) |
| | | return this.lambdaQuery().like(StringUtils.isNotBlank(query.getName()),TPhysicalGoods::getName, query.getName()) |
| | | .page(new Page<>(query.getPageNum(), query.getPageSize())); |
| | | } |
| | | } |
| | |
| | | //package com.ruoyi.system.utils; |
| | | // |
| | | //import com.alibaba.fastjson2.JSON; |
| | | //import com.alibaba.fastjson2.JSONObject; |
| | | //import com.icbc.api.DefaultIcbcClient; |
| | | //import com.icbc.api.IcbcApiException; |
| | | //import com.icbc.api.request.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1; |
| | | //import com.icbc.api.response.CardbusinessAggregatepayB2cOnlineConsumepurchaseResponseV1; |
| | | //import com.ruoyi.common.exception.ServiceException; |
| | | //import com.ruoyi.common.utils.DateUtils; |
| | | //import com.ruoyi.common.utils.WebUtils; |
| | | //import com.ruoyi.common.utils.ip.IpUtils; |
| | | //import com.ruoyi.system.config.IcbcConfig; |
| | | //import com.ruoyi.system.enums.ICBCRespOrderErrorEnum; |
| | | //import lombok.extern.slf4j.Slf4j; |
| | | //import org.springframework.beans.factory.annotation.Autowired; |
| | | //import org.springframework.stereotype.Component; |
| | | // |
| | | //import java.math.BigDecimal; |
| | | // |
| | | //@Slf4j |
| | | //@Component |
| | | //public class ICBCPayUtil { |
| | | // |
| | | // @Autowired |
| | | // private IcbcConfig icbcConfig; |
| | | // |
| | | // public JSONObject wechatPay(String outTradeNo, BigDecimal totalPrice, String goodsName,String openid){ |
| | | // CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz bizContent = new |
| | | // CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz(); |
| | | // bizContent.setMer_id(icbcConfig.getMerId()); |
| | | // bizContent.setMer_prtcl_no(icbcConfig.getMerPrtclNo()); |
| | | // bizContent.setDecive_info(icbcConfig.getDeciveInfo()); |
| | | // bizContent.setOut_trade_no(outTradeNo); |
| | | // bizContent.setOrig_date_time(DateUtils.getCurrentDateTimeWithT()); |
| | | // //交易币种,目前工行只支持使用人民币(001)支付 |
| | | // bizContent.setFee_type("001"); |
| | | // bizContent.setSpbill_create_ip(IpUtils.getIpAddr(WebUtils.request())); |
| | | // //金额,单位分 |
| | | // bizContent.setTotal_fee(String.valueOf(totalPrice.multiply(new BigDecimal(100)).intValue())); |
| | | // //支付成功后回调url |
| | | // bizContent.setMer_url(icbcConfig.getNotifyUrl()); |
| | | // bizContent.setBody(goodsName); |
| | | // //收单接入方式,5-APP,7-微信公众号,8-支付宝生活号,9-微信小程序 |
| | | // bizContent.setAccess_type("9"); |
| | | // //支付方式,9-微信;10-支付宝; |
| | | // bizContent.setPay_mode("9"); |
| | | // //商户在微信开放平台注册的APPID,支付方式为微信时不能为空 |
| | | // bizContent.setShop_appid(icbcConfig.getWxAppId()); |
| | | // //第三方用户标识,商户在微信公众号内或微信小程序内接入时必送,即access_type为7或9时,上送用户在商户APPID下的唯一标识;商户通过支付宝生活号接入时不送 |
| | | // bizContent.setOpen_id(openid); |
| | | // bizContent.setIcbc_appid(icbcConfig.getAppId()); |
| | | // bizContent.setExpire_time(icbcConfig.getExpireTime()); |
| | | // //通知类型,表示在交易处理完成后把交易结果通知商户的处理模式。取值“HS”:在交易完成后将通知信息,主动发送给商户,发送地址为notify_url指定地址; 取值“AG”:在交易完成后不通知商户。不送或送空,默认为"HS" |
| | | // bizContent.setNotify_type("HS"); |
| | | // //结果发送类型,通知方式为HS时有效。取值“0”:无论支付成功或者失败,银行都向商户发送交易通知信息;取值“1”,银行只向商户发送交易成功的通知信息。默认是"0" |
| | | // bizContent.setResult_type("0"); |
| | | // CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1 request = new CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1(); |
| | | // request.setServiceUrl(icbcConfig.getApiPayUrl()); |
| | | // request.setBizContent(bizContent); |
| | | // DefaultIcbcClient client = IcbcConfig.getInstance(icbcConfig); |
| | | // CardbusinessAggregatepayB2cOnlineConsumepurchaseResponseV1 response; |
| | | // JSONObject responsePackage = new JSONObject(); |
| | | // try { |
| | | // log.info("准备调用工行支付成功,请求参数:{}", JSON.toJSONString(request)); |
| | | // response = client.execute(request); |
| | | // if (response.isSuccess()) { |
| | | // log.info("调用工行支付成功,返回信息:{}", JSON.toJSONString(response)); |
| | | // responsePackage = JSONObject.parseObject(response.getWx_data_package()); |
| | | // } else { |
| | | // log.info("调用工行支付失败,返回信息:{}", JSON.toJSONString(response)); |
| | | // throw new ServiceException(ICBCRespOrderErrorEnum.fromCode(String.valueOf(response.getReturnCode())).getErrorMsg()); |
| | | // } |
| | | // } catch (IcbcApiException e) { |
| | | // log.error(e.toString(), e); |
| | | // } |
| | | // return responsePackage; |
| | | // } |
| | | // |
| | | //} |
| | | package com.ruoyi.system.utils; |
| | | |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.icbc.api.DefaultIcbcClient; |
| | | import com.icbc.api.IcbcApiException; |
| | | import com.icbc.api.request.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1; |
| | | import com.icbc.api.response.CardbusinessAggregatepayB2cOnlineConsumepurchaseResponseV1; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.DateUtils; |
| | | import com.ruoyi.common.utils.WebUtils; |
| | | import com.ruoyi.common.utils.ip.IpUtils; |
| | | import com.ruoyi.system.config.ICBCConfig; |
| | | import com.ruoyi.system.enums.ICBCRespOrderErrorEnum; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Slf4j |
| | | @Component |
| | | public class ICBCPayUtil { |
| | | |
| | | @Autowired |
| | | private ICBCConfig icbcConfig; |
| | | |
| | | public JSONObject wechatPay(String outTradeNo, BigDecimal totalPrice, String goodsName,String openid, String notifyUrl){ |
| | | CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz bizContent = new |
| | | CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz(); |
| | | bizContent.setMer_id(icbcConfig.getMerId()); |
| | | bizContent.setMer_prtcl_no(icbcConfig.getMerPrtclNo()); |
| | | bizContent.setDecive_info(icbcConfig.getDeciveInfo()); |
| | | bizContent.setOut_trade_no(outTradeNo); |
| | | bizContent.setOrig_date_time(DateUtils.getCurrentDateTimeWithT()); |
| | | //交易币种,目前工行只支持使用人民币(001)支付 |
| | | bizContent.setFee_type("001"); |
| | | bizContent.setSpbill_create_ip(IpUtils.getIpAddr(WebUtils.request())); |
| | | //金额,单位分 |
| | | bizContent.setTotal_fee(String.valueOf(totalPrice.multiply(new BigDecimal(100)).intValue())); |
| | | //支付成功后回调url |
| | | bizContent.setMer_url(notifyUrl); |
| | | bizContent.setBody(goodsName); |
| | | //收单接入方式,5-APP,7-微信公众号,8-支付宝生活号,9-微信小程序 |
| | | bizContent.setAccess_type("9"); |
| | | //支付方式,9-微信;10-支付宝; |
| | | bizContent.setPay_mode("9"); |
| | | //商户在微信开放平台注册的APPID,支付方式为微信时不能为空 |
| | | bizContent.setShop_appid(icbcConfig.getWxAppId()); |
| | | //第三方用户标识,商户在微信公众号内或微信小程序内接入时必送,即access_type为7或9时,上送用户在商户APPID下的唯一标识;商户通过支付宝生活号接入时不送 |
| | | bizContent.setOpen_id(openid); |
| | | bizContent.setIcbc_appid(icbcConfig.getAppId()); |
| | | bizContent.setExpire_time(icbcConfig.getExpireTime()); |
| | | //通知类型,表示在交易处理完成后把交易结果通知商户的处理模式。取值“HS”:在交易完成后将通知信息,主动发送给商户,发送地址为notify_url指定地址; 取值“AG”:在交易完成后不通知商户。不送或送空,默认为"HS" |
| | | bizContent.setNotify_type("HS"); |
| | | //结果发送类型,通知方式为HS时有效。取值“0”:无论支付成功或者失败,银行都向商户发送交易通知信息;取值“1”,银行只向商户发送交易成功的通知信息。默认是"0" |
| | | bizContent.setResult_type("0"); |
| | | CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1 request = new CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1(); |
| | | request.setServiceUrl(icbcConfig.getApiPayUrl()); |
| | | request.setBizContent(bizContent); |
| | | DefaultIcbcClient client = ICBCConfig.getInstance(icbcConfig); |
| | | CardbusinessAggregatepayB2cOnlineConsumepurchaseResponseV1 response; |
| | | JSONObject responsePackage = new JSONObject(); |
| | | try { |
| | | log.info("准备调用工行支付成功,请求参数:{}", JSON.toJSONString(request)); |
| | | response = client.execute(request); |
| | | if (response.isSuccess()) { |
| | | log.info("调用工行支付成功,返回信息:{}", JSON.toJSONString(response)); |
| | | responsePackage = JSONObject.parseObject(response.getWx_data_package()); |
| | | } else { |
| | | log.info("调用工行支付失败,返回信息:{}", JSON.toJSONString(response)); |
| | | throw new ServiceException(ICBCRespOrderErrorEnum.fromCode(String.valueOf(response.getReturnCode())).getErrorMsg()); |
| | | } |
| | | } catch (IcbcApiException e) { |
| | | log.error(e.toString(), e); |
| | | } |
| | | return responsePackage; |
| | | } |
| | | |
| | | } |