Merge remote-tracking branch 'origin/master'

This commit is contained in:
zjf committed 2025-01-08 16:30:00 +08:00
commit a7ab8dcf99
29 files changed
+653 -65

No files matched your search

+24 -22
View File
@@ -324,28 +324,30 @@ create table wallet_recharge_package
DROP TABLE IF EXISTS wallet_recharge;
create table wallet_recharge
(
id bigint NOT NULL COMMENT '编号',
wallet_id bigint NOT NULL COMMENT '会员钱包 id',
total_price int NOT NULL COMMENT '用户实际到账余额,例如充 100 送 20,则该值是 120',
pay_price int NOT NULL COMMENT '实际支付金额',
bonus_price int NOT NULL COMMENT '钱包赠送金额',
package_id bigint NULL COMMENT '充值套餐编号',
pay_status bit default b'0' NOT NULL COMMENT '是否已支付:[0:未支付 1:已经支付过]',
pay_order_id bigint NULL COMMENT '支付订单编号',
pay_channel_code varchar(16) NULL COMMENT '支付成功的支付渠道',
pay_time datetime NULL COMMENT '订单支付时间',
pay_refund_id bigint NULL COMMENT '支付退款单编号',
refund_total_price int default 0 NOT NULL COMMENT '退款金额,包含赠送金额',
refund_pay_price int default 0 NOT NULL COMMENT '退款支付金额',
refund_bonus_price int default 0 NOT NULL COMMENT '退款钱包赠送金额',
refund_time datetime NULL COMMENT '退款时间',
refund_status int default 0 NOT NULL COMMENT '退款状态',
create_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
create_time datetime DEFAULT NULL COMMENT '创建时间',
update_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '修改人',
update_time datetime DEFAULT NULL COMMENT '修改时间',
del_flag char(1) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标记',
tenant_id bigint DEFAULT NULL COMMENT '租户ID',
id bigint NOT NULL COMMENT '编号',
wallet_id bigint NOT NULL COMMENT '会员钱包 id',
total_price int NOT NULL COMMENT '用户实际到账余额,例如充 100 送 20,则该值是 120',
pay_price int NOT NULL COMMENT '实际支付金额',
bonus_price int NOT NULL COMMENT '钱包赠送金额',
package_id bigint NULL COMMENT '充值套餐编号',
pay_status bit default b'0' NOT NULL COMMENT '是否已支付:[0:未支付 1:已经支付过]',
pay_order_id bigint NULL COMMENT '支付订单编号',
pay_channel_code varchar(16) NULL COMMENT '支付成功的支付渠道',
pay_time datetime NULL COMMENT '订单支付时间',
pay_refund_order_id bigint NULL COMMENT '退款订单号',
pay_refund_after_sale_id bigint NULL COMMENT '售后单号id',
pay_refund_code varchar(256) NULL COMMENT '支付退款单code',
refund_total_price int default 0 NOT NULL COMMENT '退款金额,包含赠送金额',
refund_pay_price int default 0 NOT NULL COMMENT '退款支付金额',
refund_bonus_price int default 0 NOT NULL COMMENT '退款钱包赠送金额',
refund_time datetime NULL COMMENT '退款时间',
refund_status char(10) default '0' NOT NULL COMMENT '退款状态',
create_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
create_time datetime DEFAULT NULL COMMENT '创建时间',
update_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '修改人',
update_time datetime DEFAULT NULL COMMENT '修改时间',
del_flag char(1) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标记',
tenant_id bigint DEFAULT NULL COMMENT '租户ID',
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4 COMMENT ='会员钱包充值';
@@ -5,6 +5,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
/**
* 硬件订单类型
@@ -25,4 +26,10 @@ public enum HardOrderTypeEnum {
return Arrays.stream(values()).filter(v -> ObjectUtil.equals(type, v.getType())).findFirst().get();
}
public static final List<HardOrderTypeEnum> refundList = List.of(BELOW, RESERVE);
public static boolean isRefund(HardOrderTypeEnum type) {
return refundList.contains(type);
}
}
@@ -0,0 +1,26 @@
package com.bsd.pjcloud.hard.api.constant.refund;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 硬件售后操作类型的枚举
*/
@AllArgsConstructor
@Getter
public enum HardAfterSaleOperateTypeEnum {
MEMBER_CREATE("10", "会员申请退款"),
ADMIN_AGREE_APPLY("11", "商家同意退款"),
ADMIN_DISAGREE_APPLY("12", "商家拒绝退款"),
MEMBER_DELIVERY("20", "会员填写退货物流信息,快递公司:{deliveryName},快递单号:{logisticsNo}"),
ADMIN_AGREE_RECEIVE("21", "商家收货"),
ADMIN_DISAGREE_RECEIVE("22", "商家拒绝收货,原因:{reason}"),
ADMIN_REFUND("30", "商家退款"),
MEMBER_CANCEL("40", "会员取消退款"),
;
private final String type;
private final String content;
}
@@ -0,0 +1,16 @@
package com.bsd.pjcloud.hard.api.constant.refund;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public enum HardRefundStatusEnum {
NONE("0", "未售后"),
APPLY("10", "售后中"),
SUCCESS("20", "售后成功"),
REJECT("30", "售后失败"),
;
private final String status;
private final String name;
}
@@ -0,0 +1,35 @@
package com.bsd.pjcloud.hard.api.constant.refund;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Collection;
import java.util.Collections;
@AllArgsConstructor
@Getter
public enum HardSaleStatusEnum {
/**
* 【申请售后】
*/
APPLY("10", "申请中", "会员申请退款"), // 有赞的状态提示:退款申请待商家处理
/**
* 完成退款【退款成功】
*/
COMPLETE("50", "完成", "商家确认退款"), // 有赞的状态提示:退款成功
/**
* 【买家取消】
*/
BUYER_CANCEL("61", "买家取消售后", "会员取消退款"), // 有赞的状态提示:退款关闭
/**
* 卖家拒绝售后;商家拒绝【商家拒绝】
*/
SELLER_DISAGREE("62", "卖家拒绝", "商家拒绝退款"), // 有赞的状态提示:商家不同意退款申请
;
public static final Collection<String> APPLYING_STATUSES = Collections.singletonList(APPLY.getStatus());
private final String status;
private final String name;
private final String content;
}
@@ -0,0 +1,14 @@
package com.bsd.pjcloud.hard.api.dto.order;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class HardDisagreeDto {
@NotNull(message = "售后编号不能为空")
private Long id;
@NotEmpty(message = "审批备注不能为空")
private String auditReason;
}
@@ -3,8 +3,7 @@ package com.bsd.pjcloud.hard.api.entity.order;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.*;
import com.bsd.pjcloud.common.core.util.TenantTable;
import java.time.LocalDateTime;
@@ -14,6 +13,9 @@ import java.time.LocalDateTime;
* @author dzc
* @date 2025-01-07 17:23:08
*/
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@TenantTable
@TableName("hard_after_sale")
@@ -3,8 +3,7 @@ package com.bsd.pjcloud.hard.api.entity.order;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.*;
import com.bsd.pjcloud.common.core.util.TenantTable;
import java.time.LocalDateTime;
@@ -14,6 +13,9 @@ import java.time.LocalDateTime;
* @author dzc
* @date 2025-01-07 17:23:25
*/
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@TenantTable
@TableName("hard_after_sale_log")
@@ -1,8 +1,25 @@
package com.bsd.pjcloud.hard.api.vo.order;
import com.bsd.pjcloud.admin.api.vo.base.BaseDeptInterface;
import com.bsd.pjcloud.admin.api.vo.base.BaseUserInterface;
import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleEntity;
import lombok.Data;
@Data
public class HardAfterSaleVo extends HardAfterSaleEntity {
public class HardAfterSaleVo extends HardAfterSaleEntity implements BaseUserInterface, BaseDeptInterface {
/**
* 用户相关
*/
private String username;
private String userMobile;
private String userAvatar;
/**
* 部门相关
*/
private Long deptId;
private String deptName;
}
@@ -1,8 +1,23 @@
package com.bsd.pjcloud.hard.api.vo.order;
import com.bsd.pjcloud.admin.api.vo.base.BaseDeptInterface;
import com.bsd.pjcloud.admin.api.vo.base.BaseUserInterface;
import com.bsd.pjcloud.hard.api.entity.order.HardOrderEntity;
import lombok.Data;
@Data
public class HardOrderVo extends HardOrderEntity {
public class HardOrderVo extends HardOrderEntity implements BaseUserInterface, BaseDeptInterface {
/**
* 用户相关
*/
private String username;
private String userMobile;
private String userAvatar;
/**
* 部门相关
*/
private String deptName;
}
@@ -116,6 +116,12 @@
<version>5.7.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.seata</groupId>
<artifactId>seata-all</artifactId>
<version>2.1.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<profiles>
<profile>
@@ -7,9 +7,14 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.common.security.service.PjcloudUser;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import com.bsd.pjcloud.hard.api.dto.order.HardAfterSaleDto;
import com.bsd.pjcloud.hard.api.dto.order.HardDisagreeDto;
import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleEntity;
import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleLogEntity;
import com.bsd.pjcloud.hard.service.HardAfterSaleService;
import io.swagger.v3.oas.annotations.Parameter;
import org.springframework.security.access.prepost.PreAuthorize;
import com.bsd.pjcloud.common.excel.annotation.ResponseExcel;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
@@ -31,63 +36,83 @@ import java.util.Objects;
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/hard-after-sale" )
@Tag(description = "hard-after-sale" , name = "售后订单管理" )
@RequestMapping("/hard-after-sale")
@Tag(description = "hard-after-sale", name = "售后订单管理")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class HardAfterSaleController {
private final HardAfterSaleService hardAfterSaleService;
@Operation(summary = "分页查询" , description = "分页查询" )
@GetMapping("/page" )
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_view')" )
@GetMapping(value = "/history")
@Operation(summary = "查询售后进度")
public R<List<HardAfterSaleLogEntity>> history(@RequestParam Long id) {
return R.ok(hardAfterSaleService.getHistory(id));
}
@PutMapping("/agree")
@Operation(summary = "同意售后")
public R<Boolean> agreeRefund(@RequestParam Long id) {
PjcloudUser user = SecurityUtils.getUser();
return R.ok(hardAfterSaleService.agreeAfterSale(user.getId(), id));
}
@PutMapping("/disagree")
@Operation(summary = "拒绝售后")
public R<Boolean> disagreeRefund(@RequestBody HardDisagreeDto dto) {
PjcloudUser user = SecurityUtils.getUser();
return R.ok(hardAfterSaleService.disagreeRefund(user.getId(), dto));
}
@Operation(summary = "分页查询", description = "分页查询")
@GetMapping("/page")
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_view')")
public R getHardAfterSalePage(@ParameterObject Page page, @ParameterObject HardAfterSaleEntity hardAfterSale) {
LambdaQueryWrapper<HardAfterSaleEntity> wrapper = Wrappers.lambdaQuery();
return R.ok(hardAfterSaleService.page(page, wrapper));
}
@Operation(summary = "分页复杂查询" , description = "分页复杂查询" )
@GetMapping("/page-join" )
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_view')" )
@Operation(summary = "分页复杂查询", description = "分页复杂查询")
@GetMapping("/page-join")
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_view')")
public R pageJoin(@ParameterObject Page page, @ParameterObject HardAfterSaleDto dto) {
return R.ok(hardAfterSaleService.pageJoin(page, dto));
}
@Operation(summary = "通过id查询" , description = "通过id查询" )
@GetMapping("/{id}" )
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_view')" )
public R getById(@PathVariable("id" ) Long id) {
@Operation(summary = "通过id查询", description = "通过id查询")
@GetMapping("/{id}")
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_view')")
public R getById(@PathVariable("id") Long id) {
return R.ok(hardAfterSaleService.getById(id));
}
@Operation(summary = "新增售后订单" , description = "新增售后订单" )
@SysLog("新增售后订单" )
@Operation(summary = "新增售后订单", description = "新增售后订单")
@SysLog("新增售后订单")
@PostMapping
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_add')" )
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_add')")
public R save(@RequestBody HardAfterSaleEntity hardAfterSale) {
return R.ok(hardAfterSaleService.save(hardAfterSale));
}
@Operation(summary = "修改售后订单" , description = "修改售后订单" )
@SysLog("修改售后订单" )
@Operation(summary = "修改售后订单", description = "修改售后订单")
@SysLog("修改售后订单")
@PutMapping
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_edit')" )
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_edit')")
public R updateById(@RequestBody HardAfterSaleEntity hardAfterSale) {
return R.ok(hardAfterSaleService.updateById(hardAfterSale));
}
@Operation(summary = "通过id删除售后订单" , description = "通过id删除售后订单" )
@SysLog("通过id删除售后订单" )
@Operation(summary = "通过id删除售后订单", description = "通过id删除售后订单")
@SysLog("通过id删除售后订单")
@DeleteMapping
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_del')" )
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_del')")
public R removeById(@RequestBody Long[] ids) {
return R.ok(hardAfterSaleService.removeBatchByIds(CollUtil.toList(ids)));
}
@ResponseExcel
@GetMapping("/export")
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_export')" )
public List<HardAfterSaleEntity> export(HardAfterSaleEntity hardAfterSale,Long[] ids) {
@PreAuthorize("@pms.hasPermission('hard_hardAfterSale_export')")
public List<HardAfterSaleEntity> export(HardAfterSaleEntity hardAfterSale, Long[] ids) {
return hardAfterSaleService.list(Wrappers.lambdaQuery(hardAfterSale).in(ArrayUtil.isNotEmpty(ids), HardAfterSaleEntity::getId, ids));
}
}
@@ -3,10 +3,45 @@ package com.bsd.pjcloud.hard.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bsd.pjcloud.hard.api.dto.order.HardAfterSaleDto;
import com.bsd.pjcloud.hard.api.dto.order.HardDisagreeDto;
import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleEntity;
import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleLogEntity;
import com.bsd.pjcloud.hard.api.vo.order.HardAfterSaleVo;
import java.util.List;
public interface HardAfterSaleService extends IService<HardAfterSaleEntity> {
Page<HardAfterSaleVo> pageJoin(Page page, HardAfterSaleDto dto);
/**
* 获取售后进度
*
* @param id 售后id
*/
List<HardAfterSaleLogEntity> getHistory(Long id);
/**
* 退款
*
* @param afterSaleId 售后id
*/
void refund(Long afterSaleId);
/**
* 同意售后
*
* @param userId 用户id
* @param id
*/
Boolean agreeAfterSale(Long userId, Long id);
/**
* 拒绝售后
*
* @param userId 用户id
* @param dto
* @return
*/
Boolean disagreeRefund(Long userId, HardDisagreeDto dto);
}
@@ -1,13 +1,49 @@
package com.bsd.pjcloud.hard.service.impl.order;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.admin.api.entity.SysDept;
import com.bsd.pjcloud.admin.api.entity.SysUser;
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
import com.bsd.pjcloud.admin.api.utils.DataUtil;
import com.bsd.pjcloud.common.core.util.BeanUtils;
import com.bsd.pjcloud.common.core.util.CollectionUtils;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum;
import com.bsd.pjcloud.hard.api.constant.order.HardOrderTypeEnum;
import com.bsd.pjcloud.hard.api.constant.refund.HardAfterSaleOperateTypeEnum;
import com.bsd.pjcloud.hard.api.constant.refund.HardRefundStatusEnum;
import com.bsd.pjcloud.hard.api.constant.refund.HardSaleStatusEnum;
import com.bsd.pjcloud.hard.api.dto.order.HardAfterSaleDto;
import com.bsd.pjcloud.hard.api.dto.order.HardDisagreeDto;
import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleEntity;
import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleLogEntity;
import com.bsd.pjcloud.hard.api.entity.order.HardOrderEntity;
import com.bsd.pjcloud.hard.api.vo.order.HardAfterSaleVo;
import com.bsd.pjcloud.hard.api.vo.order.HardOrderVo;
import com.bsd.pjcloud.hard.mapper.order.HardAfterSaleLogMapper;
import com.bsd.pjcloud.hard.mapper.order.HardAfterSaleMapper;
import com.bsd.pjcloud.hard.service.HardAfterSaleService;
import com.bsd.pjcloud.hard.service.HardOrderService;
import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeRefundDto;
import com.bsd.pjcloud.wallet.api.feign.RemoteWalletRechargeService;
import com.bsd.pjcloud.wallet.api.vo.recharge.WalletRechargeVo;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* 售后订单
@@ -15,11 +51,158 @@ import org.springframework.stereotype.Service;
* @author dzc
* @date 2025-01-07 17:23:08
*/
@Validated
@Slf4j
@RequiredArgsConstructor
@Service
public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, HardAfterSaleEntity> implements HardAfterSaleService {
private final HardAfterSaleLogMapper hardAfterSaleLogMapper;
private final HardOrderService hardOrderService;
private final RemoteUserService userService;
private final RemoteDeptService deptService;
private final RemoteWalletRechargeService walletRechargeService;
@Override
public Page<HardAfterSaleVo> pageJoin(Page page, HardAfterSaleDto dto) {
return baseMapper.pageJoin(page, dto);
Page<HardAfterSaleVo> list = baseMapper.pageJoin(page, dto);
if (ObjectUtil.isNotEmpty(list.getRecords())) {
// 用户
List<Long> userIds = list.getRecords().stream().map(HardAfterSaleVo::getUserId).distinct().toList();
R<List<SysUser>> userList = userService.getUserById(new ArrayList<>(userIds));
if (ObjectUtil.isNotEmpty(userList.getData())) {
DataUtil.convertUserList(list.getRecords(), CollectionUtils.convertMap(userList.getData(), SysUser::getUserId));
}
// 部门
List<Long> deptIds = list.getRecords().stream().map(HardAfterSaleVo::getDeptId).distinct().toList();
R<Map<Long, SysDept>> deptList = deptService.getDeptByDeptIds(deptIds);
if (ObjectUtil.isNotEmpty(deptList.getData())) {
DataUtil.convertDeptList(list.getRecords(), deptList.getData());
}
}
return list;
}
@Override
public List<HardAfterSaleLogEntity> getHistory(Long id) {
return hardAfterSaleLogMapper.selectList(new LambdaQueryWrapper<HardAfterSaleLogEntity>()
.eq(HardAfterSaleLogEntity::getAfterSaleId, id)
);
}
@Override
@GlobalTransactional
@Transactional(rollbackFor = Exception.class)
public void refund(Long afterSaleId) {
HardAfterSaleEntity afterSale = baseMapper.selectById(afterSaleId);
if (ObjectUtil.isEmpty(afterSale)) throw new RuntimeException("售后订单不存在");
// 校验订单是否可以退款
HardOrderVo order = validateOrderCanRefund(afterSale.getOrderId());
// 生成退款单号
String refundCode = "hard_" + order.getId();
// 创建退款单
WalletRechargeRefundDto hardRefundDto = WalletRechargeRefundDto.builder().orderId(order.getId()).afterSaleId(afterSale.getId()).refundCode(refundCode).reason("订单退款").price(order.getPayPrice()).build();
R<WalletRechargeVo> walletRefundResult = walletRechargeService.refund(hardRefundDto);
WalletRechargeVo walletRefund = Optional.of(walletRefundResult).map(R::getData).orElseThrow(() -> new RuntimeException("钱包退款错误"));
HardOrderEntity updateObj = HardOrderEntity.builder()
.id(order.getId())
.orderStatus(HardOrderStatusEnum.REFUND.getType())
.refundStatus(HardRefundStatusEnum.SUCCESS.getStatus())
.payRefundId(walletRefund.getId())
.refundPrice(order.getPayPrice())
.refundTime(LocalDateTime.now())
.build();
hardOrderService.updateById(updateObj);
}
@Override
public Boolean agreeAfterSale(Long userId, Long id) {
HardAfterSaleEntity afterSale = validateAfterSaleAuditable(id);
HardOrderEntity order = hardOrderService.getById(afterSale.getOrderId());
if (order == null) throw new RuntimeException("设备订单不存在");
// 更新售后单的状态
HardAfterSaleEntity updateRefundObj = HardAfterSaleEntity.builder()
.id(id)
.status(HardSaleStatusEnum.COMPLETE.getStatus())
.auditUserId(userId)
.auditTime(LocalDateTime.now())
.build();
baseMapper.updateById(updateRefundObj);
// 记录售后日志
HardAfterSaleLogEntity saveLogObj = HardAfterSaleLogEntity.builder()
.afterSaleId(afterSale.getId())
.userId(userId)
.operateType(HardAfterSaleOperateTypeEnum.ADMIN_AGREE_APPLY.getType())
.beforeStatus(order.getOrderStatus())
.afterStatus(order.getOrderStatus())
.content(HardSaleStatusEnum.COMPLETE.getContent())
.build();
hardAfterSaleLogMapper.insert(saveLogObj);
// 执行退款
getSelf().refund(updateRefundObj.getId());
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean disagreeRefund(Long userId, HardDisagreeDto dto) {
HardAfterSaleEntity afterSale = validateAfterSaleAuditable(dto.getId());
HardOrderEntity order = hardOrderService.getById(afterSale.getOrderId());
if (order == null) throw new RuntimeException("设备订单不存在");
// 更新售后单的状态
HardAfterSaleEntity updateRefundObj = HardAfterSaleEntity.builder()
.id(dto.getId())
.status(HardSaleStatusEnum.SELLER_DISAGREE.getStatus())
.auditUserId(userId)
.auditTime(LocalDateTime.now())
.applyReason(dto.getAuditReason())
.build();
baseMapper.updateById(updateRefundObj);
// 记录售后日志
HardAfterSaleLogEntity saveLogObj = HardAfterSaleLogEntity.builder()
.afterSaleId(afterSale.getId())
.userId(userId)
.operateType(HardAfterSaleOperateTypeEnum.ADMIN_DISAGREE_APPLY.getType())
.beforeStatus(order.getOrderStatus())
.afterStatus(order.getOrderStatus())
.content(HardSaleStatusEnum.SELLER_DISAGREE.getContent())
.build();
hardAfterSaleLogMapper.insert(saveLogObj);
// 更新交易订单项的售后状态为【售后失败】
HardOrderEntity updateOrderObj = HardOrderEntity.builder().id(order.getId()).refundStatus(HardRefundStatusEnum.REJECT.getStatus()).refundTime(LocalDateTime.now()).build();
hardOrderService.updateById(updateOrderObj);
return true;
}
// 校验订单是否可以退款
private HardOrderVo validateOrderCanRefund(Long orderId) {
HardOrderEntity order = hardOrderService.getById(orderId);
if (ObjectUtil.isEmpty(order)) throw new RuntimeException("示例订单不存在");
HardOrderVo orderVo = BeanUtils.toBean(order, HardOrderVo.class);
// 检查是否可以退款
HardOrderTypeEnum orderTypeEnum = HardOrderTypeEnum.valueOfByType(order.getOrderType());
if (HardOrderTypeEnum.isRefund(orderTypeEnum)) {
throw new RuntimeException("该订单类型不支持退款");
}
// 校验订单是否已退款
if (ObjectUtil.isNotEmpty(order.getPayRefundId())) {
throw new RuntimeException("发起退款失败,示例订单已退款");
}
return orderVo;
}
private HardAfterSaleEntity validateAfterSaleAuditable(Long id) {
HardAfterSaleEntity afterSale = baseMapper.selectById(id);
if (afterSale == null) throw new RuntimeException("售后单不存在");
if (ObjectUtil.notEqual(afterSale.getStatus(), HardSaleStatusEnum.APPLY.getStatus())) {
throw new RuntimeException("审批失败,售后状态不处于审批中");
}
return afterSale;
}
private HardAfterSaleServiceImpl getSelf() {
return SpringUtil.getBean(getClass());
}
}
@@ -5,10 +5,8 @@ import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.canteen.api.feign.RemoteCanteenSpuService;
import com.bsd.pjcloud.canteen.api.feign.RemoteOnlineCanteenSpuService;
import com.bsd.pjcloud.canteen.entity.CanteenOnlineSpuEntity;
import com.bsd.pjcloud.canteen.entity.CanteenSpuEntity;
import com.bsd.pjcloud.common.core.util.BeanUtils;
import com.bsd.pjcloud.hard.api.constant.HardTypeEnum;
import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum;
@@ -110,7 +108,7 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
return switch (sysType) {
case CANTEEN -> {
// 查询食堂商品
List<CanteenOnlineSpuEntity> supList = onlineCanteenSpuService.getSpuListByIds(productIds).getData();
List<CanteenOnlineSpuEntity> supList = onlineCanteenSpuService.getSpuListByIds(productIds).getData();
AtomicInteger canteenTotalPrice = new AtomicInteger();
for (HardCreateCarDto v : list) {
supList.stream().filter(i -> ObjectUtil.equals(i.getId(), v.getProductId())).findFirst().ifPresent(spu -> {
@@ -3,7 +3,13 @@ package com.bsd.pjcloud.hard.service.impl.order;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.admin.api.entity.SysDept;
import com.bsd.pjcloud.admin.api.entity.SysUser;
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
import com.bsd.pjcloud.admin.api.utils.DataUtil;
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
import com.bsd.pjcloud.common.core.util.CollectionUtils;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.hard.api.constant.HardTypeEnum;
import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum;
@@ -31,6 +37,7 @@ import com.bsd.pjcloud.wallet.api.entity.WalletTransactionEntity;
import com.bsd.pjcloud.wallet.api.feign.*;
import com.bsd.pjcloud.wallet.api.vo.MchManageVo;
import com.bsd.pjcloud.wallet.api.vo.WalletSettingVo;
import com.bsd.pjcloud.wallet.api.vo.recharge.WalletRechargeApplyVo;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -43,6 +50,7 @@ import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
@@ -67,10 +75,27 @@ public class HardwareOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardO
private final RemoteWalletService remoteWalletService;
private final RemoteWalletTransactionService walletTransactionService;
private final RemoteWalletSettingService walletSettingService;
private final RemoteUserService userService;
private final RemoteDeptService deptService;
@Override
public Page<HardOrderVo> pageJoin(Page page, HardOrderDto dto) {
return baseMapper.pageJoin(page, dto);
Page<HardOrderVo> list = baseMapper.pageJoin(page, dto);
if (ObjectUtil.isNotEmpty(list.getRecords())) {
// 用户
List<Long> userIds = list.getRecords().stream().map(HardOrderVo::getUserId).distinct().toList();
R<List<SysUser>> userList = userService.getUserById(new ArrayList<>(userIds));
if (ObjectUtil.isNotEmpty(userList.getData())) {
DataUtil.convertUserList(list.getRecords(), CollectionUtils.convertMap(userList.getData(), SysUser::getUserId));
}
// 部门
List<Long> deptIds = list.getRecords().stream().map(HardOrderVo::getDeptId).distinct().toList();
R<Map<Long, SysDept>> deptList = deptService.getDeptByDeptIds(deptIds);
if (ObjectUtil.isNotEmpty(deptList.getData())) {
DataUtil.convertDeptList(list.getRecords(), deptList.getData());
}
}
return list;
}
@Override
@@ -0,0 +1,17 @@
package com.bsd.pjcloud.wallet.api.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum WalletRefundStatusEnum {
WAITING("0", "未退款"),
SUCCESS("10", "退款成功"),
FAILURE("20", "退款失败"),
;
private final String status;
private final String name;
}
@@ -0,0 +1,37 @@
package com.bsd.pjcloud.wallet.api.dto.recharge;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class WalletRechargeRefundDto {
@NotNull(message = "钱包id不能为空")
private Long walletId;
@NotNull(message = "订单编号不能为空")
private Long orderId;
@NotNull(message = "售后订单id不能为空")
private Long afterSaleId;
@NotEmpty(message = "退款code不能为空")
private String refundCode;
@NotEmpty(message = "退款描述不能为空")
@Length(max = 128, message = "退款描述长度不能超过 128")
private String reason;
@NotNull(message = "退款金额不能为空")
@Min(value = 1, message = "退款金额必须大于零")
private Integer price;
}
@@ -79,10 +79,22 @@ public class WalletRechargeEntity extends Model<WalletRechargeEntity> {
private LocalDateTime payTime;
/**
* 支付退款单编号
* 退款订单号
*/
@Schema(description = "支付退款单编号")
private Long payRefundId;
@Schema(description = "退款订单号")
private Long payRefundOrderId;
/**
* 售后单号
*/
@Schema(description = "售后单号")
private Long payRefundAfterSaleId;
/**
* 支付退款单code
*/
@Schema(description = "支付退款单code")
private String payRefundCode;
/**
* 退款金额,包含赠送金额
@@ -112,7 +124,7 @@ public class WalletRechargeEntity extends Model<WalletRechargeEntity> {
* 退款状态
*/
@Schema(description = "退款状态")
private Integer refundStatus;
private String refundStatus;
/**
* 创建人
@@ -0,0 +1,23 @@
package com.bsd.pjcloud.wallet.api.feign;
import com.bsd.pjcloud.common.core.constant.ServiceNameConstants;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeRefundDto;
import com.bsd.pjcloud.wallet.api.vo.recharge.WalletRechargeVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(contextId = "remoteWalletRechargeService", value = ServiceNameConstants.WALLET_SERVICE)
public interface RemoteWalletRechargeService {
/**
* 退款
*
* @param dto
* @return
*/
@PostMapping("/wallet-recharge/refund")
R<WalletRechargeVo> refund(@RequestBody WalletRechargeRefundDto dto);
}
@@ -5,7 +5,6 @@ import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.feign.annotation.NoToken;
import com.bsd.pjcloud.wallet.api.dto.WalletBalanceTransactionDto;
import com.bsd.pjcloud.wallet.api.entity.WalletTransactionEntity;
import com.bsd.pjcloud.wallet.api.vo.WalletSettingVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -1,5 +1,6 @@
com.bsd.pjcloud.wallet.api.feign.RemoteWalletService
com.bsd.pjcloud.wallet.api.feign.RemoteCodeUseService
com.bsd.pjcloud.wallet.api.feign.RemoteWalletRechargeService
com.bsd.pjcloud.wallet.api.feign.RemoteMchService
com.bsd.pjcloud.wallet.api.feign.RemoteWalletSettingService
com.bsd.pjcloud.wallet.api.feign.RemoteWalletTransactionService
@@ -8,9 +8,12 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeDto;
import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeRefundDto;
import com.bsd.pjcloud.wallet.api.dto.recharge.app.WalletAppRechargeDto;
import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargeEntity;
import com.bsd.pjcloud.wallet.api.vo.recharge.WalletRechargeVo;
import com.bsd.pjcloud.wallet.service.WalletRechargeService;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import com.bsd.pjcloud.common.excel.annotation.ResponseExcel;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
@@ -38,6 +41,14 @@ public class WalletRechargeController {
private final WalletRechargeService walletRechargeService;
/* ************************************* start 远程调用 start ************************************* */
@Operation(summary = "远程调用-退款", description = "远程调用-退款")
@PostMapping("/refund")
public R<WalletRechargeVo> refund(@Valid @RequestBody WalletRechargeRefundDto dto) {
return R.ok(walletRechargeService.refund(dto));
}
/* ************************************* end 远程调用 end ************************************* */
/* ************************************* start app start ************************************* */
@Operation(summary = "模拟充值", description = "模拟充值")
@PostMapping("/app/create")
@@ -14,6 +14,12 @@ import org.apache.ibatis.annotations.Param;
@Mapper
public interface WalletManageMapper extends PjcloudBaseMapper<WalletManageEntity> {
/**
* 当消费时候, 更新钱包
*
* @param id 钱包 id
* @param price 消费金额
*/
default int updateWhenConsumption(Long id, Integer price) {
LambdaUpdateWrapper<WalletManageEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<WalletManageEntity>()
.setSql(" balance = balance - " + price + ", total_expense = total_expense + " + price)
@@ -22,6 +28,25 @@ public interface WalletManageMapper extends PjcloudBaseMapper<WalletManageEntity
return update(null, lambdaUpdateWrapper);
}
/**
* 当消费退款时候, 更新钱包
*
* @param id 钱包 id
* @param price 消费金额
*/
default int updateWhenConsumptionRefund(Long id, Integer price) {
LambdaUpdateWrapper<WalletManageEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<WalletManageEntity>()
.setSql(" balance = balance + " + price + ", total_expense = total_expense - " + price)
.eq(WalletManageEntity::getId, id);
return update(null, lambdaUpdateWrapper);
}
/**
* 当充值的时候,更新钱包
*
* @param id 钱包 id
* @param price 钱包金额
*/
default int updateWhenRecharge(Long id, Integer price) {
LambdaUpdateWrapper<WalletManageEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<WalletManageEntity>()
.setSql(" balance = balance + " + price + ", total_recharge = total_recharge + " + price)
@@ -3,6 +3,7 @@ package com.bsd.pjcloud.wallet.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeDto;
import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeRefundDto;
import com.bsd.pjcloud.wallet.api.dto.recharge.app.WalletAppRechargeDto;
import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargeEntity;
import com.bsd.pjcloud.wallet.api.vo.recharge.WalletRechargeVo;
@@ -17,4 +18,18 @@ public interface WalletRechargeService extends IService<WalletRechargeEntity> {
* @return
*/
WalletRechargeEntity createWalletRecharge(WalletAppRechargeDto dto);
/**
* 远程调用-退款
* @param dto
* @return
*/
WalletRechargeVo refund(WalletRechargeRefundDto dto);
/**
* 根据退款id查询
* @return
*/
WalletRechargeEntity getByRefundId(Long refundId);
}
@@ -105,6 +105,9 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
walletManageMapper.updateWhenRecharge(wallet.getId(), price);
break;
}
case REFUND: {
walletManageMapper.updateWhenConsumptionRefund(wallet.getId(), price);
}
default: {
log.error("|{}|,钱包id({})使用未实现的增加钱包余额的类型({}).", TAG, walletId, bizType.getDesc());
throw new UnsupportedOperationException("待实现");
@@ -70,13 +70,13 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
List<Long> userIds = list.getRecords().stream().map(WalletRechargeApplyVo::getUserId).distinct().toList();
R<List<SysUser>> userList = userService.getUserById(new ArrayList<>(userIds));
if (ObjectUtil.isNotEmpty(userList.getData())) {
DataUtil.convertUserList(page.getRecords(), CollectionUtils.convertMap(userList.getData(), SysUser::getUserId));
DataUtil.convertUserList(list.getRecords(), CollectionUtils.convertMap(userList.getData(), SysUser::getUserId));
}
// 部门
List<Long> deptIds = list.getRecords().stream().map(WalletRechargeApplyVo::getDeptId).distinct().toList();
R<Map<Long, SysDept>> deptList = deptService.getDeptByDeptIds(deptIds);
if (ObjectUtil.isNotEmpty(deptList.getData())) {
DataUtil.convertDeptList(page.getRecords(), deptList.getData());
DataUtil.convertDeptList(list.getRecords(), deptList.getData());
}
}
return list;
@@ -1,16 +1,19 @@
package com.bsd.pjcloud.wallet.service.impl.recharge;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.common.core.util.BeanUtils;
import com.bsd.pjcloud.hard.api.constant.refund.HardRefundStatusEnum;
import com.bsd.pjcloud.wallet.api.constant.WalletBizEnum;
import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeDto;
import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeRefundDto;
import com.bsd.pjcloud.wallet.api.dto.recharge.app.WalletAppRechargeDto;
import com.bsd.pjcloud.wallet.api.entity.WalletManageEntity;
import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargeEntity;
import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargePackageEntity;
import com.bsd.pjcloud.wallet.api.vo.recharge.WalletRechargeVo;
import com.bsd.pjcloud.wallet.mapper.WalletManageMapper;
import com.bsd.pjcloud.wallet.mapper.recharge.WalletRechargeMapper;
import com.bsd.pjcloud.wallet.service.WalletManageService;
import com.bsd.pjcloud.wallet.service.WalletRechargePackageService;
@@ -23,6 +26,8 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
/**
* 会员钱包充值
@@ -67,4 +72,36 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
walletTransactionService.addWalletBalance(wallet.getId(), rechargeObj.getTotalPrice(), String.valueOf(rechargeObj.getId()), WalletBizEnum.RECHARGE);
return rechargeObj;
}
@Override
public WalletRechargeEntity getByRefundId(Long refundId) {
return baseMapper.selectOne(new LambdaQueryWrapper<WalletRechargeEntity>()
.eq(WalletRechargeEntity::getPayRefundOrderId, refundId)
);
}
@Override
@Transactional(rollbackFor = Exception.class)
public WalletRechargeVo refund(WalletRechargeRefundDto dto) {
// 查询钱包
WalletManageEntity wallet = walletManageService.getWallet(dto.getWalletId());
if (ObjectUtil.isEmpty(wallet)) throw new RuntimeException("用户钱包不存在");
WalletRechargeEntity refund = getByRefundId(dto.getOrderId());
if (ObjectUtil.isNotEmpty(refund)) throw new RuntimeException("已经存在退款单");
WalletRechargeEntity recharge = WalletRechargeEntity.builder()
.walletId(wallet.getId())
.payRefundCode(dto.getRefundCode())
.payRefundOrderId(dto.getAfterSaleId())
.payRefundAfterSaleId(dto.getAfterSaleId())
.refundPayPrice(dto.getPrice())
.refundBonusPrice(0)
.refundTotalPrice(dto.getPrice())
.refundStatus(HardRefundStatusEnum.SUCCESS.getStatus())
.refundTime(LocalDateTime.now())
.build();
baseMapper.insert(recharge);
// 增加金额
walletTransactionService.addWalletBalance(wallet.getId(), recharge.getTotalPrice(), String.valueOf(dto.getAfterSaleId()), WalletBizEnum.REFUND);
return BeanUtils.toBean(recharge, WalletRechargeVo.class);
}
}
@@ -13,7 +13,7 @@
<result property="payOrderId" column="pay_order_id"/>
<result property="payChannelCode" column="pay_channel_code"/>
<result property="payTime" column="pay_time"/>
<result property="payRefundId" column="pay_refund_id"/>
<result property="payRefundOrderId" column="pay_refund_id"/>
<result property="refundTotalPrice" column="refund_total_price"/>
<result property="refundPayPrice" column="refund_pay_price"/>
<result property="refundBonusPrice" column="refund_bonus_price"/>