From 55909637f48faffa562b4c9cc3d0ed2734fc77b8 Mon Sep 17 00:00:00 2001
From: wangfukang <15630117759@163.com>
Date: Fri, 17 Apr 2026 17:01:47 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E6=8E=A5=E6=8B=BC=E5=9B=A2=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../controller/AdminSettlementController.java | 204 +++++++++++++++++
.../mall/controller/CommentController.java | 42 ++--
.../mall/controller/MallCouponController.java | 4 +-
.../mall/controller/MallOrderController.java | 24 ++
.../ReturnCommissionController.java | 12 +-
.../controller/ShopSettlementController.java | 61 +++++
.../mall/dao/mapper/MallOrderMapper.java | 11 +
.../mapper/MallSettlementRecordMapper.java | 17 ++
.../service/impl/DeductLogServiceImpl.java | 14 +-
.../java/cc/hiver/mall/entity/Comment.java | 6 +-
.../java/cc/hiver/mall/entity/MallOrder.java | 2 +
.../hiver/mall/entity/MallRefundRecord.java | 9 +-
.../mall/entity/MallSettlementRecord.java | 77 +++++++
.../main/java/cc/hiver/mall/entity/Shop.java | 4 +-
.../invitelog/mapper/InviteLogMapper.java | 2 +
.../service/impl/InviteLogServiceImpl.java | 10 +-
.../hiver/mall/pojo/query/CommentQuery.java | 8 +-
.../cc/hiver/mall/pojo/vo/MallOrderVO.java | 3 +
.../mall/quartz/MerchantSettlementTask.java | 216 ++++++++++++++++++
.../service/mybatis/MallOrderService.java | 9 +
.../mybatis/MallSettlementRecordService.java | 22 ++
.../mybatis/MallUserCouponService.java | 2 +-
.../mall/serviceimpl/ShopServiceImpl.java | 2 +-
.../mybatis/MallDeliveryOrderServiceImpl.java | 9 +
.../mybatis/MallOrderServiceImpl.java | 116 ++++++++--
.../mybatis/MallRefundRecordServiceImpl.java | 72 ++++++
.../MallSettlementRecordServiceImpl.java | 138 +++++++++++
.../mybatis/MallUserCouponServiceImpl.java | 13 +-
.../main/resources/mapper/CommentMapper.xml | 19 +-
.../main/resources/mapper/MallOrderMapper.xml | 74 +++++-
.../src/main/resources/mapper/ShopMapper.xml | 10 +-
31 files changed, 1122 insertions(+), 90 deletions(-)
create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminSettlementController.java
create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopSettlementController.java
create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallSettlementRecordMapper.java
create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallSettlementRecord.java
create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/MerchantSettlementTask.java
create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallSettlementRecordService.java
create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallSettlementRecordServiceImpl.java
diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminSettlementController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminSettlementController.java
new file mode 100644
index 00000000..66da5cd2
--- /dev/null
+++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminSettlementController.java
@@ -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(@RequestBody SettlementQuery query) {
+ LambdaQueryWrapper 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 page = new Page<>(query.getPageNumber(), query.getPageSize());
+ Page result = mallSettlementRecordService.page(page, qw);
+ return new ResultUtil>().setData(result);
+ }
+
+ @Data
+ public static class ConfirmReq {
+ private List 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> summaryList(@RequestBody SummaryQuery query) {
+ if (StringUtils.isBlank(query.getRegionId()) || StringUtils.isBlank(query.getSettlementDate())) {
+ return ResultUtil.error("区域ID或日期不能为空");
+ }
+
+ LambdaQueryWrapper qw = new LambdaQueryWrapper<>();
+ qw.eq(MallSettlementRecord::getRegionId, query.getRegionId());
+ qw.eq(MallSettlementRecord::getStatus, 0);
+ qw.apply("DATE(create_time) = {0}", query.getSettlementDate());
+
+ List list = mallSettlementRecordService.list(qw);
+
+ // Group by shopId
+ Map> map = list.stream().collect(Collectors.groupingBy(MallSettlementRecord::getShopId));
+
+ List result = new ArrayList<>();
+ for (Map.Entry> entry : map.entrySet()) {
+ String shopId = entry.getKey();
+ List 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>().setData(result);
+ }
+
+ @Data
+ public static class ConfirmShopReq {
+ @ApiModelProperty(value = "选中的商家ID列表")
+ private List 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 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 list = mallSettlementRecordService.list(qw);
+ if (list == null || list.isEmpty()) {
+ return ResultUtil.success("没有需要确认的结算记录");
+ }
+ List 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());
+ }
+ }
+}
diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CommentController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CommentController.java
index 80c55b64..603b6805 100644
--- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CommentController.java
+++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CommentController.java
@@ -20,27 +20,21 @@ import cc.hiver.core.common.utils.ResultUtil;
import cc.hiver.core.common.utils.StringUtils;
import cc.hiver.core.common.vo.Result;
import cc.hiver.mall.entity.Comment;
-import cc.hiver.mall.entity.ShopTakeaway;
import cc.hiver.mall.pojo.query.CommentQuery;
-import cc.hiver.mall.pojo.query.ShopTakeawayQuery;
-import cc.hiver.mall.pojo.vo.ProductPageVO;
import cc.hiver.mall.service.CommentService;
-import cc.hiver.mall.service.ShopTakeawayService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
/**
- * 店铺外卖业务配置控制器
+ * 评论接口
*
* @author cc
*/
@@ -55,24 +49,22 @@ public class CommentController {
@RequestMapping(value = "/save", method = RequestMethod.POST)
@ApiOperation("保存")
- @ResponseBody
- public Result save(Comment comment) {
- // 1. 获取当前时间
- final LocalDateTime now = LocalDateTime.now();
-
- // 2. 定义格式化器 (例如:yyyy-MM-dd HH:mm:ss)
- final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-
- // 3. 转换为字符串
- final String timeStr = now.format(formatter);
- comment.setCreateByName(timeStr);
- if(StringUtils.isEmpty(comment.getParentId())){
- comment.setLevel(ShopConstant.SHOP_STATUS_LOCK);
- }else{
- comment.setLevel(ShopConstant.SHOP_STATUS_NORMAL);
+ public Result save( @RequestBody List comment) {
+ comment.forEach(e -> {
+ e.setCreateTime(new Date());
+ if(StringUtils.isEmpty(e.getParentId())){
+ e.setLevel(ShopConstant.SHOP_STATUS_LOCK);
+ }else{
+ e.setLevel(ShopConstant.SHOP_STATUS_NORMAL);
+ }
+ });
+ if(comment != null && comment.get(0).getParentId()!=null){
+ Comment commentPar = commentService.getById(comment.get(0).getParentId());
+ commentPar.setHasAnswer(1);
+ commentService.updateById(commentPar);
}
- final Integer result = commentService.insert(comment);
- return new ResultUtil().setData(comment);
+ commentService.saveBatch(comment);
+ return ResultUtil.success("评论成功");
}
@RequestMapping(value = "/deleteById", method = RequestMethod.POST)
diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallCouponController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallCouponController.java
index 578b8e0c..3ab39cd5 100644
--- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallCouponController.java
+++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallCouponController.java
@@ -50,8 +50,8 @@ public class MallCouponController {
@PostMapping("/send")
@ApiOperation(value = "平台发放优惠券")
- public Result
+ *
+ * @author hiver
+ */
+@Service
+public class MallSettlementRecordServiceImpl extends ServiceImpl implements MallSettlementRecordService {
+
+ @Autowired
+ private MallOrderService mallOrderService;
+
+ @Autowired
+ private ShopService shopService;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void confirmSettlements(List ids) {
+ if (ids == null || ids.isEmpty()) return;
+ List 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 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 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 goodsQw = new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
+ goodsQw.eq(cc.hiver.mall.entity.MallReturnOrderGoods::getOrderId, refund.getId());
+ List 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);
+ }
+}
diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallUserCouponServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallUserCouponServiceImpl.java
index ff091f0e..ba3611ac 100644
--- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallUserCouponServiceImpl.java
+++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallUserCouponServiceImpl.java
@@ -137,13 +137,18 @@ public class MallUserCouponServiceImpl extends ServiceImpl phones = Arrays.asList(userPhones.split(","));
phones.forEach(phone -> {
- this.receiveCoupon(userService.findByMobile(phone).getId(), couponId);
+ for(int i = 0; i < giveNum; i++){
+ User user = userService.findByMobile(phone);
+ if(user != null){
+ this.receiveCoupon(userService.findByMobile(phone).getId(), couponId);
+ }
+ }
});
}
@@ -151,7 +156,9 @@ public class MallUserCouponServiceImpl extends ServiceImpl users = userService.getAll();
users.forEach(user -> {
- this.receiveCoupon(user.getId(), couponId);
+ for(int i = 0; i < giveNum; i++){
+ this.receiveCoupon(user.getId(), couponId);
+ }
});
}
}
diff --git a/hiver-modules/hiver-mall/src/main/resources/mapper/CommentMapper.xml b/hiver-modules/hiver-mall/src/main/resources/mapper/CommentMapper.xml
index 968c5c88..901853fa 100644
--- a/hiver-modules/hiver-mall/src/main/resources/mapper/CommentMapper.xml
+++ b/hiver-modules/hiver-mall/src/main/resources/mapper/CommentMapper.xml
@@ -7,17 +7,18 @@
-
+
+
- id, parent_id, remark, level, picture, create_time, create_by, create_by_name, create_by_icon, score, order_id, shop_id
+ id, parent_id, remark, level, picture, create_time, create_by, create_by_name, create_by_icon, score, order_id, shop_id, has_answer