31 changed files with 1122 additions and 90 deletions
@ -0,0 +1,204 @@ |
|||
package cc.hiver.mall.controller; |
|||
|
|||
import cc.hiver.core.common.utils.ResultUtil; |
|||
import cc.hiver.core.common.vo.Result; |
|||
import cc.hiver.mall.entity.MallSettlementRecord; |
|||
import cc.hiver.mall.entity.Shop; |
|||
import cc.hiver.mall.service.ShopService; |
|||
import cc.hiver.mall.service.mybatis.MallSettlementRecordService; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import io.swagger.annotations.Api; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
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 java.math.BigDecimal; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Slf4j |
|||
@RestController |
|||
@Api(tags = "后台管理系统结算记录接口") |
|||
@RequestMapping("/hiver/mall/admin/settlement") |
|||
public class AdminSettlementController { |
|||
|
|||
@Autowired |
|||
private MallSettlementRecordService mallSettlementRecordService; |
|||
|
|||
@Autowired |
|||
private ShopService shopService; |
|||
|
|||
@Data |
|||
public static class SettlementQuery { |
|||
private String shopId; |
|||
private Integer status; |
|||
private Integer type; |
|||
private int pageNumber = 1; |
|||
private int pageSize = 10; |
|||
} |
|||
|
|||
@PostMapping("/page") |
|||
@ApiOperation(value = "分页查询结算记录") |
|||
public Result<Page<MallSettlementRecord>> page(@RequestBody SettlementQuery query) { |
|||
LambdaQueryWrapper<MallSettlementRecord> qw = new LambdaQueryWrapper<>(); |
|||
if (StringUtils.isNotBlank(query.getShopId())) { |
|||
qw.eq(MallSettlementRecord::getShopId, query.getShopId()); |
|||
} |
|||
if (query.getStatus() != null) { |
|||
qw.eq(MallSettlementRecord::getStatus, query.getStatus()); |
|||
} |
|||
if (query.getType() != null) { |
|||
qw.eq(MallSettlementRecord::getType, query.getType()); |
|||
} |
|||
qw.orderByDesc(MallSettlementRecord::getCreateTime); |
|||
|
|||
Page<MallSettlementRecord> page = new Page<>(query.getPageNumber(), query.getPageSize()); |
|||
Page<MallSettlementRecord> result = mallSettlementRecordService.page(page, qw); |
|||
return new ResultUtil<Page<MallSettlementRecord>>().setData(result); |
|||
} |
|||
|
|||
@Data |
|||
public static class ConfirmReq { |
|||
private List<String> ids; |
|||
} |
|||
|
|||
@PostMapping("/confirm") |
|||
@ApiOperation(value = "每日结算确认(支持批量)") |
|||
public Result confirm(@RequestBody ConfirmReq req) { |
|||
if (req.getIds() == null || req.getIds().isEmpty()) { |
|||
return ResultUtil.error("请选择要确认的结算记录"); |
|||
} |
|||
try { |
|||
mallSettlementRecordService.confirmSettlements(req.getIds()); |
|||
return ResultUtil.success("结算确认成功"); |
|||
} catch (Exception e) { |
|||
log.error("结算确认失败: {}", e.getMessage(), e); |
|||
return ResultUtil.error("结算确认失败: " + e.getMessage()); |
|||
} |
|||
} |
|||
|
|||
@Data |
|||
public static class SummaryQuery { |
|||
@ApiModelProperty(value = "区域ID") |
|||
private String regionId; |
|||
@ApiModelProperty(value = "结算日期,格式yyyy-MM-dd") |
|||
private String settlementDate; |
|||
} |
|||
|
|||
@Data |
|||
public static class SettlementSummaryVo { |
|||
@ApiModelProperty(value = "商家ID") |
|||
private String shopId; |
|||
@ApiModelProperty(value = "商家名称") |
|||
private String shopName; |
|||
@ApiModelProperty(value = "扣除售后商家所得总额基数") |
|||
private BigDecimal totalBaseAmount; |
|||
@ApiModelProperty(value = "服务费总额") |
|||
private BigDecimal totalCommissionAmount; |
|||
@ApiModelProperty(value = "实际结算给商家的钱") |
|||
private BigDecimal totalSettlementAmount; |
|||
@ApiModelProperty(value = "记录数") |
|||
private Integer recordCount; |
|||
} |
|||
|
|||
@PostMapping("/summaryList") |
|||
@ApiOperation(value = "按区域和日期获取商家结算汇总") |
|||
public Result<List<SettlementSummaryVo>> summaryList(@RequestBody SummaryQuery query) { |
|||
if (StringUtils.isBlank(query.getRegionId()) || StringUtils.isBlank(query.getSettlementDate())) { |
|||
return ResultUtil.error("区域ID或日期不能为空"); |
|||
} |
|||
|
|||
LambdaQueryWrapper<MallSettlementRecord> qw = new LambdaQueryWrapper<>(); |
|||
qw.eq(MallSettlementRecord::getRegionId, query.getRegionId()); |
|||
qw.eq(MallSettlementRecord::getStatus, 0); |
|||
qw.apply("DATE(create_time) = {0}", query.getSettlementDate()); |
|||
|
|||
List<MallSettlementRecord> list = mallSettlementRecordService.list(qw); |
|||
|
|||
// Group by shopId
|
|||
Map<String, List<MallSettlementRecord>> map = list.stream().collect(Collectors.groupingBy(MallSettlementRecord::getShopId)); |
|||
|
|||
List<SettlementSummaryVo> result = new ArrayList<>(); |
|||
for (Map.Entry<String, List<MallSettlementRecord>> entry : map.entrySet()) { |
|||
String shopId = entry.getKey(); |
|||
List<MallSettlementRecord> shopRecords = entry.getValue(); |
|||
|
|||
SettlementSummaryVo vo = new SettlementSummaryVo(); |
|||
vo.setShopId(shopId); |
|||
|
|||
Shop shop = shopService.findById(shopId); |
|||
if (shop != null) { |
|||
vo.setShopName(shop.getShopName()); |
|||
} |
|||
|
|||
BigDecimal totalBase = BigDecimal.ZERO; |
|||
BigDecimal totalComm = BigDecimal.ZERO; |
|||
BigDecimal totalSettlement = BigDecimal.ZERO; |
|||
|
|||
for (MallSettlementRecord r : shopRecords) { |
|||
if (r.getBaseAmount() != null) totalBase = totalBase.add(r.getBaseAmount()); |
|||
if (r.getCommissionAmount() != null) totalComm = totalComm.add(r.getCommissionAmount()); |
|||
if (r.getSettlementAmount() != null) totalSettlement = totalSettlement.add(r.getSettlementAmount()); |
|||
} |
|||
vo.setTotalBaseAmount(totalBase); |
|||
vo.setTotalCommissionAmount(totalComm); |
|||
vo.setTotalSettlementAmount(totalSettlement); |
|||
vo.setRecordCount(shopRecords.size()); |
|||
|
|||
result.add(vo); |
|||
} |
|||
return new ResultUtil<List<SettlementSummaryVo>>().setData(result); |
|||
} |
|||
|
|||
@Data |
|||
public static class ConfirmShopReq { |
|||
@ApiModelProperty(value = "选中的商家ID列表") |
|||
private List<String> shopIds; |
|||
@ApiModelProperty(value = "区域ID") |
|||
private String regionId; |
|||
@ApiModelProperty(value = "结算日期,格式yyyy-MM-dd") |
|||
private String settlementDate; |
|||
} |
|||
|
|||
@PostMapping("/confirmByShop") |
|||
@ApiOperation(value = "每日结算确认(按商家)") |
|||
public Result confirmByShop(@RequestBody ConfirmShopReq req) { |
|||
if (req.getShopIds() == null || req.getShopIds().isEmpty()) { |
|||
return ResultUtil.error("请选择要确认的商家"); |
|||
} |
|||
try { |
|||
LambdaQueryWrapper<MallSettlementRecord> qw = new LambdaQueryWrapper<>(); |
|||
if (StringUtils.isNotBlank(req.getRegionId())) { |
|||
qw.eq(MallSettlementRecord::getRegionId, req.getRegionId()); |
|||
} |
|||
if (StringUtils.isNotBlank(req.getSettlementDate())) { |
|||
qw.apply("DATE(create_time) = {0}", req.getSettlementDate()); |
|||
} |
|||
qw.in(MallSettlementRecord::getShopId, req.getShopIds()); |
|||
qw.eq(MallSettlementRecord::getStatus, 0); |
|||
|
|||
List<MallSettlementRecord> list = mallSettlementRecordService.list(qw); |
|||
if (list == null || list.isEmpty()) { |
|||
return ResultUtil.success("没有需要确认的结算记录"); |
|||
} |
|||
List<String> recordIds = list.stream().map(MallSettlementRecord::getId).collect(Collectors.toList()); |
|||
|
|||
mallSettlementRecordService.confirmSettlements(recordIds); |
|||
|
|||
return ResultUtil.success("结算确认成功"); |
|||
} catch (Exception e) { |
|||
log.error("结算确认失败: {}", e.getMessage(), e); |
|||
return ResultUtil.error("结算确认失败: " + e.getMessage()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
package cc.hiver.mall.controller; |
|||
|
|||
import cc.hiver.core.common.utils.ResultUtil; |
|||
import cc.hiver.core.common.vo.Result; |
|||
import cc.hiver.mall.entity.MallSettlementRecord; |
|||
import cc.hiver.mall.service.mybatis.MallSettlementRecordService; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import io.swagger.annotations.Api; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
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; |
|||
|
|||
@Slf4j |
|||
@RestController |
|||
@Api(tags = "商家端结算记录查询接口") |
|||
@RequestMapping("/hiver/mall/shop/settlement") |
|||
public class ShopSettlementController { |
|||
|
|||
@Autowired |
|||
private MallSettlementRecordService mallSettlementRecordService; |
|||
|
|||
@Data |
|||
public static class ShopSettlementQuery { |
|||
// Required for safety
|
|||
private String shopId; |
|||
private Integer status; |
|||
private Integer type; |
|||
private int pageNumber = 1; |
|||
private int pageSize = 10; |
|||
} |
|||
|
|||
@PostMapping("/page") |
|||
@ApiOperation(value = "商家分页查询结算记录") |
|||
public Result<Page<MallSettlementRecord>> page(@RequestBody ShopSettlementQuery query) { |
|||
if (StringUtils.isBlank(query.getShopId())) { |
|||
return ResultUtil.error("缺少商家店铺ID参数"); |
|||
} |
|||
|
|||
LambdaQueryWrapper<MallSettlementRecord> qw = new LambdaQueryWrapper<>(); |
|||
qw.eq(MallSettlementRecord::getShopId, query.getShopId()); |
|||
|
|||
if (query.getStatus() != null) { |
|||
qw.eq(MallSettlementRecord::getStatus, query.getStatus()); |
|||
} |
|||
if (query.getType() != null) { |
|||
qw.eq(MallSettlementRecord::getType, query.getType()); |
|||
} |
|||
qw.orderByDesc(MallSettlementRecord::getCreateTime); |
|||
|
|||
Page<MallSettlementRecord> page = new Page<>(query.getPageNumber(), query.getPageSize()); |
|||
Page<MallSettlementRecord> result = mallSettlementRecordService.page(page, qw); |
|||
return new ResultUtil<Page<MallSettlementRecord>>().setData(result); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
package cc.hiver.mall.dao.mapper; |
|||
|
|||
import cc.hiver.mall.entity.MallSettlementRecord; |
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import org.springframework.stereotype.Repository; |
|||
|
|||
/** |
|||
* <p> |
|||
* Mapper 接口 |
|||
* </p> |
|||
* |
|||
* @author hiver |
|||
*/ |
|||
@Repository |
|||
public interface MallSettlementRecordMapper extends BaseMapper<MallSettlementRecord> { |
|||
|
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
package cc.hiver.mall.entity; |
|||
|
|||
import cc.hiver.core.common.utils.SnowFlakeUtil; |
|||
import com.baomidou.mybatisplus.annotation.TableField; |
|||
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 javax.persistence.Entity; |
|||
import javax.persistence.Id; |
|||
import javax.persistence.Table; |
|||
import javax.persistence.Transient; |
|||
import java.io.Serializable; |
|||
import java.math.BigDecimal; |
|||
import java.util.Date; |
|||
|
|||
@Data |
|||
@Entity |
|||
@Table(name = "mall_settlement_record") |
|||
@TableName("mall_settlement_record") |
|||
@ApiModel(value = "商家账单结算记录") |
|||
public class MallSettlementRecord implements Serializable { |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
@Id |
|||
@TableId |
|||
@ApiModelProperty(value = "主键") |
|||
private String id = SnowFlakeUtil.nextId().toString(); |
|||
|
|||
@ApiModelProperty(value = "关联订单ID") |
|||
private String orderId; |
|||
|
|||
@ApiModelProperty(value = "关联店铺ID") |
|||
private String shopId; |
|||
|
|||
@ApiModelProperty(value = "关联学校区域ID") |
|||
private String regionId; |
|||
|
|||
@ApiModelProperty(value = "关联售后记录ID (负数计算使用)") |
|||
private String refundId; |
|||
|
|||
@ApiModelProperty(value = "结算类型 1:正数结算(正常) 2:负数结算(售后)") |
|||
private Integer type; |
|||
|
|||
@ApiModelProperty(value = "基数金额(退款会扣除售后商品金额)") |
|||
private BigDecimal baseAmount; |
|||
|
|||
@ApiModelProperty(value = "抽佣比例") |
|||
private BigDecimal commissionRate; |
|||
|
|||
@ApiModelProperty(value = "平台抽成佣金") |
|||
private BigDecimal commissionAmount; |
|||
|
|||
@ApiModelProperty(value = "商家实际结算金额(可提现金额)") |
|||
private BigDecimal settlementAmount; |
|||
|
|||
@ApiModelProperty(value = "状态 0:待确认 1:已确认结算") |
|||
private Integer status; |
|||
|
|||
@ApiModelProperty(value = "创建时间") |
|||
private Date createTime; |
|||
|
|||
@ApiModelProperty(value = "确认时间") |
|||
private Date confirmTime; |
|||
|
|||
@Transient |
|||
@TableField(exist = false) |
|||
@ApiModelProperty(value = "订单编号(快照)") |
|||
private String orderNumber; |
|||
|
|||
@Transient |
|||
@TableField(exist = false) |
|||
@ApiModelProperty(value = "店铺名称(快照)") |
|||
private String shopName; |
|||
} |
|||
@ -0,0 +1,216 @@ |
|||
package cc.hiver.mall.quartz; |
|||
|
|||
import cc.hiver.mall.dao.mapper.MallReturnOrderGoodsMapper; |
|||
import cc.hiver.mall.entity.*; |
|||
import cc.hiver.mall.service.ShopService; |
|||
import cc.hiver.mall.service.ShopTakeawayService; |
|||
import cc.hiver.mall.service.mybatis.MallOrderService; |
|||
import cc.hiver.mall.service.mybatis.MallRefundRecordService; |
|||
import cc.hiver.mall.service.mybatis.MallSettlementRecordService; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.util.Date; |
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
@Component |
|||
public class MerchantSettlementTask { |
|||
@Autowired |
|||
private MallOrderService mallOrderService; |
|||
@Autowired |
|||
private MallRefundRecordService mallRefundRecordService; |
|||
@Autowired |
|||
private MallReturnOrderGoodsMapper mallReturnOrderGoodsMapper; |
|||
@Autowired |
|||
private MallSettlementRecordService mallSettlementRecordService; |
|||
@Autowired |
|||
private ShopTakeawayService shopTakeawayService; |
|||
@Autowired |
|||
private ShopService shopService; |
|||
|
|||
@Scheduled(cron = "0 0 2 * * ?") |
|||
public void executeSettlement() { |
|||
log.info("[MerchantSettlementTask] Starting daily settlement calculation..."); |
|||
|
|||
// 1. Process Normal Unsettled Orders
|
|||
try { |
|||
LambdaQueryWrapper<MallOrder> qw = new LambdaQueryWrapper<>(); |
|||
qw.in(MallOrder::getStatus, 5, 12); |
|||
qw.eq(MallOrder::getSettlementStatus, 0); |
|||
List<MallOrder> orders = mallOrderService.list(qw); |
|||
|
|||
for (MallOrder order : orders) { |
|||
try { |
|||
processUnsettledOrder(order); |
|||
} catch (Exception e) { |
|||
log.error("[MerchantSettlementTask] Failed to process unsettled order {}", order.getId(), e); |
|||
} |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("[MerchantSettlementTask] Error processing unsettled orders", e); |
|||
} |
|||
|
|||
// 2. Process Already Settled Orders with New Refunds
|
|||
try { |
|||
LambdaQueryWrapper<MallRefundRecord> refundQw = new LambdaQueryWrapper<>(); |
|||
refundQw.eq(MallRefundRecord::getStatus, 4); |
|||
List<MallRefundRecord> refundRecords = mallRefundRecordService.list(refundQw); |
|||
|
|||
for (MallRefundRecord refund : refundRecords) { |
|||
try { |
|||
processSettledRefund(refund); |
|||
} catch (Exception e) { |
|||
log.error("[MerchantSettlementTask] Failed to process settled refund {}", refund.getId(), e); |
|||
} |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("[MerchantSettlementTask] Error processing settled refunds", e); |
|||
} |
|||
|
|||
log.info("[MerchantSettlementTask] Daily settlement calculation finished."); |
|||
} |
|||
|
|||
private void processUnsettledOrder(MallOrder order) { |
|||
LambdaQueryWrapper<MallSettlementRecord> existsQw = new LambdaQueryWrapper<>(); |
|||
existsQw.eq(MallSettlementRecord::getOrderId, order.getId()); |
|||
existsQw.eq(MallSettlementRecord::getType, 1); |
|||
long count = mallSettlementRecordService.count(existsQw); |
|||
if (count > 0) return; // Skip if already pending confirmation
|
|||
|
|||
LambdaQueryWrapper<ShopTakeaway> shopQw = new LambdaQueryWrapper<>(); |
|||
shopQw.eq(ShopTakeaway::getShopId, order.getShopId()); |
|||
ShopTakeaway takeaway = shopTakeawayService.getOne(shopQw); |
|||
|
|||
BigDecimal commissionRate = BigDecimal.ZERO; |
|||
if (takeaway != null) { |
|||
if (order.getOrderType() != null && order.getOrderType() == 1) { |
|||
commissionRate = takeaway.getCommissionRateOne(); |
|||
} else if (order.getOrderType() != null && (order.getOrderType() == 2 || order.getOrderType() == 3)) { |
|||
commissionRate = takeaway.getCommissionRateMore(); |
|||
} |
|||
} |
|||
if (commissionRate == null) { |
|||
commissionRate = BigDecimal.ZERO; |
|||
} |
|||
|
|||
LambdaQueryWrapper<MallRefundRecord> refQw = new LambdaQueryWrapper<>(); |
|||
refQw.eq(MallRefundRecord::getOrderId, order.getId()); |
|||
refQw.eq(MallRefundRecord::getStatus, 4); |
|||
List<MallRefundRecord> refunds = mallRefundRecordService.list(refQw); |
|||
|
|||
BigDecimal refundAmount = BigDecimal.ZERO; |
|||
for (MallRefundRecord r : refunds) { |
|||
String linkId = r.getLinkId(); |
|||
// 只有商家负责的售后(linkId不为W开头)才需要从商家的结算基准中扣除
|
|||
if (linkId == null || !linkId.toUpperCase().startsWith("W")) { |
|||
if (r.getRefundAmount() != null) { |
|||
refundAmount = refundAmount.add(r.getRefundAmount()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
BigDecimal goodsAmount = order.getGoodsAmount() != null ? order.getGoodsAmount() : BigDecimal.ZERO; |
|||
BigDecimal packageFee = order.getPackageFee() != null ? order.getPackageFee() : BigDecimal.ZERO; |
|||
|
|||
BigDecimal baseAmount = goodsAmount.add(packageFee).subtract(refundAmount); |
|||
|
|||
BigDecimal actualCommission = BigDecimal.ZERO; |
|||
if (baseAmount.compareTo(BigDecimal.ZERO) > 0) { |
|||
actualCommission = baseAmount.multiply(commissionRate); |
|||
} else { |
|||
baseAmount = BigDecimal.ZERO; |
|||
} |
|||
|
|||
BigDecimal settlementAmount = baseAmount.subtract(actualCommission); |
|||
|
|||
MallSettlementRecord record = new MallSettlementRecord(); |
|||
record.setOrderId(order.getId()); |
|||
record.setShopId(order.getShopId()); |
|||
record.setType(1); |
|||
record.setBaseAmount(baseAmount); |
|||
record.setCommissionRate(commissionRate); |
|||
record.setCommissionAmount(actualCommission); |
|||
record.setRegionId(order.getRegionId()); |
|||
record.setSettlementAmount(settlementAmount); |
|||
record.setStatus(0); |
|||
record.setCreateTime(new Date()); |
|||
|
|||
mallSettlementRecordService.save(record); |
|||
} |
|||
|
|||
private void processSettledRefund(MallRefundRecord refund) { |
|||
String linkId = refund.getLinkId(); |
|||
// 配送员负责的售后(linkId为W开头),不扣商家的款
|
|||
if (linkId != null && linkId.toUpperCase().startsWith("W")) { |
|||
return; |
|||
} |
|||
|
|||
MallOrder order = mallOrderService.getById(refund.getOrderId()); |
|||
if (order == null || order.getSettlementStatus() == null || order.getSettlementStatus() == 0) { |
|||
return; |
|||
} |
|||
|
|||
LambdaQueryWrapper<MallSettlementRecord> existsQw = new LambdaQueryWrapper<>(); |
|||
existsQw.eq(MallSettlementRecord::getRefundId, refund.getId()); |
|||
existsQw.eq(MallSettlementRecord::getType, 2); |
|||
long count = mallSettlementRecordService.count(existsQw); |
|||
if (count > 0) { |
|||
return; |
|||
} |
|||
|
|||
LambdaQueryWrapper<ShopTakeaway> shopQw = new LambdaQueryWrapper<>(); |
|||
shopQw.eq(ShopTakeaway::getShopId, order.getShopId()); |
|||
ShopTakeaway takeaway = shopTakeawayService.getOne(shopQw); |
|||
|
|||
BigDecimal commissionRate = BigDecimal.ZERO; |
|||
if (takeaway != null) { |
|||
if (order.getOrderType() != null && order.getOrderType() == 1) { |
|||
commissionRate = takeaway.getCommissionRateOne(); |
|||
} else if (order.getOrderType() != null && (order.getOrderType() == 2 || order.getOrderType() == 3)) { |
|||
commissionRate = takeaway.getCommissionRateMore(); |
|||
} |
|||
} |
|||
if (commissionRate == null) { |
|||
commissionRate = BigDecimal.ZERO; |
|||
} |
|||
|
|||
LambdaQueryWrapper<MallReturnOrderGoods> goodsQw = new LambdaQueryWrapper<>(); |
|||
goodsQw.eq(MallReturnOrderGoods::getOrderId, refund.getId()); |
|||
List<MallReturnOrderGoods> returnGoods = mallReturnOrderGoodsMapper.selectList(goodsQw); |
|||
|
|||
BigDecimal totalReturnPice = BigDecimal.ZERO; |
|||
if (returnGoods != null) { |
|||
for (MallReturnOrderGoods g : returnGoods) { |
|||
BigDecimal price = g.getPrice() != null ? g.getPrice() : BigDecimal.ZERO; |
|||
BigDecimal quantity = g.getQuantity() != null ? new BigDecimal(g.getQuantity()) : BigDecimal.ZERO; |
|||
totalReturnPice = totalReturnPice.add(price.multiply(quantity)); |
|||
} |
|||
} |
|||
|
|||
if (totalReturnPice.compareTo(BigDecimal.ZERO) == 0) { |
|||
return; |
|||
} |
|||
|
|||
BigDecimal deductionAmount = totalReturnPice.multiply(BigDecimal.ONE.subtract(commissionRate)); |
|||
|
|||
MallSettlementRecord record = new MallSettlementRecord(); |
|||
record.setOrderId(order.getId()); |
|||
record.setShopId(order.getShopId()); |
|||
record.setRefundId(refund.getId()); |
|||
record.setType(2); |
|||
record.setRegionId(order.getRegionId()); |
|||
record.setBaseAmount(totalReturnPice); |
|||
record.setCommissionRate(commissionRate); |
|||
record.setCommissionAmount(totalReturnPice.multiply(commissionRate)); |
|||
record.setSettlementAmount(deductionAmount.negate()); |
|||
record.setStatus(0); |
|||
record.setCreateTime(new Date()); |
|||
|
|||
mallSettlementRecordService.save(record); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
package cc.hiver.mall.service.mybatis; |
|||
|
|||
import cc.hiver.mall.entity.MallRefundRecord; |
|||
import cc.hiver.mall.entity.MallSettlementRecord; |
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* <p> |
|||
* 服务类 |
|||
* </p> |
|||
* |
|||
* @author hiver |
|||
*/ |
|||
public interface MallSettlementRecordService extends IService<MallSettlementRecord> { |
|||
|
|||
void confirmSettlements(List<String> ids); |
|||
|
|||
void processSettledRefund(MallRefundRecord refund); |
|||
|
|||
} |
|||
@ -0,0 +1,138 @@ |
|||
package cc.hiver.mall.serviceimpl.mybatis; |
|||
|
|||
import cc.hiver.mall.dao.mapper.MallSettlementRecordMapper; |
|||
import cc.hiver.mall.entity.MallOrder; |
|||
import cc.hiver.mall.entity.MallSettlementRecord; |
|||
import cc.hiver.mall.entity.Shop; |
|||
import cc.hiver.mall.service.ShopService; |
|||
import cc.hiver.mall.service.mybatis.MallOrderService; |
|||
import cc.hiver.mall.service.mybatis.MallSettlementRecordService; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.transaction.annotation.Transactional; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.util.Date; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* <p> |
|||
* 服务实现类 |
|||
* </p> |
|||
* |
|||
* @author hiver |
|||
*/ |
|||
@Service |
|||
public class MallSettlementRecordServiceImpl extends ServiceImpl<MallSettlementRecordMapper, MallSettlementRecord> implements MallSettlementRecordService { |
|||
|
|||
@Autowired |
|||
private MallOrderService mallOrderService; |
|||
|
|||
@Autowired |
|||
private ShopService shopService; |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void confirmSettlements(List<String> ids) { |
|||
if (ids == null || ids.isEmpty()) return; |
|||
List<MallSettlementRecord> records = this.listByIds(ids); |
|||
for (MallSettlementRecord record : records) { |
|||
if (record.getStatus() != null && record.getStatus() == 1) { |
|||
continue; // Already confirmed
|
|||
} |
|||
|
|||
// Confirm it
|
|||
record.setStatus(1); |
|||
record.setConfirmTime(new Date()); |
|||
this.updateById(record); |
|||
|
|||
// Update MallOrder if it's a normal settlement
|
|||
if (record.getType() != null && record.getType() == 1) { |
|||
MallOrder order = mallOrderService.getById(record.getOrderId()); |
|||
if (order != null) { |
|||
order.setSettlementStatus(1); |
|||
mallOrderService.updateById(order); |
|||
} |
|||
} |
|||
|
|||
// Update Shop balance
|
|||
Shop shop = shopService.findById(record.getShopId()); |
|||
if (shop != null && record.getSettlementAmount() != null) { |
|||
BigDecimal balance = shop.getBalance() != null ? shop.getBalance() : BigDecimal.ZERO; |
|||
shop.setBalance(balance.add(record.getSettlementAmount())); |
|||
shopService.update(shop); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Autowired |
|||
private cc.hiver.mall.service.ShopTakeawayService shopTakeawayService; |
|||
@Autowired |
|||
private cc.hiver.mall.dao.mapper.MallReturnOrderGoodsMapper mallReturnOrderGoodsMapper; |
|||
|
|||
@Override |
|||
public void processSettledRefund(cc.hiver.mall.entity.MallRefundRecord refund) { |
|||
MallOrder order = mallOrderService.getById(refund.getOrderId()); |
|||
if (order == null || order.getSettlementStatus() == null || order.getSettlementStatus() == 0) { |
|||
return; |
|||
} |
|||
|
|||
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<MallSettlementRecord> existsQw = new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>(); |
|||
existsQw.eq(MallSettlementRecord::getRefundId, refund.getId()); |
|||
existsQw.eq(MallSettlementRecord::getType, 2); |
|||
long count = this.count(existsQw); |
|||
if (count > 0) { |
|||
return; |
|||
} |
|||
|
|||
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<cc.hiver.mall.entity.ShopTakeaway> shopQw = new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>(); |
|||
shopQw.eq(cc.hiver.mall.entity.ShopTakeaway::getShopId, order.getShopId()); |
|||
cc.hiver.mall.entity.ShopTakeaway takeaway = shopTakeawayService.getOne(shopQw); |
|||
|
|||
BigDecimal commissionRate = BigDecimal.ZERO; |
|||
if (takeaway != null) { |
|||
if (order.getOrderType() != null && order.getOrderType() == 1) { |
|||
commissionRate = takeaway.getCommissionRateOne(); |
|||
} else if (order.getOrderType() != null && (order.getOrderType() == 2 || order.getOrderType() == 3)) { |
|||
commissionRate = takeaway.getCommissionRateMore(); |
|||
} |
|||
} |
|||
if (commissionRate == null) { |
|||
commissionRate = BigDecimal.ZERO; |
|||
} |
|||
|
|||
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<cc.hiver.mall.entity.MallReturnOrderGoods> goodsQw = new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>(); |
|||
goodsQw.eq(cc.hiver.mall.entity.MallReturnOrderGoods::getOrderId, refund.getId()); |
|||
List<cc.hiver.mall.entity.MallReturnOrderGoods> returnGoods = mallReturnOrderGoodsMapper.selectList(goodsQw); |
|||
|
|||
BigDecimal totalReturnPice = BigDecimal.ZERO; |
|||
if (returnGoods != null) { |
|||
for (cc.hiver.mall.entity.MallReturnOrderGoods g : returnGoods) { |
|||
BigDecimal price = g.getPrice() != null ? g.getPrice() : BigDecimal.ZERO; |
|||
BigDecimal quantity = g.getQuantity() != null ? new BigDecimal(g.getQuantity()) : BigDecimal.ZERO; |
|||
totalReturnPice = totalReturnPice.add(price.multiply(quantity)); |
|||
} |
|||
} |
|||
|
|||
if (totalReturnPice.compareTo(BigDecimal.ZERO) == 0) { |
|||
return; |
|||
} |
|||
|
|||
BigDecimal deductionAmount = totalReturnPice.multiply(BigDecimal.ONE.subtract(commissionRate)); |
|||
|
|||
MallSettlementRecord record = new MallSettlementRecord(); |
|||
record.setOrderId(order.getId()); |
|||
record.setShopId(order.getShopId()); |
|||
record.setRefundId(refund.getId()); |
|||
record.setType(2); |
|||
record.setBaseAmount(totalReturnPice); |
|||
record.setCommissionRate(commissionRate); |
|||
record.setCommissionAmount(totalReturnPice.multiply(commissionRate)); |
|||
record.setSettlementAmount(deductionAmount.negate()); |
|||
record.setStatus(0); |
|||
record.setCreateTime(new Date()); |
|||
|
|||
this.save(record); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue