feat:订单创建

pull/1121/head
梁宇奇 2025-04-03 14:35:15 +08:00
parent f2b809bc3c
commit 56e9a321b7
11 changed files with 324 additions and 87 deletions

View File

@ -0,0 +1,46 @@
package com.ruoyi.web.controller.xkt;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.XktBaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.web.controller.xkt.vo.order.StoreOrderAddReqVO;
import com.ruoyi.web.controller.xkt.vo.order.StoreOrderAddRespVO;
import com.ruoyi.xkt.dto.order.StoreOrderAddDTO;
import com.ruoyi.xkt.dto.order.StoreOrderAddResultDTO;
import com.ruoyi.xkt.service.IStoreOrderService;
import io.swagger.annotations.Api;
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;
/**
* @author liangyq
* @date 2025-04-03 14:18
*/
@Api(tags = "订单")
@RestController
@RequestMapping("/rest/v1/order")
public class StoreOrderController extends XktBaseController {
@Autowired
private IStoreOrderService storeOrderService;
/**
*
*/
// @PreAuthorize("@ss.hasPermi('system:order:add')")
@Log(title = "订单", businessType = BusinessType.INSERT)
@PostMapping
public R<StoreOrderAddRespVO> create(@RequestBody StoreOrderAddReqVO vo) {
StoreOrderAddDTO dto = BeanUtil.toBean(vo, StoreOrderAddDTO.class);
dto.setOrderUserId(SecurityUtils.getUserId());
StoreOrderAddResultDTO resultDTO = storeOrderService.createOrder(dto);
//TODO
return success();
}
}

View File

@ -0,0 +1,92 @@
package com.ruoyi.web.controller.xkt.vo.order;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* @author liangyq
* @date 2025-04-02 22:31
*/
@ApiModel
@Data
public class StoreOrderAddReqVO {
/**
* ID
*/
@ApiModelProperty("档口ID")
private Long storeId;
// /**
// * 下单用户ID
// */
// private Long orderUserId;
/**
*
*/
@ApiModelProperty("订单备注")
private String orderRemark;
/**
* ID
*/
@ApiModelProperty("物流ID")
private Long expressId;
/**
* -
*/
@ApiModelProperty("收货人-名称")
private String destinationContactName;
/**
* -
*/
@ApiModelProperty("收货人-电话")
private String destinationContactPhoneNumber;
/**
* -
*/
@ApiModelProperty("收货人-省编码")
private String destinationProvinceCode;
/**
* -
*/
@ApiModelProperty("收货人-市编码")
private String destinationCityCode;
/**
* -
*/
@ApiModelProperty("收货人-区县编码")
private String destinationCountyCode;
/**
* -
*/
@ApiModelProperty("收货人-详细地址")
private String destinationDetailAddress;
/**
* [1: 2:]
*/
@ApiModelProperty("发货方式[1:货其再发 2:有货先发]")
private Integer deliveryType;
/**
*
*/
@ApiModelProperty("最晚发货时间")
private Date deliveryEndTime;
/**
*
*/
@ApiModelProperty("明细列表")
private List<Detail> detailList;
@ApiModel
@Data
public static class Detail {
@ApiModelProperty("商品颜色尺码ID")
private Long storeProdColorSizeId;
@ApiModelProperty("商品数量")
private Integer goodsQuantity;
}
}

View File

@ -0,0 +1,14 @@
package com.ruoyi.web.controller.xkt.vo.order;
import io.swagger.annotations.ApiModel;
import lombok.Data;
/**
* @author liangyq
* @date 2025-04-02 22:31
*/
@ApiModel
@Data
public class StoreOrderAddRespVO {
}

View File

@ -0,0 +1,23 @@
package com.ruoyi.xkt.dto.order;
import com.ruoyi.xkt.domain.StoreOrder;
import com.ruoyi.xkt.domain.StoreOrderDetail;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author liangyq
* @date 2025-04-03 13:46
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StoreOrderAddResultDTO {
private StoreOrder order;
private List<StoreOrderDetail> orderDetails;
}

View File

@ -3,6 +3,7 @@ package com.ruoyi.xkt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.xkt.domain.StoreProductColorPrice;
import com.ruoyi.xkt.dto.storeProdColorPrice.StoreProdColorPriceDTO;
import org.springframework.stereotype.Repository;
import java.util.List;
@ -12,6 +13,7 @@ import java.util.List;
* @author ruoyi
* @date 2025-03-26
*/
@Repository
public interface StoreProductColorPriceMapper extends BaseMapper<StoreProductColorPrice> {
/**
*

View File

@ -2,6 +2,7 @@ package com.ruoyi.xkt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.xkt.domain.StoreProductColorSize;
import org.springframework.stereotype.Repository;
import java.util.List;
@ -11,6 +12,7 @@ import java.util.List;
* @author ruoyi
* @date 2025-03-26
*/
@Repository
public interface StoreProductColorSizeMapper extends BaseMapper<StoreProductColorSize> {
/**
*

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.xkt.domain.StoreProduct;
import com.ruoyi.xkt.dto.storeProduct.StoreProdFuzzyResDTO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@ -13,6 +14,7 @@ import java.util.List;
* @author ruoyi
* @date 2025-03-26
*/
@Repository
public interface StoreProductMapper extends BaseMapper<StoreProduct> {
/**
*

View File

@ -0,0 +1,28 @@
package com.ruoyi.xkt.service;
import com.ruoyi.xkt.domain.ExpressFeeConfig;
/**
* @author liangyq
* @date 2025-04-03 13:35
*/
public interface IExpressService {
/**
*
*
* @param expressId
*/
void checkExpress(Long expressId);
/**
*
*
* @param expressId
* @param provinceCode
* @param cityCode
* @param countyCode
* @return
*/
ExpressFeeConfig getExpressFeeConfig(Long expressId, String provinceCode, String cityCode, String countyCode);
}

View File

@ -1,6 +1,7 @@
package com.ruoyi.xkt.service;
import com.ruoyi.xkt.dto.order.StoreOrderAddDTO;
import com.ruoyi.xkt.dto.order.StoreOrderAddResultDTO;
import com.ruoyi.xkt.dto.order.StoreOrderInfoDTO;
/**
@ -14,5 +15,5 @@ public interface IStoreOrderService {
* @param storeOrderAddDTO
* @return
*/
StoreOrderInfoDTO createOrder(StoreOrderAddDTO storeOrderAddDTO);
StoreOrderAddResultDTO createOrder(StoreOrderAddDTO storeOrderAddDTO);
}

View File

@ -0,0 +1,70 @@
package com.ruoyi.xkt.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.xkt.domain.Express;
import com.ruoyi.xkt.domain.ExpressFeeConfig;
import com.ruoyi.xkt.mapper.ExpressFeeConfigMapper;
import com.ruoyi.xkt.mapper.ExpressMapper;
import com.ruoyi.xkt.service.IExpressService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author liangyq
* @date 2025-04-03 13:37
*/
@Service
public class ExpressServiceImpl implements IExpressService {
@Autowired
private ExpressMapper expressMapper;
@Autowired
private ExpressFeeConfigMapper expressFeeConfigMapper;
@Override
public void checkExpress(Long expressId) {
Assert.notNull(expressId);
Express express = expressMapper.selectById(expressId);
Assert.isTrue(BeanValidators.exists(express), "快递不存在");
Assert.isTrue(express.getSystemDeliverAccess(), "快递不可用");
}
@Override
public ExpressFeeConfig getExpressFeeConfig(Long expressId, String provinceCode, String cityCode,
String countyCode) {
Assert.notNull(expressId);
Assert.notEmpty(provinceCode);
Assert.notEmpty(cityCode);
Assert.notEmpty(countyCode);
Map<String, ExpressFeeConfig> map = expressFeeConfigMapper.selectList(Wrappers.lambdaQuery(ExpressFeeConfig.class)
.eq(ExpressFeeConfig::getExpressId, expressId)
.in(ExpressFeeConfig::getRegionCode, Arrays.asList(provinceCode, cityCode, countyCode)))
.stream()
//过滤掉已被删除的配置
.filter(BeanValidators::exists)
.collect(Collectors.toMap(o -> o.getRegionCode(), o -> o, (n, o) -> n));
ExpressFeeConfig expressFeeConfig = null;
if (CollUtil.isNotEmpty(map)) {
if (map.size() == 1) {
expressFeeConfig = CollUtil.getFirst(map.values());
} else {
expressFeeConfig = map.get(countyCode);
//按区市省从小到大去匹配
if (expressFeeConfig == null) {
expressFeeConfig = map.get(cityCode);
if (expressFeeConfig == null) {
expressFeeConfig = map.get(provinceCode);
}
}
}
}
return expressFeeConfig;
}
}

View File

@ -1,20 +1,19 @@
package com.ruoyi.xkt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.XktBaseEntity;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.xkt.domain.*;
import com.ruoyi.xkt.dto.order.StoreOrderAddDTO;
import com.ruoyi.xkt.dto.order.StoreOrderDetailInfoDTO;
import com.ruoyi.xkt.dto.order.StoreOrderInfoDTO;
import com.ruoyi.xkt.dto.order.StoreOrderAddResultDTO;
import com.ruoyi.xkt.enums.*;
import com.ruoyi.xkt.mapper.*;
import com.ruoyi.xkt.service.IExpressService;
import com.ruoyi.xkt.service.IStoreOrderService;
import com.ruoyi.xkt.service.IVoucherSequenceService;
import org.springframework.beans.factory.annotation.Autowired;
@ -40,47 +39,47 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
@Autowired
private StoreOrderExpressTrackMapper storeOrderExpressTrackMapper;
@Autowired
private ExpressMapper expressMapper;
@Autowired
private ExpressFeeConfigMapper expressFeeConfigMapper;
private IExpressService expressService;
@Autowired
private StoreProductMapper storeProductMapper;
@Autowired
private StoreProductColorSizeMapper storeProductColorSizeMapper;
@Autowired
private StoreProductColorPriceMapper storeProductColorPriceMapper;
@Autowired
private IVoucherSequenceService voucherSequenceService;
@Transactional
@Override
public StoreOrderInfoDTO createOrder(StoreOrderAddDTO storeOrderAddDTO) {
public StoreOrderAddResultDTO createOrder(StoreOrderAddDTO storeOrderAddDTO) {
Long orderUserId = storeOrderAddDTO.getOrderUserId();
Long storeId = storeOrderAddDTO.getStoreId();
Long expressId = storeOrderAddDTO.getExpressId();
//校验
checkExpress(expressId);
checkDelivery(storeOrderAddDTO.getDeliveryType(),
storeOrderAddDTO.getDeliveryEndTime());
expressService.checkExpress(expressId);
checkDelivery(storeOrderAddDTO.getDeliveryType(), storeOrderAddDTO.getDeliveryEndTime());
Map<Long, StoreProductColorSize> spcsMap = checkOrderDetailThenRtnSpcsMap(storeId,
storeOrderAddDTO.getDetailList());
//快递费配置
ExpressFeeConfig expressFeeConfig = getExpressFeeConfig(expressId,
ExpressFeeConfig expressFeeConfig = expressService.getExpressFeeConfig(expressId,
storeOrderAddDTO.getDestinationProvinceCode(), storeOrderAddDTO.getDestinationCityCode(),
storeOrderAddDTO.getDestinationCountyCode());
Assert.isTrue(BeanValidators.exists(expressFeeConfig), "无快递费用配置");
boolean isFirstExpressItem = true;
//生成订单明细
List<StoreOrderDetail> storeOrderDetailList = new ArrayList<>(storeOrderAddDTO.getDetailList().size());
List<StoreOrderDetail> orderDetailList = new ArrayList<>(storeOrderAddDTO.getDetailList().size());
int orderGoodsQuantity = 0;
BigDecimal orderGoodsAmount = BigDecimal.ZERO;
BigDecimal orderExpressFee = BigDecimal.ZERO;
for (StoreOrderAddDTO.Detail detail : storeOrderAddDTO.getDetailList()) {
StoreProductColorSize spcs = spcsMap.get(detail.getStoreProdColorSizeId());
StoreOrderDetail storeOrderDetail = new StoreOrderDetail();
storeOrderDetailList.add(storeOrderDetail);
storeOrderDetail.setStoreProdColorSizeId(spcs.getId());
storeOrderDetail.setStoreProdId(spcs.getStoreProdId());
storeOrderDetail.setDetailStatus(EOrderStatus.PENDING_PAYMENT.getValue());
storeOrderDetail.setPayStatus(EPayStatus.INIT.getValue());
storeOrderDetail.setExpressStatus(EExpressStatus.INIT.getValue());
StoreOrderDetail orderDetail = new StoreOrderDetail();
orderDetailList.add(orderDetail);
orderDetail.setStoreProdColorSizeId(spcs.getId());
orderDetail.setStoreProdId(spcs.getStoreProdId());
orderDetail.setDetailStatus(EOrderStatus.PENDING_PAYMENT.getValue());
orderDetail.setPayStatus(EPayStatus.INIT.getValue());
orderDetail.setExpressStatus(EExpressStatus.INIT.getValue());
//计算明细费用
BigDecimal goodsPrice = calcPrice(orderUserId, spcs);
Integer goodsQuantity = detail.getGoodsQuantity();
@ -99,13 +98,13 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
expressFee = NumberUtil.mul(expressFeeConfig.getNextItemAmount(), BigDecimal.valueOf(goodsQuantity));
}
BigDecimal totalAmount = NumberUtil.add(goodsAmount, expressFee);
storeOrderDetail.setGoodsPrice(goodsPrice);
storeOrderDetail.setGoodsQuantity(goodsQuantity);
storeOrderDetail.setGoodsAmount(goodsAmount);
storeOrderDetail.setExpressFee(expressFee);
storeOrderDetail.setTotalAmount(totalAmount);
storeOrderDetail.setDelFlag(Constants.UNDELETED);
storeOrderDetail.setVersion(0L);
orderDetail.setGoodsPrice(goodsPrice);
orderDetail.setGoodsQuantity(goodsQuantity);
orderDetail.setGoodsAmount(goodsAmount);
orderDetail.setExpressFee(expressFee);
orderDetail.setTotalAmount(totalAmount);
orderDetail.setDelFlag(Constants.UNDELETED);
orderDetail.setVersion(0L);
//计算订单费用
orderGoodsQuantity = orderGoodsQuantity + goodsQuantity;
orderGoodsAmount = NumberUtil.add(orderGoodsAmount, goodsAmount);
@ -146,18 +145,15 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
//落库
storeOrderMapper.insert(order);
Long orderId = order.getId();
List<Long> orderDetailIdList = new ArrayList<>(storeOrderDetailList.size());
storeOrderDetailList.forEach(storeOrderDetail -> {
List<Long> orderDetailIdList = new ArrayList<>(orderDetailList.size());
orderDetailList.forEach(storeOrderDetail -> {
storeOrderDetail.setStoreOrderId(orderId);
storeOrderDetailMapper.insert(storeOrderDetail);
orderDetailIdList.add(storeOrderDetail.getId());
});
//操作记录
//TODO
//返回
StoreOrderInfoDTO infoDTO = BeanUtil.toBean(order, StoreOrderInfoDTO.class);
infoDTO.setDetailList(BeanUtil.copyToList(storeOrderDetailList, StoreOrderDetailInfoDTO.class));
return infoDTO;
return new StoreOrderAddResultDTO(order, orderDetailList);
}
/**
@ -168,49 +164,22 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
* @return
*/
private BigDecimal calcPrice(Long orderUserId, StoreProductColorSize storeProductColorSize) {
//TODO
return BigDecimal.ONE;
}
/**
*
*
* @param expressId
* @param provinceCode
* @param cityCode
* @param countyCode
* @return
*/
private ExpressFeeConfig getExpressFeeConfig(Long expressId, String provinceCode, String cityCode,
String countyCode) {
Assert.notNull(expressId);
Assert.notEmpty(provinceCode);
Assert.notEmpty(cityCode);
Assert.notEmpty(countyCode);
Map<String, ExpressFeeConfig> map = expressFeeConfigMapper.selectList(Wrappers.lambdaQuery(ExpressFeeConfig.class)
.eq(ExpressFeeConfig::getExpressId, expressId)
.in(ExpressFeeConfig::getRegionCode, Arrays.asList(provinceCode, cityCode, countyCode)))
.stream()
//过滤掉已被删除的配置
.filter(BeanValidators::exists)
.collect(Collectors.toMap(o -> o.getRegionCode(), o -> o, (n, o) -> n));
ExpressFeeConfig expressFeeConfig = null;
if (CollUtil.isNotEmpty(map)) {
if (map.size() == 1) {
expressFeeConfig = CollUtil.getFirst(map.values());
} else {
expressFeeConfig = map.get(countyCode);
//按区市省从小到大去匹配
if (expressFeeConfig == null) {
expressFeeConfig = map.get(cityCode);
if (expressFeeConfig == null) {
expressFeeConfig = map.get(provinceCode);
}
}
}
StoreProductColorPrice productColorPrice = storeProductColorPriceMapper.selectOne(Wrappers
.lambdaQuery(StoreProductColorPrice.class)
.eq(StoreProductColorPrice::getStoreProdId, storeProductColorSize.getStoreProdId())
.eq(StoreProductColorPrice::getStoreColorId, storeProductColorSize.getStoreColorId())
.eq(XktBaseEntity::getDelFlag, Constants.UNDELETED));
Assert.notNull(productColorPrice, "无法获取商品定价");
BigDecimal price = productColorPrice.getPrice();
if ("0".equals(storeProductColorSize.getStandard())) {
//非标准尺码
StoreProduct product = storeProductMapper.selectById(storeProductColorSize.getStoreProdId());
BigDecimal addPrice = BigDecimal.valueOf(NumberUtil.nullToZero(product.getOverPrice()));
price = NumberUtil.add(price, addPrice);
}
Assert.isTrue(BeanValidators.exists(expressFeeConfig), "快递费用配置不存在");
return expressFeeConfig;
//TODO 客户优惠
return price;
}
/**
@ -228,18 +197,6 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
}
}
/**
*
*
* @param expressId
*/
private void checkExpress(Long expressId) {
Assert.notNull(expressId);
Express express = expressMapper.selectById(expressId);
Assert.isTrue(BeanValidators.exists(express), "快递不存在");
Assert.isTrue(express.getSystemDeliverAccess(), "快递不可用");
}
/**
*
*