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 send(@RequestParam String userPhones, @RequestParam Integer type,@RequestParam String couponId) { - mallUserCouponService.send(userPhones, type,couponId); + public Result send(@RequestParam String userPhones,@RequestParam Integer giveNum, @RequestParam Integer type,@RequestParam String couponId) { + mallUserCouponService.send(userPhones, type,couponId, giveNum); return ResultUtil.success("发放成功"); } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java index 7d9872ed..251ee2dd 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java @@ -18,6 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; +import java.util.Map; /** * 订单接口 @@ -90,6 +91,15 @@ public class MallOrderController { return new ResultUtil().setData(vo); } + /** + * 商家首页查询 + */ + @GetMapping("/countByShop/{shopId}") + @ApiOperation("商家首页查询") + public Result> countByShop(@PathVariable String shopId) { + return new ResultUtil>().setData(mallOrderService.countByShop(shopId)); + } + /** * 商家接单 */ @@ -105,6 +115,20 @@ public class MallOrderController { } } + /** + * 用户点击出餐 + */ + @PostMapping("/userRequireMake") + @ApiOperation(value = "用户点击出餐") + public Result userRequireMake(@ApiParam("订单ID") @RequestParam String orderId) { + try { + mallOrderService.userRequireMake(orderId); + 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/ReturnCommissionController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ReturnCommissionController.java index 243edbd5..d8a93fe3 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ReturnCommissionController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ReturnCommissionController.java @@ -126,23 +126,23 @@ public class ReturnCommissionController { // 提现金额 final BigDecimal commission = returnCommission.getCommission(); // 店铺当前返佣余额 - final BigDecimal shopBefRebateAmount = shop.getRebateAmount(); + //final BigDecimal shopBefRebateAmount = shop.getRebateAmount(); // 店铺当前返佣余额 - final BigDecimal shopAfterRebateAmount = shopBefRebateAmount.subtract(commission); + /* final BigDecimal shopAfterRebateAmount = shopBefRebateAmount.subtract(commission); if (shopBefRebateAmount.compareTo(commission) < 0) { // 如果提现金额大于返佣余额,则不允许提现 return ResultUtil.error("提现金额不可大于佣金余额!"); - } + }*/ try { final AlipayFundTransUniTransferResponse payResult = AliPayUtil.pay(phoneNumber, name, String.valueOf(commission), returnCommission.getId()); if ("SUCCESS".equals(payResult.getStatus())) { returnCommission.setStatus("1"); aliResult = "支付宝转账成功"; - returnCommission.setShopBefRebateAmount(shopBefRebateAmount); - returnCommission.setShopAfterRebateAmount(shopAfterRebateAmount); + //.setShopBefRebateAmount(shopBefRebateAmount); + //returnCommission.setShopAfterRebateAmount(shopAfterRebateAmount); // 3. 更新店铺返佣金额 - shop.setRebateAmount(shopAfterRebateAmount); + //shop.setRebateAmount(shopAfterRebateAmount); shopService.update(shop); } else { returnCommission.setStatus("2"); diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopSettlementController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopSettlementController.java new file mode 100644 index 00000000..b640e8fd --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopSettlementController.java @@ -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(@RequestBody ShopSettlementQuery query) { + if (StringUtils.isBlank(query.getShopId())) { + return ResultUtil.error("缺少商家店铺ID参数"); + } + + LambdaQueryWrapper 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 page = new Page<>(query.getPageNumber(), query.getPageSize()); + Page result = mallSettlementRecordService.page(page, qw); + return new ResultUtil>().setData(result); + } +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallOrderMapper.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallOrderMapper.java index 32a773da..cc54064e 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallOrderMapper.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallOrderMapper.java @@ -8,6 +8,9 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; +import java.time.LocalDateTime; +import java.util.HashMap; + /** * 核心订单 Mapper 接口 */ @@ -20,4 +23,12 @@ public interface MallOrderMapper extends BaseMapper { IPage selectPageVO(IPage page, @Param("q") MallOrderPageQuery q); MallOrder selectMallOrderByGroupId(@Param("groupId") String groupId); + + HashMap selectOrderStatusCount(@Param("shopId") String shopId); + + HashMap selectOrderRevenueAndCount(@Param("shopId") String shopId,@Param("startTime") LocalDateTime startTime,@Param("endTime") LocalDateTime endTime); + + Integer selectPendingBadReviewCount(@Param("shopId") String shopId); + + Integer selectRefundCount(@Param("shopId") String shopId); } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallSettlementRecordMapper.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallSettlementRecordMapper.java new file mode 100644 index 00000000..8fe2afd5 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallSettlementRecordMapper.java @@ -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; + +/** + *

+ * Mapper 接口 + *

+ * + * @author hiver + */ +@Repository +public interface MallSettlementRecordMapper extends BaseMapper { + +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/deductlog/service/impl/DeductLogServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/deductlog/service/impl/DeductLogServiceImpl.java index fafca610..053811a9 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/deductlog/service/impl/DeductLogServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/deductlog/service/impl/DeductLogServiceImpl.java @@ -166,13 +166,13 @@ public class DeductLogServiceImpl extends ServiceImpl 0) { + /*if (shopBefRebateAmount.compareTo(BigDecimal.ZERO) > 0) { // 返佣金额大于0的时候再保存返佣记录 saveDeductLog(deductLog); - } + }*/ } } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Comment.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Comment.java index 1f9959e1..3a944858 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Comment.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Comment.java @@ -10,6 +10,7 @@ import lombok.Data; import javax.persistence.Transient; import java.io.Serializable; import java.math.BigDecimal; +import java.util.Date; import java.util.List; @Data @@ -30,11 +31,14 @@ public class Comment implements Serializable { @ApiModelProperty(value = "等级 0 一级评论 1回复评论") private Integer level; + @ApiModelProperty(value = "是否回复 1是已回复") + private Integer hasAnswer; + @ApiModelProperty(value = "图片") private String picture; @ApiModelProperty(value = "创建时间") - private String createTime; + private Date createTime; @ApiModelProperty(value = "创建人id") private String createBy; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java index ad4ceaed..44529dde 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java @@ -77,6 +77,8 @@ public class MallOrder implements Serializable { private Date payTime; @ApiModelProperty(value = "商家出餐时间") private Date shopMakeTime; + @ApiModelProperty(value = "自取订单用户要求出餐 默认mull 1为用户要求") + private Integer userRequireMake; @ApiModelProperty(value = "学校id") private String regionId; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallRefundRecord.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallRefundRecord.java index d1a2bd2f..5bf0b6de 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallRefundRecord.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallRefundRecord.java @@ -42,11 +42,11 @@ public class MallRefundRecord implements Serializable { private Integer status; @ApiModelProperty(value = "退款类型 1 退商品 2退配送费 3 全额退款") private Integer refundType; - @ApiModelProperty(value = "全额退款类型 1 商家原因 2 配送原因 3 两者都有 4 平台退款") + @ApiModelProperty(value = "全额退款类型 1 商家原因 2 配送原因 3 两者都有(商家退商品和餐盒费金额,配送员退配送费) 4 平台退款") private Integer refundTypeStatus; @ApiModelProperty(value = "创建时间") private Date createTime; - @ApiModelProperty(value = "退款成功时间") + @ApiModelProperty(value = "处理退款/售后时间") private Date successTime; @ApiModelProperty(value = "面对面配送 退款 参团用户订单id集合") private String groupOrderIds; @@ -86,6 +86,11 @@ public class MallRefundRecord implements Serializable { @TableField(exist = false) private BigDecimal goodsAmount; + @ApiModelProperty("订单实际支付总价") + @Transient + @TableField(exist = false) + private BigDecimal totalAmount; + @ApiModelProperty("餐盒费") @Transient @TableField(exist = false) diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallSettlementRecord.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallSettlementRecord.java new file mode 100644 index 00000000..83b66ff4 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallSettlementRecord.java @@ -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; +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Shop.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Shop.java index 1e9e7ecf..dca91dfb 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Shop.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Shop.java @@ -136,8 +136,8 @@ public class Shop extends HiverBaseEntity { @ApiModelProperty(value = "支付宝户名") private String aliName; - @ApiModelProperty(value = "返佣金额") - private BigDecimal rebateAmount; + @ApiModelProperty(value = "账户余额") + private BigDecimal balance; @ApiModelProperty(value = "店铺规格库分类id") private String attrId; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/invitelog/mapper/InviteLogMapper.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/invitelog/mapper/InviteLogMapper.java index a17c2bbd..c5d0e147 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/invitelog/mapper/InviteLogMapper.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/invitelog/mapper/InviteLogMapper.java @@ -4,7 +4,9 @@ import cc.hiver.mall.invitelog.entity.InviteLog; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; +@Repository public interface InviteLogMapper extends BaseMapper { InviteLog getByregisterShopId(@Param("shopId") String shopId, @Param("isOpen") Integer isOpen); diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/invitelog/service/impl/InviteLogServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/invitelog/service/impl/InviteLogServiceImpl.java index 83aa8316..02b5b113 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/invitelog/service/impl/InviteLogServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/invitelog/service/impl/InviteLogServiceImpl.java @@ -71,16 +71,16 @@ public class InviteLogServiceImpl extends ServiceImpl userCoupon; + @ApiModelProperty("评价") + private List comments; + @ApiModelProperty("收货地址详情(冗余展示用)") private String addressDetail; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/MerchantSettlementTask.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/MerchantSettlementTask.java new file mode 100644 index 00000000..23327e3e --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/MerchantSettlementTask.java @@ -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 qw = new LambdaQueryWrapper<>(); + qw.in(MallOrder::getStatus, 5, 12); + qw.eq(MallOrder::getSettlementStatus, 0); + List 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 refundQw = new LambdaQueryWrapper<>(); + refundQw.eq(MallRefundRecord::getStatus, 4); + List 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 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 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 refQw = new LambdaQueryWrapper<>(); + refQw.eq(MallRefundRecord::getOrderId, order.getId()); + refQw.eq(MallRefundRecord::getStatus, 4); + List 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 existsQw = new LambdaQueryWrapper<>(); + existsQw.eq(MallSettlementRecord::getRefundId, refund.getId()); + existsQw.eq(MallSettlementRecord::getType, 2); + long count = mallSettlementRecordService.count(existsQw); + if (count > 0) { + return; + } + + LambdaQueryWrapper 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 goodsQw = new LambdaQueryWrapper<>(); + goodsQw.eq(MallReturnOrderGoods::getOrderId, refund.getId()); + List 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); + } +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java index e608f297..78dd91fc 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java @@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; import org.apache.ibatis.annotations.Param; +import java.util.Map; + /** * 核心订单 Service 接口 */ @@ -63,6 +65,11 @@ public interface MallOrderService extends IService { */ void shopMakeTime(String orderId); + /** + * 用户要求出餐 + */ + void userRequireMake(String orderId); + /** * 商家拒绝退款 */ @@ -74,4 +81,6 @@ public interface MallOrderService extends IService { void completeOrder(String orderId); MallOrder selectMallOrderByGroupId(@Param("groupId") String groupId); + + Map countByShop(String shopId); } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallSettlementRecordService.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallSettlementRecordService.java new file mode 100644 index 00000000..c5c2525e --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallSettlementRecordService.java @@ -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; + +/** + *

+ * 服务类 + *

+ * + * @author hiver + */ +public interface MallSettlementRecordService extends IService { + + void confirmSettlements(List ids); + + void processSettledRefund(MallRefundRecord refund); + +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallUserCouponService.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallUserCouponService.java index 6f20f027..e74b06f7 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallUserCouponService.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallUserCouponService.java @@ -16,5 +16,5 @@ public interface MallUserCouponService extends IService { boolean useCoupon(String orderId); boolean refundCoupon(String orderId); IPage selectPageVO(MallCouponQuery q); - void send(String userPhones,Integer type,String couponId); + void send(String userPhones,Integer type,String couponId,Integer giveNum); } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopServiceImpl.java index ef3fc25c..20421b20 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopServiceImpl.java @@ -212,7 +212,7 @@ public class ShopServiceImpl implements ShopService { final String shopId = securityUtil.getShopId(); final Shop shop = shopDao.getById(shopId); // 获取当前店铺的返佣余额 - resultMap.put("rebateAmount", String.valueOf(shop.getRebateAmount())); + //resultMap.put("rebateAmount", String.valueOf(shop.getRebateAmount())); // 获取累计返佣金额 // 订单返佣 String allDeductRebateAmountByShopId = deductLogService.getAllRebateAmountByShopId(shopId); diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java index 3bd14f07..2621fed3 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java @@ -1,5 +1,7 @@ package cc.hiver.mall.serviceimpl.mybatis; +import cc.hiver.core.entity.Worker; +import cc.hiver.core.serviceimpl.WorkerServiceImpl; import cc.hiver.mall.dao.mapper.MallDeliveryOrderMapper; import cc.hiver.mall.dao.mapper.MallOrderGoodsMapper; import cc.hiver.mall.dao.mapper.MallOrderGroupMapper; @@ -66,6 +68,9 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl uw = new LambdaUpdateWrapper<>(); + uw.eq(MallOrder::getId, orderId).set(MallOrder::getUserRequireMake,1); + this.update(uw); + } + @Override @Transactional(rollbackFor = Exception.class) public void rejectRefund(String orderId, String reason) { @@ -903,6 +917,29 @@ public class MallOrderServiceImpl extends ServiceImpl countByShop(String shopId) { + Map result = new HashMap(); + HashMap orderStatusCount = this.baseMapper.selectOrderStatusCount(shopId); + result.put("orderStatusCount", orderStatusCount); + // 1. 获取指定日期(例如:今天) + LocalDate date = LocalDate.now(); + + // 2. 生成开始时间:当天的 00:00:00 + LocalDateTime startTime = date.atStartOfDay(); + + // 3. 生成结束时间:当天的 23:59:59 + LocalDateTime endTime = date.atTime(LocalTime.MAX); + + HashMap orderRevenueAndCount = this.baseMapper.selectOrderRevenueAndCount(shopId,startTime,endTime); + result.put("orderRevenueAndCount", orderRevenueAndCount); + Integer pendingBadReviewCount = this.baseMapper.selectPendingBadReviewCount(shopId); + result.put("pendingBadReviewCount", pendingBadReviewCount); + Integer refundCount = this.baseMapper.selectRefundCount(shopId); + result.put("refundCount", refundCount); + return result; + } + // ================================================================ // 查询 // ================================================================ @@ -972,6 +1009,31 @@ public class MallOrderServiceImpl extends ServiceImpl commentsPage = commentService.getCommentList(commentQuery); + List parentIds = new ArrayList<>(); + commentsPage.getRecords().forEach(e -> { + parentIds.add(e.getId()); + }); + //封装子级评论 + if(parentIds.size() > 0){ + final List commentsChild = commentService.getCommentListByParentId(parentIds); + commentsPage.getRecords().forEach(e -> { + e.setComments(new ArrayList<>()); + if(commentsChild.size() > 0){ + commentsChild.forEach(comment -> { + if (e.getId().equals(comment.getParentId())) { + e.getComments().add(comment); + } + }); + } + }); + vo.setComments(commentsPage.getRecords()); + } // 售后、退款信息 LambdaQueryWrapper rq = new LambdaQueryWrapper<>(); rq.eq(MallRefundRecord::getOrderId, orderId); @@ -1095,13 +1157,14 @@ public class MallOrderServiceImpl extends ServiceImpl uq = new LambdaQueryWrapper<>(); + uq.eq(MallUserCoupon::getOrderId, record.getOrderId()); + List coupons = mallUserCouponMapper.selectList(uq); + //计算已结算订单 商家同意售后时,按照商品原价-抽佣金额给商家加一条负数待结算记录, + // 未结算的订单结算时需要关联是否有售后减掉售后金额 商家需要有账单结算记录 + //配送员同意售后时需要在他的账户余额减退款金额,订单配送完成给加钱 + if(coupons != null){ + BigDecimal totalCoupons = coupons.stream() + .map(item -> item.getDiscountAmount()) // 提取 BigDecimal 金额 + .reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal allAmount = amount.add(totalCoupons); + //计算比例 + ratio = totalCoupons.divide(allAmount, 4, RoundingMode.HALF_UP); + } // 全额退款 if(refundType == 3){ if(refundTypeStatus == 1){ record.setLinkId(order.getShopId()); + if(ratio != null){ + record.setRefundAmount(record.getRefundAmount() + .subtract(record.getRefundAmount().multiply(ratio)).setScale(2, RoundingMode.HALF_UP)); + } mallRefundRecordMapper.insert(record); - List goodsList = mallOrderGoodsMapper.selectByOrderId(order.getId()); - if (goodsList == null || goodsList.isEmpty()) return; - List returnList = goodsList.stream() - .map(goods -> { - // 在这里为每个 MallOrderGoods 对象创建并填充对应的 MallReturnOrderGoods 对象 - MallReturnOrderGoods returnGoods = new MallReturnOrderGoods(); - returnGoods.setOrderId(record.getId()); - returnGoods.setProductId(goods.getProductId()); - returnGoods.setProductName(goods.getProductName()); - returnGoods.setProductPicture(goods.getProductPicture()); - returnGoods.setSpecs(goods.getSpecs()); - returnGoods.setPrice(goods.getPrice()); - returnGoods.setQuantity(goods.getQuantity()); - mallReturnOrderGoodsMapper.insert(returnGoods); - return returnGoods; - }) - .collect(Collectors.toList()); }else if(refundTypeStatus == 2){ record.setLinkId(workerId); + if(ratio != null){ + record.setRefundAmount(record.getRefundAmount() + .subtract(record.getRefundAmount().multiply(ratio)).setScale(2, RoundingMode.HALF_UP)); + } mallRefundRecordMapper.insert(record); }else if(refundTypeStatus == 3){ //商家、配送员都加一条 record.setLinkId(order.getShopId()); record.setRefundAmount(order.getGoodsAmount().add(order.getPackageFee())); + if(ratio != null){ + record.setRefundAmount(record.getRefundAmount() + .subtract(record.getRefundAmount().multiply(ratio)).setScale(2, RoundingMode.HALF_UP)); + } mallRefundRecordMapper.insert(record); MallRefundRecord mallRefundRecord1 = record; mallRefundRecord1.setId(SnowFlakeUtil.nextId().toString()); mallRefundRecord1.setLinkId(workerId); mallRefundRecord1.setRefundAmount(order.getDeliveryFee()); + if(ratio != null){ + mallRefundRecord1.setRefundAmount(mallRefundRecord1.getRefundAmount() + .subtract(mallRefundRecord1.getRefundAmount().multiply(ratio)).setScale(2, RoundingMode.HALF_UP)); + } mallRefundRecordMapper.insert(mallRefundRecord1); } } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java index c01bd8d6..1561b6d3 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java @@ -1,6 +1,8 @@ package cc.hiver.mall.serviceimpl.mybatis; import cc.hiver.core.common.utils.SnowFlakeUtil; +import cc.hiver.core.entity.Worker; +import cc.hiver.core.serviceimpl.WorkerServiceImpl; import cc.hiver.mall.dao.mapper.*; import cc.hiver.mall.entity.*; import cc.hiver.mall.pojo.query.MallRefundRecordPageQuery; @@ -17,6 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -67,9 +70,17 @@ public class MallRefundRecordServiceImpl extends ServiceImpl uq = new LambdaQueryWrapper<>(); + uq.eq(MallUserCoupon::getOrderId, mallRefundRecord.getOrderId()); + List coupons = mallUserCouponMapper.selectList(uq); + //计算已结算订单 商家同意售后时,按照商品原价-抽佣金额给商家加一条负数待结算记录, + // 未结算的订单结算时需要关联是否有售后减掉售后金额 商家需要有账单结算记录 + //配送员同意售后时需要在他的账户余额减退款金额,订单配送完成给加钱 + if(coupons != null){ + BigDecimal totalCoupons = coupons.stream() + .map(item -> item.getDiscountAmount()) // 提取 BigDecimal 金额 + .reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal allAmount = mallRefundRecord.getTotalAmount().add(totalCoupons); + //计算比例 + ratio = totalCoupons.divide(allAmount, 4, RoundingMode.HALF_UP); + } //如果是售后商品 给商家加一条 如果是配送给配送员加一条 //如果是全额退款商家问题给商家加一条如果是配送问题给配送员加一条 如果两者都有给两者都加一条(处理以后需要查一下还有没有没处理的再更新订单状态) @@ -85,10 +111,16 @@ public class MallRefundRecordServiceImpl extends ServiceImpl item.getRefundAmount()) // 提取 BigDecimal 金额 .reduce(BigDecimal.ZERO, BigDecimal::add); wechatPayUtil.refund(mallRefundRecord.getOrderId(), totalRefund.multiply(new BigDecimal(100)).longValue(), totalRefund.multiply(new BigDecimal(100)).longValue()); + if(mallRefundRecord.getLinkId().toUpperCase().startsWith("W")){ + //配送员同意退款。扣掉余额 + Worker worker = workerServiceImpl.findByWorkerId(mallRefundRecord.getLinkId()); + worker.setDepoBal(worker.getDepoBal().subtract(mallRefundRecord.getRefundAmount())); + workerServiceImpl.update(worker); + } }else{ //拒绝退款 //MallOrder order = mallOrderService.getById(mallRefundRecord.getOrderId()); @@ -220,7 +262,25 @@ public class MallRefundRecordServiceImpl extends ServiceImpl uq = new LambdaQueryWrapper<>(); + uq.eq(MallUserCoupon::getOrderId, mallRefundRecord.getOrderId()); + List coupons = mallUserCouponMapper.selectList(uq);*/ + //计算已结算订单 商家同意售后时,按照商品原价-抽佣金额给商家加一条负数待结算记录, + // 未结算的订单结算时需要关联是否有售后减掉售后金额 商家需要有账单结算记录 + //配送员同意售后时需要在他的账户余额减退款金额,订单配送完成给加钱 + /*if(coupons != null){ + BigDecimal totalCoupons = coupons.stream() + .map(item -> item.getDiscountAmount()) // 提取 BigDecimal 金额 + .reduce(BigDecimal.ZERO, BigDecimal::add); + + }*/ wechatPayUtil.refund(mallRefundRecord.getOrderId(),order.getTotalAmount().multiply(new BigDecimal(100)).longValue(), mallRefundRecord.getRefundAmount().multiply(new BigDecimal(100)).longValue()); + if(mallRefundRecord.getLinkId().toUpperCase().startsWith("W")){ + //配送员同意退款。扣掉余额 + Worker worker = workerServiceImpl.findByWorkerId(mallRefundRecord.getLinkId()); + worker.setDepoBal(worker.getDepoBal().subtract(mallRefundRecord.getRefundAmount())); + workerServiceImpl.update(worker); + } } //都处理了 if(!hasEnd){ @@ -278,6 +338,12 @@ public class MallRefundRecordServiceImpl extends ServiceImpl + * 服务实现类 + *

+ * + * @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 + SELECT + COUNT(*) AS count, + CASE + WHEN (`status` = 3 AND delivery_type = 1) THEN 'daiqu' + WHEN (`status` = 4 AND delivery_type = 1) THEN 'daisong' + WHEN (`status` = 3 AND delivery_type = 2 AND user_require_make IS NULL) THEN 'daixiaofei' + WHEN (`status` = 3 AND delivery_type = 2 AND user_require_make = 1) THEN 'daichucan' + END AS counttype + FROM mall_order + + GROUP BY counttype + + + + + + + + + + +