Commit 7a7ca4293c6c1b7ca49b9c6a3665fd2487e105b1

Authored by 芋道源码
Committed by Gitee
2 parents cccad2c6 3e66a922

!1060 【功能新增】商城: 满减送活动下单后,赠送积分、优惠劵、包邮

Merge pull request !1060 from puhui999/develop
Showing 17 changed files with 214 additions and 49 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java
@@ -3,9 +3,10 @@ package cn.iocoder.yudao.module.promotion.api.coupon; @@ -3,9 +3,10 @@ package cn.iocoder.yudao.module.promotion.api.coupon;
3 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; 3 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO;
4 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; 4 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
5 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO; 5 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO;
6 -  
7 import jakarta.validation.Valid; 6 import jakarta.validation.Valid;
8 7
  8 +import java.util.List;
  9 +
9 /** 10 /**
10 * 优惠劵 API 接口 11 * 优惠劵 API 接口
11 * 12 *
@@ -35,4 +36,13 @@ public interface CouponApi { @@ -35,4 +36,13 @@ public interface CouponApi {
35 */ 36 */
36 CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO); 37 CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO);
37 38
  39 + /**
  40 + * 【管理员】给指定用户批量发送优惠券
  41 + *
  42 + * @param templateIds 优惠劵编号的数组
  43 + * @param counts 优惠券数量的数组
  44 + * @param userId 用户编号
  45 + */
  46 + void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId);
  47 +
38 } 48 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java
@@ -7,10 +7,11 @@ import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO; @@ -7,10 +7,11 @@ import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO;
7 import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; 7 import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
9 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; 9 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
  10 +import jakarta.annotation.Resource;
10 import org.springframework.stereotype.Service; 11 import org.springframework.stereotype.Service;
11 import org.springframework.validation.annotation.Validated; 12 import org.springframework.validation.annotation.Validated;
12 13
13 -import jakarta.annotation.Resource; 14 +import java.util.List;
14 15
15 /** 16 /**
16 * 优惠劵 API 实现类 17 * 优惠劵 API 实现类
@@ -41,4 +42,9 @@ public class CouponApiImpl implements CouponApi { @@ -41,4 +42,9 @@ public class CouponApiImpl implements CouponApi {
41 return CouponConvert.INSTANCE.convert(coupon); 42 return CouponConvert.INSTANCE.convert(coupon);
42 } 43 }
43 44
  45 + @Override
  46 + public void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId) {
  47 + couponService.takeCouponsByAdmin(templateIds, counts, userId);
  48 + }
  49 +
44 } 50 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java
@@ -96,7 +96,7 @@ public class RewardActivityBaseVO { @@ -96,7 +96,7 @@ public class RewardActivityBaseVO {
96 @AssertTrue(message = "优惠劵和数量必须一一对应") 96 @AssertTrue(message = "优惠劵和数量必须一一对应")
97 @JsonIgnore 97 @JsonIgnore
98 public boolean isCouponCountsValid() { 98 public boolean isCouponCountsValid() {
99 - return BooleanUtil.isFalse(givePoint) || CollUtil.size(couponIds) == CollUtil.size(couponCounts); 99 + return BooleanUtil.isFalse(giveCoupon) || CollUtil.size(couponIds) == CollUtil.size(couponCounts);
100 } 100 }
101 101
102 @AssertTrue(message = "赠送的积分不能小于 1") 102 @AssertTrue(message = "赠送的积分不能小于 1")
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
@@ -340,7 +340,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -340,7 +340,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
340 CombinationRecordStatusEnum.FAILED); 340 CombinationRecordStatusEnum.FAILED);
341 // 2. 订单取消 341 // 2. 订单取消
342 headAndRecords.forEach(item -> tradeOrderApi.cancelPaidOrder(item.getUserId(), item.getOrderId(), 342 headAndRecords.forEach(item -> tradeOrderApi.cancelPaidOrder(item.getUserId(), item.getOrderId(),
343 - TradeOrderCancelTypeEnum.COMBINATION_CLOSE)); 343 + TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getType()));
344 } 344 }
345 345
346 /** 346 /**
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
@@ -106,6 +106,15 @@ public interface CouponService { @@ -106,6 +106,15 @@ public interface CouponService {
106 } 106 }
107 107
108 /** 108 /**
  109 + * 【管理员】给指定用户批量发送优惠券
  110 + *
  111 + * @param templateIds 优惠劵编号的数组
  112 + * @param counts 优惠券数量的数组
  113 + * @param userId 用户编号
  114 + */
  115 + void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId);
  116 +
  117 + /**
109 * 【会员】领取优惠券 118 * 【会员】领取优惠券
110 * 119 *
111 * @param templateId 优惠券模板编号 120 * @param templateId 优惠券模板编号
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
@@ -19,19 +19,19 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponMapper; @@ -19,19 +19,19 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponMapper;
19 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; 19 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
20 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; 20 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
21 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; 21 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
  22 +import jakarta.annotation.Resource;
22 import lombok.extern.slf4j.Slf4j; 23 import lombok.extern.slf4j.Slf4j;
23 import org.springframework.stereotype.Service; 24 import org.springframework.stereotype.Service;
24 import org.springframework.transaction.annotation.Transactional; 25 import org.springframework.transaction.annotation.Transactional;
25 import org.springframework.validation.annotation.Validated; 26 import org.springframework.validation.annotation.Validated;
26 27
27 -import jakarta.annotation.Resource;  
28 -  
29 import java.time.LocalDateTime; 28 import java.time.LocalDateTime;
30 import java.util.*; 29 import java.util.*;
31 import java.util.stream.Collectors; 30 import java.util.stream.Collectors;
32 31
33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 32 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
34 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 33 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
35 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; 35 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
36 import static java.util.Arrays.asList; 36 import static java.util.Arrays.asList;
37 37
@@ -175,11 +175,35 @@ public class CouponServiceImpl implements CouponService { @@ -175,11 +175,35 @@ public class CouponServiceImpl implements CouponService {
175 // 3. 批量保存优惠劵 175 // 3. 批量保存优惠劵
176 couponMapper.insertBatch(convertList(userIds, userId -> CouponConvert.INSTANCE.convert(template, userId))); 176 couponMapper.insertBatch(convertList(userIds, userId -> CouponConvert.INSTANCE.convert(template, userId)));
177 177
178 - // 3. 增加优惠劵模板的领取数量 178 + // 4. 增加优惠劵模板的领取数量
179 couponTemplateService.updateCouponTemplateTakeCount(templateId, userIds.size()); 179 couponTemplateService.updateCouponTemplateTakeCount(templateId, userIds.size());
180 } 180 }
181 181
182 @Override 182 @Override
  183 + public void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId) {
  184 + // 1. 获得优惠券模版
  185 + List<CouponTemplateDO> templateList = couponTemplateService.getCouponTemplateList(templateIds);
  186 + if (CollUtil.isEmpty(templateList)) {
  187 + return;
  188 + }
  189 +
  190 + Map<Long, CouponTemplateDO> templateMap = convertMap(templateList, CouponTemplateDO::getId);
  191 + // 2.1 批量构建优惠券
  192 + List<CouponDO> couponList = new ArrayList<>();
  193 + for (int i = 0; i < templateIds.size(); i++) {
  194 + int finalI = i;
  195 + findAndThen(templateMap, templateIds.get(i), template -> {
  196 + for (int j = 0; j < counts.get(finalI); j++) {
  197 + couponList.add(CouponConvert.INSTANCE.convert(template, userId)
  198 + .setTakeType(CouponTakeTypeEnum.ADMIN.getValue()));
  199 + }
  200 + });
  201 + }
  202 + // 2.2 批量保存优惠券
  203 + couponMapper.insertBatch(couponList);
  204 + }
  205 +
  206 + @Override
183 @Transactional(rollbackFor = Exception.class) 207 @Transactional(rollbackFor = Exception.class)
184 public void takeCouponByRegister(Long userId) { 208 public void takeCouponByRegister(Long userId) {
185 List<CouponTemplateDO> templates = couponTemplateService.getCouponTemplateListByTakeType(CouponTakeTypeEnum.REGISTER); 209 List<CouponTemplateDO> templates = couponTemplateService.getCouponTemplateListByTakeType(CouponTakeTypeEnum.REGISTER);
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java
1 package cn.iocoder.yudao.module.trade.api.order; 1 package cn.iocoder.yudao.module.trade.api.order;
2 2
3 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; 3 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
4 -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum;  
5 4
6 import java.util.Collection; 5 import java.util.Collection;
7 import java.util.List; 6 import java.util.List;
@@ -34,8 +33,8 @@ public interface TradeOrderApi { @@ -34,8 +33,8 @@ public interface TradeOrderApi {
34 * 33 *
35 * @param userId 用户编号 34 * @param userId 用户编号
36 * @param orderId 订单编号 35 * @param orderId 订单编号
37 - * @param cancelTypeEnum 取消类型 36 + * @param cancelType 取消类型
38 */ 37 */
39 - void cancelPaidOrder(Long userId, Long orderId, TradeOrderCancelTypeEnum cancelTypeEnum); 38 + void cancelPaidOrder(Long userId, Long orderId, Integer cancelType);
40 39
41 } 40 }
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
@@ -60,6 +60,7 @@ public interface ErrorCodeConstants { @@ -60,6 +60,7 @@ public interface ErrorCodeConstants {
60 ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板"); 60 ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板");
61 ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵"); 61 ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵");
62 ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_005, "参与秒杀的商品,超过了秒杀总限购数量"); 62 ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_005, "参与秒杀的商品,超过了秒杀总限购数量");
  63 + ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_006, "计算快递运费异常,配送方式不匹配");
63 64
64 // ========== 物流 Express 模块 1-011-004-000 ========== 65 // ========== 物流 Express 模块 1-011-004-000 ==========
65 ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在"); 66 ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在");
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.api.order; @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.api.order;
2 2
3 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; 3 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
4 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; 4 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
5 -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum;  
6 import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; 5 import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
7 import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; 6 import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
8 import jakarta.annotation.Resource; 7 import jakarta.annotation.Resource;
@@ -37,8 +36,8 @@ public class TradeOrderApiImpl implements TradeOrderApi { @@ -37,8 +36,8 @@ public class TradeOrderApiImpl implements TradeOrderApi {
37 } 36 }
38 37
39 @Override 38 @Override
40 - public void cancelPaidOrder(Long userId, Long orderId, TradeOrderCancelTypeEnum cancelTypeEnum) {  
41 - tradeOrderUpdateService.cancelPaidOrder(userId, orderId, cancelTypeEnum); 39 + public void cancelPaidOrder(Long userId, Long orderId, Integer cancelType) {
  40 + tradeOrderUpdateService.cancelPaidOrder(userId, orderId, cancelType);
42 } 41 }
43 42
44 } 43 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
@@ -16,6 +16,7 @@ import com.baomidou.mybatisplus.annotation.TableName; @@ -16,6 +16,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
16 import lombok.*; 16 import lombok.*;
17 17
18 import java.time.LocalDateTime; 18 import java.time.LocalDateTime;
  19 +import java.util.List;
19 20
20 /** 21 /**
21 * 交易订单 DO 22 * 交易订单 DO
@@ -290,6 +291,18 @@ public class TradeOrderDO extends BaseDO { @@ -290,6 +291,18 @@ public class TradeOrderDO extends BaseDO {
290 * VIP 减免金额,单位:分 291 * VIP 减免金额,单位:分
291 */ 292 */
292 private Integer vipPrice; 293 private Integer vipPrice;
  294 + /**
  295 + * 赠送的优惠劵编号的数组
  296 + *
  297 + * 目的:用于后续取消或者售后订单时,需要扣减赠送
  298 + */
  299 + private List<Long> couponIds;
  300 + /**
  301 + * 赠送的优惠券数量的数组
  302 + *
  303 + * 目的:用于后续取消或者售后订单时,需要扣减赠送
  304 + */
  305 + private List<Integer> couponCounts;
293 306
294 /** 307 /**
295 * 秒杀活动编号 308 * 秒杀活动编号
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java
@@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettle @@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettle
9 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; 9 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO;
10 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; 10 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
11 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 11 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
12 -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum;  
13 import jakarta.validation.constraints.NotNull; 12 import jakarta.validation.constraints.NotNull;
14 13
15 /** 14 /**
@@ -186,14 +185,13 @@ public interface TradeOrderUpdateService { @@ -186,14 +185,13 @@ public interface TradeOrderUpdateService {
186 */ 185 */
187 void updateOrderCombinationInfo(Long orderId, Long activityId, Long combinationRecordId, Long headId); 186 void updateOrderCombinationInfo(Long orderId, Long activityId, Long combinationRecordId, Long headId);
188 187
189 - // TODO @puhui999:不传递枚举哈。因为 rpc 不好支持。  
190 /** 188 /**
191 * 取消支付订单 189 * 取消支付订单
192 * 190 *
193 * @param userId 用户编号 191 * @param userId 用户编号
194 * @param orderId 订单编号 192 * @param orderId 订单编号
195 - * @param cancelType 取消类型 193 + * @param cancelType 取消类型
196 */ 194 */
197 - void cancelPaidOrder(Long userId, Long orderId, TradeOrderCancelTypeEnum cancelType); 195 + void cancelPaidOrder(Long userId, Long orderId, Integer cancelType);
198 196
199 } 197 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
@@ -201,6 +201,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -201,6 +201,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
201 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); 201 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
202 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); 202 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
203 order.setUserIp(getClientIP()).setTerminal(getTerminal()); 203 order.setUserIp(getClientIP()).setTerminal(getTerminal());
  204 + // 优惠券
  205 + order.setCouponIds(calculateRespBO.getCouponIds()).setCouponCounts(calculateRespBO.getCouponCounts());
204 // 支付 + 退款信息 206 // 支付 + 退款信息
205 order.setAdjustPrice(0).setPayStatus(false); 207 order.setAdjustPrice(0).setPayStatus(false);
206 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); 208 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
@@ -858,8 +860,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -858,8 +860,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
858 860
859 @Override 861 @Override
860 @Transactional(rollbackFor = Exception.class) 862 @Transactional(rollbackFor = Exception.class)
861 - public void cancelPaidOrder(Long userId, Long orderId, TradeOrderCancelTypeEnum cancelType) {  
862 - // TODO @puhui999:这里校验下 cancelType 只允许拼团关闭; 863 + public void cancelPaidOrder(Long userId, Long orderId, Integer cancelType) {
  864 + // 1. 这里校验下 cancelType 只允许拼团关闭;
  865 + if (!TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getType().equals(cancelType)) {
  866 + return;
  867 + }
863 // 1.1 检验订单存在 868 // 1.1 检验订单存在
864 TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderId, userId); 869 TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderId, userId);
865 if (order == null) { 870 if (order == null) {
@@ -876,13 +881,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -876,13 +881,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
876 } 881 }
877 882
878 // 2.1 取消订单 883 // 2.1 取消订单
879 - cancelOrder0(order, cancelType); 884 + cancelOrder0(order, TradeOrderCancelTypeEnum.COMBINATION_CLOSE);
880 // 2.2 创建退款单 885 // 2.2 创建退款单
881 payRefundApi.createRefund(new PayRefundCreateReqDTO() 886 payRefundApi.createRefund(new PayRefundCreateReqDTO()
882 .setAppKey(tradeOrderProperties.getPayAppKey()).setUserIp(getClientIP()) // 支付应用 887 .setAppKey(tradeOrderProperties.getPayAppKey()).setUserIp(getClientIP()) // 支付应用
883 .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号 888 .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号
884 .setMerchantRefundId(String.valueOf(order.getId())) 889 .setMerchantRefundId(String.valueOf(order.getId()))
885 - .setReason(cancelType.getName()).setPrice(order.getPayPrice()));// 价格信息 890 + .setReason(TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getName()).setPrice(order.getPayPrice()));// 价格信息
886 } 891 }
887 892
888 /** 893 /**
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCouponOrderHandler.java
1 package cn.iocoder.yudao.module.trade.service.order.handler; 1 package cn.iocoder.yudao.module.trade.service.order.handler;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; 4 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
4 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; 5 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
5 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 6 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
6 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; 7 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
  8 +import jakarta.annotation.Resource;
7 import org.springframework.stereotype.Component; 9 import org.springframework.stereotype.Component;
8 10
9 -import jakarta.annotation.Resource;  
10 import java.util.List; 11 import java.util.List;
11 12
12 /** 13 /**
@@ -31,12 +32,26 @@ public class TradeCouponOrderHandler implements TradeOrderHandler { @@ -31,12 +32,26 @@ public class TradeCouponOrderHandler implements TradeOrderHandler {
31 } 32 }
32 33
33 @Override 34 @Override
  35 + public void afterPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
  36 + if (CollUtil.isEmpty(order.getCouponIds())) {
  37 + return;
  38 + }
  39 + // 赠送优惠券
  40 + couponApi.takeCouponsByAdmin(order.getCouponIds(), order.getCouponCounts(), order.getUserId());
  41 + }
  42 +
  43 + @Override
34 public void afterCancelOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) { 44 public void afterCancelOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
35 - if (order.getCouponId() == null || order.getCouponId() <= 0) { 45 + // 情况一:退还订单使用的优惠券
  46 + if (order.getCouponId() != null && order.getCouponId() > 0) {
  47 + // 退回优惠劵
  48 + couponApi.returnUsedCoupon(order.getCouponId());
  49 + }
  50 + // 情况二:收回赠送的优惠券
  51 + if (CollUtil.isEmpty(order.getCouponIds())) {
36 return; 52 return;
37 } 53 }
38 - // 退回优惠劵  
39 - couponApi.returnUsedCoupon(order.getCouponId()); 54 + // TODO @puhui999: 收回优惠券再考虑一下,是直接删除券还是改个状态
40 } 55 }
41 56
42 } 57 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
@@ -68,6 +68,20 @@ public class TradePriceCalculateRespBO { @@ -68,6 +68,20 @@ public class TradePriceCalculateRespBO {
68 private Long bargainActivityId; 68 private Long bargainActivityId;
69 69
70 /** 70 /**
  71 + * 是否包邮
  72 + */
  73 + private Boolean freeDelivery;
  74 +
  75 + /**
  76 + * 赠送的优惠劵编号的数组
  77 + */
  78 + private List<Long> couponIds;
  79 + /**
  80 + * 赠送的优惠券数量的数组
  81 + */
  82 + private List<Integer> couponCounts;
  83 +
  84 + /**
71 * 订单价格 85 * 订单价格
72 */ 86 */
73 @Data 87 @Data
@@ -213,8 +227,19 @@ public class TradePriceCalculateRespBO { @@ -213,8 +227,19 @@ public class TradePriceCalculateRespBO {
213 */ 227 */
214 private Long categoryId; 228 private Long categoryId;
215 229
  230 + // ========== 物流相关字段 =========
  231 +
216 /** 232 /**
217 - * 运费模板 Id 233 + * 配送方式数组
  234 + *
  235 + * 对应 DeliveryTypeEnum 枚举
  236 + */
  237 + private List<Integer> deliveryTypes;
  238 +
  239 + /**
  240 + * 物流配置模板编号
  241 + *
  242 + * 对应 TradeDeliveryExpressTemplateDO 的 id 编号
218 */ 243 */
219 private Long deliveryTemplateId; 244 private Long deliveryTemplateId;
220 245
@@ -234,7 +259,7 @@ public class TradePriceCalculateRespBO { @@ -234,7 +259,7 @@ public class TradePriceCalculateRespBO {
234 private List<ProductPropertyValueDetailRespDTO> properties; 259 private List<ProductPropertyValueDetailRespDTO> properties;
235 260
236 /** 261 /**
237 - * 使用的积分 262 + * 赠送的积分
238 */ 263 */
239 private Integer givePoint; 264 private Integer givePoint;
240 265
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
@@ -6,8 +6,6 @@ import cn.hutool.core.util.StrUtil; @@ -6,8 +6,6 @@ import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
7 import cn.iocoder.yudao.module.member.api.address.MemberAddressApi; 7 import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
8 import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO; 8 import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
9 -import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;  
10 -import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;  
11 import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; 9 import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
12 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; 10 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
13 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; 11 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
@@ -30,8 +28,7 @@ import java.util.Set; @@ -30,8 +28,7 @@ import java.util.Set;
30 28
31 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
32 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 30 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
33 -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PICK_UP_STORE_NOT_EXISTS;  
34 -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND; 31 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
35 32
36 /** 33 /**
37 * 运费的 {@link TradePriceCalculator} 实现类 34 * 运费的 {@link TradePriceCalculator} 实现类
@@ -52,19 +49,15 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -52,19 +49,15 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
52 private DeliveryExpressTemplateService deliveryExpressTemplateService; 49 private DeliveryExpressTemplateService deliveryExpressTemplateService;
53 @Resource 50 @Resource
54 private TradeConfigService tradeConfigService; 51 private TradeConfigService tradeConfigService;
55 - @Resource  
56 - private ProductSpuApi productSpuApi;  
57 52
58 @Override 53 @Override
59 public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { 54 public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
60 if (param.getDeliveryType() == null) { 55 if (param.getDeliveryType() == null) {
61 return; 56 return;
62 } 57 }
63 - // TODO @puhui999:1)TradePriceCalculateRespBO 传递进来 delveryType 配送方式,减少读取;2)如果不匹配,抛出业务异常; = = 不然就不扣钱啦。  
64 // 校验是不是存在商品不能门店自提,或者不能快递发货的情况。就是说,配送方式不匹配哈 58 // 校验是不是存在商品不能门店自提,或者不能快递发货的情况。就是说,配送方式不匹配哈
65 - List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(convertSet(result.getItems(), OrderItem::getSpuId));  
66 - if (anyMatch(spuList, item -> !item.getDeliveryTypes().contains(param.getDeliveryType()))) {  
67 - return; 59 + if (anyMatch(result.getItems(), item -> !item.getDeliveryTypes().contains(param.getDeliveryType()))) {
  60 + throw exception(PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL);
68 } 61 }
69 62
70 if (DeliveryTypeEnum.PICK_UP.getType().equals(param.getDeliveryType())) { 63 if (DeliveryTypeEnum.PICK_UP.getType().equals(param.getDeliveryType())) {
@@ -101,7 +94,12 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -101,7 +94,12 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
101 return; 94 return;
102 } 95 }
103 96
104 - // 情况二:快递模版 97 + // 情况二:活动包邮
  98 + if (Boolean.TRUE.equals(result.getFreeDelivery())) {
  99 + return;
  100 + }
  101 +
  102 + // 情况三:快递模版
105 // 2.1 过滤出已选中的商品 SKU 103 // 2.1 过滤出已选中的商品 SKU
106 List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected); 104 List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected);
107 Set<Long> deliveryTemplateIds = convertSet(selectedItem, OrderItem::getDeliveryTemplateId); 105 Set<Long> deliveryTemplateIds = convertSet(selectedItem, OrderItem::getDeliveryTemplateId);
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
@@ -31,8 +31,8 @@ public class TradePriceCalculatorHelper { @@ -31,8 +31,8 @@ public class TradePriceCalculatorHelper {
31 List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) { 31 List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) {
32 // 创建 PriceCalculateRespDTO 对象 32 // 创建 PriceCalculateRespDTO 对象
33 TradePriceCalculateRespBO result = new TradePriceCalculateRespBO(); 33 TradePriceCalculateRespBO result = new TradePriceCalculateRespBO();
34 - result.setType(getOrderType(param));  
35 - result.setPromotions(new ArrayList<>()); 34 + result.setType(getOrderType(param)).setPromotions(new ArrayList<>())
  35 + .setCouponIds(new ArrayList<>()).setCouponCounts(new ArrayList<>());
36 36
37 // 创建它的 OrderItem 属性 37 // 创建它的 OrderItem 属性
38 result.setItems(new ArrayList<>(param.getItems().size())); 38 result.setItems(new ArrayList<>(param.getItems().size()));
@@ -60,7 +60,7 @@ public class TradePriceCalculatorHelper { @@ -60,7 +60,7 @@ public class TradePriceCalculatorHelper {
60 .setWeight(sku.getWeight()).setVolume(sku.getVolume()); 60 .setWeight(sku.getWeight()).setVolume(sku.getVolume());
61 // spu 信息 61 // spu 信息
62 orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId()) 62 orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId())
63 - .setDeliveryTemplateId(spu.getDeliveryTemplateId()) 63 + .setDeliveryTypes(spu.getDeliveryTypes()).setDeliveryTemplateId(spu.getDeliveryTemplateId())
64 .setGivePoint(spu.getGiveIntegral()).setUsePoint(0); 64 .setGivePoint(spu.getGiveIntegral()).setUsePoint(0);
65 if (StrUtil.isBlank(orderItem.getPicUrl())) { 65 if (StrUtil.isBlank(orderItem.getPicUrl())) {
66 orderItem.setPicUrl(spu.getPicUrl()); 66 orderItem.setPicUrl(spu.getPicUrl());
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java
@@ -3,9 +3,11 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; @@ -3,9 +3,11 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
6 import cn.iocoder.yudao.module.promotion.api.reward.RewardActivityApi; 7 import cn.iocoder.yudao.module.promotion.api.reward.RewardActivityApi;
7 import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; 8 import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
8 import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; 9 import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
  10 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
9 import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; 11 import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
10 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; 12 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
11 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; 13 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
@@ -14,7 +16,10 @@ import jakarta.annotation.Resource; @@ -14,7 +16,10 @@ import jakarta.annotation.Resource;
14 import org.springframework.core.annotation.Order; 16 import org.springframework.core.annotation.Order;
15 import org.springframework.stereotype.Component; 17 import org.springframework.stereotype.Component;
16 18
  19 +import java.util.ArrayList;
  20 +import java.util.Comparator;
17 import java.util.List; 21 import java.util.List;
  22 +import java.util.Objects;
18 23
19 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 24 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
20 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; 25 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
@@ -61,7 +66,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator @@ -61,7 +66,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
61 if (rule == null) { 66 if (rule == null) {
62 TradePriceCalculatorHelper.addNotMatchPromotion(result, orderItems, 67 TradePriceCalculatorHelper.addNotMatchPromotion(result, orderItems,
63 rewardActivity.getId(), rewardActivity.getName(), PromotionTypeEnum.REWARD_ACTIVITY.getType(), 68 rewardActivity.getId(), rewardActivity.getName(), PromotionTypeEnum.REWARD_ACTIVITY.getType(),
64 - getRewardActivityNotMeetTip(rewardActivity)); 69 + getRewardActivityNotMeetTip(rewardActivity, orderItems));
65 return; 70 return;
66 } 71 }
67 72
@@ -84,6 +89,36 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator @@ -84,6 +89,36 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
84 TradePriceCalculatorHelper.recountPayPrice(orderItem); 89 TradePriceCalculatorHelper.recountPayPrice(orderItem);
85 } 90 }
86 TradePriceCalculatorHelper.recountAllPrice(result); 91 TradePriceCalculatorHelper.recountAllPrice(result);
  92 +
  93 + // 4.1 记录赠送的积分
  94 + if (rule.getGivePoint()) {
  95 + List<Integer> dividePoints = TradePriceCalculatorHelper.dividePrice(orderItems, rule.getPoint());
  96 + for (int i = 0; i < orderItems.size(); i++) {
  97 + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i);
  98 + // 商品可能赠送了积分,所以这里要加上
  99 + orderItem.setGivePoint(orderItem.getGivePoint() + dividePoints.get(i));
  100 + }
  101 + }
  102 + // 4.2 记录订单是否包邮
  103 + if (rule.getFreeDelivery()) {
  104 + // 只要满足一个活动包邮那么这单就包邮
  105 + result.setFreeDelivery(true);
  106 + }
  107 + // 4.3 记录赠送的优惠券
  108 + if (rule.getGiveCoupon()) {
  109 + for (int i = 0; i < rule.getCouponIds().size(); i++) {
  110 + Long couponId = result.getCouponIds().get(i);
  111 + Integer couponCount = result.getCouponCounts().get(i);
  112 + int index = CollUtil.indexOf(result.getCouponIds(), id -> Objects.equals(couponId, id));
  113 + if (index != -1) { // 情况一:别的满减活动送过同类优惠券,则直接增加数量
  114 + List<Integer> couponCounts = result.getCouponCounts();
  115 + couponCounts.set(index, couponCounts.get(index) + couponCount);
  116 + result.setCouponCounts(couponCounts);
  117 + } else { // 情况二:还没有赠送的优惠券
  118 + result.setCouponIds(rule.getCouponIds()).setCouponCounts(rule.getCouponCounts());
  119 + }
  120 + }
  121 + }
87 } 122 }
88 123
89 /** 124 /**
@@ -95,9 +130,21 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator @@ -95,9 +130,21 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
95 */ 130 */
96 private List<TradePriceCalculateRespBO.OrderItem> filterMatchActivityOrderItems(TradePriceCalculateRespBO result, 131 private List<TradePriceCalculateRespBO.OrderItem> filterMatchActivityOrderItems(TradePriceCalculateRespBO result,
97 RewardActivityMatchRespDTO rewardActivity) { 132 RewardActivityMatchRespDTO rewardActivity) {
98 - // TODO @puhui999:是不是得根据类型过滤哈  
99 - return filterList(result.getItems(),  
100 - orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getSpuId())); 133 + // 情况一:全部商品都可以参与
  134 + if (PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) {
  135 + return result.getItems();
  136 + }
  137 + // 情况二:指定商品参与
  138 + if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope())) {
  139 + return filterList(result.getItems(),
  140 + orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getSpuId()));
  141 + }
  142 + // 情况三:指定商品类型参与
  143 + if (PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) {
  144 + return filterList(result.getItems(),
  145 + orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getCategoryId()));
  146 + }
  147 + return List.of();
101 } 148 }
102 149
103 /** 150 /**
@@ -130,14 +177,30 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator @@ -130,14 +177,30 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
130 } 177 }
131 178
132 /** 179 /**
133 - * 获得满减送活动部匹配时的提示 180 + * 获得满减送活动不匹配时的提示
134 * 181 *
135 * @param rewardActivity 满减送活动 182 * @param rewardActivity 满减送活动
136 * @return 提示 183 * @return 提示
137 */ 184 */
138 - private String getRewardActivityNotMeetTip(RewardActivityMatchRespDTO rewardActivity) {  
139 - // TODO 芋艿:后面再想想;应该找第一个规则,算下还差多少即可。  
140 - return "TODO"; 185 + private String getRewardActivityNotMeetTip(RewardActivityMatchRespDTO rewardActivity,
  186 + List<TradePriceCalculateRespBO.OrderItem> orderItems) {
  187 + // 1. 计算数量和价格
  188 + Integer count = TradePriceCalculatorHelper.calculateTotalCount(orderItems);
  189 + Integer price = TradePriceCalculatorHelper.calculateTotalPayPrice(orderItems);
  190 + assert count != null && price != null;
  191 +
  192 + // 2. 构建不满足时的提示信息-按最低档规则算
  193 + String meetTip = "满减送:购满 {} {},可以减 {} 元";
  194 + List<RewardActivityMatchRespDTO.Rule> rules = new ArrayList<>(rewardActivity.getRules());
  195 + rules.sort(Comparator.comparing(RewardActivityMatchRespDTO.Rule::getLimit)); // 按优惠门槛降序
  196 + RewardActivityMatchRespDTO.Rule rule = rules.get(0);
  197 + if (PromotionConditionTypeEnum.PRICE.getType().equals(rewardActivity.getConditionType())) {
  198 + return StrUtil.format(meetTip, rule.getLimit(), "元", MoneyUtils.fenToYuanStr(rule.getDiscountPrice()));
  199 + }
  200 + if (PromotionConditionTypeEnum.COUNT.getType().equals(rewardActivity.getConditionType())) {
  201 + return StrUtil.format(meetTip, rule.getLimit(), "件", MoneyUtils.fenToYuanStr(rule.getDiscountPrice()));
  202 + }
  203 + return StrUtil.EMPTY;
141 } 204 }
142 205
143 } 206 }