订单接口的梳理

This commit is contained in:
YunaiV 2023-05-14 17:35:34 +08:00
parent c21e88860f
commit 7fef594390
24 changed files with 344 additions and 291 deletions

View File

@ -49,7 +49,7 @@ public interface ErrorCodeConstants {
ErrorCode COMMENT_ADDITIONAL_EXISTS = new ErrorCode(1008007003, "商品追加评价已存在");
// ========== 商品 收藏 1008008000 ==========
ErrorCode PRODUCT_FAVORITE_EXISTS = new ErrorCode(1008008000, "该商品已经被收藏");
ErrorCode PRODUCT_FAVORITE_NOT_EXISTS = new ErrorCode(1008008001, "商品收藏不存在");
ErrorCode FAVORITE_EXISTS = new ErrorCode(1008008000, "该商品已经被收藏");
ErrorCode FAVORITE_NOT_EXISTS = new ErrorCode(1008008001, "商品收藏不存在");
}

View File

@ -1,14 +1,15 @@
package cn.iocoder.yudao.module.product.dal.dataobject.delivery;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalTime;
// TODO @JasonDeliveryPickUpStoreDO
/**
* 自提门店 DO
*
@ -18,6 +19,7 @@ import java.time.LocalTime;
@KeySequence("pick_up_store_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
public class PickUpStoreDO extends BaseDO {
/**
* 编号自增
*/
@ -40,17 +42,18 @@ public class PickUpStoreDO extends BaseDO {
private String phone;
/**
* 区域id
* 区域 id
*/
private Integer areaId;
// TODO Jason改成 detailAddress主要和 AddressDO 保持一致哈
/**
* 门店详细地址
*/
private String address;
/**
* 门店logo
* 门店 logo
*/
private String logo;
@ -58,7 +61,6 @@ public class PickUpStoreDO extends BaseDO {
* 营业开始时间
*/
private LocalTime openingTime;
/**
* 营业结束时间
*/
@ -68,18 +70,16 @@ public class PickUpStoreDO extends BaseDO {
* 纬度
*/
private String latitude;
/**
* 经度
*/
private String longitude;
/**
* 门店状态0正常 1停用
* 门店状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
}

View File

@ -2,14 +2,18 @@ package cn.iocoder.yudao.module.product.service.spu;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO;
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
@ -180,8 +184,16 @@ public class ProductSpuServiceImpl implements ProductSpuService {
@Override
public PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO) {
//return productSpuMapper.selectPage(pageReqVO); TODO 有差异接口接受参数类型不对
return null;
// 查找时如果查找某个分类编号则包含它的子分类因为顶级分类不包含商品
Set<Long> categoryIds = new HashSet<>();
if (pageReqVO.getCategoryId() != null && pageReqVO.getCategoryId() > 0) {
categoryIds.add(pageReqVO.getCategoryId());
List<ProductCategoryDO> categoryChildren = categoryService.getEnableCategoryList(new ProductCategoryListReqVO()
.setParentId(pageReqVO.getCategoryId()).setStatus(CommonStatusEnum.ENABLE.getStatus()));
categoryIds.addAll(CollectionUtils.convertList(categoryChildren, ProductCategoryDO::getId));
}
// 分页查询
return productSpuMapper.selectPage(pageReqVO, categoryIds);
}
@Override

View File

@ -10,11 +10,6 @@ import java.time.LocalTime;
import java.util.Collection;
import java.util.List;
/**
* 秒杀时段 Mapper
*
* @author halfninety
*/
@Mapper
public interface SeckillTimeMapper extends BaseMapperX<SeckillTimeDO> {

View File

@ -23,8 +23,6 @@ public enum TradeOrderStatusEnum implements IntArrayValuable {
COMPLETED(30, "已完成"),
CANCELED(40, "已取消");
// TODO 芋艿 TAKE("待核验")虚拟订单需要核验商品
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderStatusEnum::getStatus).toArray();
/**

View File

@ -4,7 +4,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Date;
/**
* 交易订单 Base VO提供给添加修改详细的子 VO 使用
@ -118,9 +117,6 @@ public class TradeOrderBaseVO {
@Schema(description = "收件人地区编号", required = true, example = "110000")
private Integer receiverAreaId;
@Schema(description = "收件人邮编", required = true, example = "100000")
private Integer receiverPostCode;
@Schema(description = "收件人详细地址", required = true, example = "中关村大街 1 号")
private String receiverDetailAddress;

View File

@ -1,6 +1,6 @@
### /trade-order/confirm-create-order-info 基于商品,确认创建订单
GET {{appApi}}/trade/order/get-create-info?items[0].skuId=1&items[0].count=1
Authorization: Bearer {{user-access-token}}
### /trade-order/settlement 获得订单结算信息
GET {{appApi}}/trade/order/settlement?cartIds=1
Authorization: Bearer {{appToken}}
tenant-id: {{appTenentId}}
### /trade-order/confirm-create-order-info-from-cart 基于购物车,确认创建订单

View File

@ -2,11 +2,11 @@ package cn.iocoder.yudao.module.trade.controller.app.order;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi;
import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
@ -21,7 +21,11 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@ -40,12 +44,78 @@ public class AppTradeOrderController {
@Resource
private ProductPropertyValueApi productPropertyValueApi;
@GetMapping("/get-create-info")
@Operation(summary = "基于商品,确认创建订单")
@GetMapping("/settlement")
@Operation(summary = "获得订单结算信息")
@PreAuthenticated
public CommonResult<AppTradeOrderGetCreateInfoRespVO> getOrderCreateInfo(AppTradeOrderCreateReqVO createReqVO) {
public CommonResult<AppTradeOrderSettlementRespVO> settlementOrder(
@Valid AppTradeOrderSettlementReqVO settlementReqVO) {
// return success(tradeOrderService.getOrderConfirmCreateInfo(UserSecurityContextHolder.getUserId(), skuId, quantity, couponCardId));
return null;
AppTradeOrderSettlementRespVO settlement = new AppTradeOrderSettlementRespVO();
AppTradeOrderSettlementRespVO.Price price = new AppTradeOrderSettlementRespVO.Price();
price.setOriginalPrice(1000);
price.setDeliveryPrice(200);
price.setCouponPrice(100);
price.setPointPrice(50);
price.setPayPrice(950);
List<AppTradeOrderSettlementRespVO.Item> skus = new ArrayList<>();
AppTradeOrderSettlementRespVO.Item item1 = new AppTradeOrderSettlementRespVO.Item();
item1.setCartId(1L);
item1.setSpuId(2048L);
item1.setSpuName("Apple iPhone 12");
item1.setSkuId(1024);
item1.setPrice(500);
item1.setPicUrl("https://pro.crmeb.net/uploads/attach/2022/10/12/0c56f9abb80d2775fc1e80dbe4f8826a.jpg");
item1.setCount(2);
List<AppProductPropertyValueDetailRespVO> properties1 = new ArrayList<>();
AppProductPropertyValueDetailRespVO property1 = new AppProductPropertyValueDetailRespVO();
property1.setPropertyId(1L);
property1.setPropertyName("尺寸");
property1.setValueId(2L);
property1.setValueName("");
properties1.add(property1);
item1.setProperties(properties1);
AppTradeOrderSettlementRespVO.Item item2 = new AppTradeOrderSettlementRespVO.Item();
item2.setCartId(2L);
item2.setSpuId(3072L);
item2.setSpuName("Samsung Galaxy S21");
item2.setSkuId(2048);
item2.setPrice(800);
item2.setPicUrl("https://pro.crmeb.net/uploads/attach/2022/10/12/0c56f9abb80d2775fc1e80dbe4f8826a.jpg");
item2.setCount(1);
List<AppProductPropertyValueDetailRespVO> properties2 = new ArrayList<>();
AppProductPropertyValueDetailRespVO property2 = new AppProductPropertyValueDetailRespVO();
property2.setPropertyId(10L);
property2.setPropertyName("颜色");
property2.setValueId(20L);
property2.setValueName("白色");
properties2.add(property2);
item2.setProperties(properties2);
skus.add(item1);
skus.add(item2);
settlement.setItems(skus);
settlement.setPrice(price);
AppTradeOrderSettlementRespVO.Address address = new AppTradeOrderSettlementRespVO.Address();
address.setId(1L);
address.setName("John");
address.setMobile("18888888888");
address.setProvinceId(1L);
address.setProvinceName("Beijing");
address.setCityId(1L);
address.setCityName("Beijing");
address.setDistrictId(1L);
address.setDistrictName("Chaoyang Distripct");
address.setDetailAddress("No. 10, Xinzhong Street, Chaoyang District");
address.setDefaulted(true);
settlement.setAddress(address);
return success(settlement);
}
@PostMapping("/create")
@ -53,12 +123,13 @@ public class AppTradeOrderController {
@PreAuthenticated
public CommonResult<Long> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO,
HttpServletRequest servletRequest) {
// 获取登录用户用户 IP 地址
Long loginUserId = getLoginUserId();
String clientIp = ServletUtils.getClientIP(servletRequest);
// 创建交易订单预支付记录
Long orderId = tradeOrderService.createOrder(loginUserId, clientIp, createReqVO);
return success(orderId);
return success(1L);
// // 获取登录用户用户 IP 地址
// Long loginUserId = getLoginUserId();
// String clientIp = ServletUtils.getClientIP(servletRequest);
// // 创建交易订单预支付记录
// Long orderId = tradeOrderService.createOrder(loginUserId, clientIp, createReqVO);
// return success(orderId);
}
@PostMapping("/update-paid")
@ -85,7 +156,7 @@ public class AppTradeOrderController {
}
@GetMapping("/page")
@Operation(summary = "获得订单交易分页")
@Operation(summary = "获得交易订单分页")
public CommonResult<PageResult<AppTradeOrderPageItemRespVO>> getOrderPage(AppTradeOrderPageReqVO reqVO) {
// 查询订单
PageResult<TradeOrderDO> pageResult = tradeOrderService.getOrderPage(getLoginUserId(), reqVO);
@ -99,4 +170,18 @@ public class AppTradeOrderController {
return success(TradeOrderConvert.INSTANCE.convertPage02(pageResult, orderItems, propertyValueDetails));
}
// TODO 芋艿后续实现
@GetMapping("/get-count")
@Operation(summary = "获得交易订单数量")
public CommonResult<Map<String, Integer>> getOrderCount() {
Map<String, Integer> orderCount = new HashMap<>();
orderCount.put("allCount", 10);
orderCount.put("unpaidCount", 5);
orderCount.put("undeliveredCount", 2);
orderCount.put("deliveredCount", 1);
orderCount.put("uncommentedCount", 3);
orderCount.put("allPrice", 300);
return success(orderCount);
}
}

View File

@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.trade.controller.app.order.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@ -20,33 +18,13 @@ public class AppTradeOrderCreateReqVO {
@Schema(description = "优惠劵编号", example = "1024")
private Long couponId;
@Schema(description = "购物车项的编号数组", required = true, example = "true")
@NotEmpty(message = "购物车项不能为空")
private List<Long> cartIds;
// ========== AppTradeOrderSettlementReqVO 字段 ==========
@Schema(description = "备注", example = "这个是我的订单哟")
private String remark;
@Schema(description = "是否来自购物车", required = true, example = "true") // true - 来自购物车false - 立即购买
@NotNull(message = "是否来自购物车不能为空")
private Boolean fromCart;
/**
* 订单商品项列表
*/
@NotEmpty(message = "必须选择购买的商品")
@Valid
private List<Item> items;
@Schema(description = "订单商品项")
@Data
public static class Item {
@Schema(description = "商品 SKU 编号", required = true, example = "111")
@NotNull(message = "商品 SKU 编号不能为空")
private Long skuId;
@Schema(description = "商品 SKU 购买数量", required = true, example = "1024")
@NotNull(message = "商品 SKU 购买数量不能为空")
@Min(value = 1, message = "商品 SKU 购买数量必须大于 0")
private Integer count;
}
}

View File

@ -40,12 +40,18 @@ public class AppTradeOrderDetailRespVO {
// ========== 价格 + 支付基本信息 ==========
@Schema(description = "是否已支付", required = true, example = "true")
private Boolean payed;
@Schema(description = "支付订单编号", required = true, example = "1024")
private Long payOrderId;
@Schema(description = "付款时间")
private LocalDateTime payTime;
@Schema(description = "支付渠道", required = true, example = "wx_lite_pay")
private String payChannelCode;
@Schema(description = "商品原价(总)", required = true, example = "1000")
private Integer originalPrice;
@ -87,9 +93,6 @@ public class AppTradeOrderDetailRespVO {
@Schema(description = "收件人地区名字", required = true, example = "上海 上海市 普陀区")
private String receiverAreaName;
@Schema(description = "收件人邮编", required = true, example = "100000")
private Integer receiverPostCode;
@Schema(description = "收件人详细地址", required = true, example = "中关村大街 1 号")
private String receiverDetailAddress;

View File

@ -1,168 +0,0 @@
package cn.iocoder.yudao.module.trade.controller.app.order.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
@Schema(description = "用户 App - 订单获得创建信息 Response VO")
@Data
public class AppTradeOrderGetCreateInfoRespVO {
/**
* 商品分组数组
*/
private List<ItemGroup> itemGroups;
/**
* 费用
*/
private Fee fee;
// /**
// * 优惠劵列表 TODO 芋艿后续改改
// */
// private List<CouponCardAvailableRespDTO> coupons;
@Schema(description = "商品分组") // 多个商品参加同一个活动从而形成分组
@Data
public static class ItemGroup {
// /**
// * 优惠活动
// */
// private PromotionActivityRespDTO activity; // TODO 芋艿偷懒
/**
* 商品 SKU 数组
*/
private List<Sku> items;
}
@Schema(description = "商品 SKU")
@Data
public static class Sku {
// SKU 自带信息
@Schema(description = "SKU 编号", required = true, example = "1024")
private Integer id;
/**
* SPU 信息
*/
private Spu spu;
/**
* 图片地址
*/
private String picURL;
// /**
// * 属性数组
// */
// private List<ProductAttrKeyValueRespVO> attrs; // TODO 后面改下
/**
* 价格单位
*/
private Integer price;
/**
* 库存数量
*/
private Integer stock;
// SKU 自带信息
/**
* 购买数量
*/
private Integer buyQuantity;
// /**
// * 优惠活动
// */
// private PromotionActivityRespDTO activity; // TODO 芋艿偷懒
/**
* 原始单价单位
*/
private Integer originPrice;
/**
* 购买单价单位
*/
private Integer buyPrice;
/**
* 最终价格单位
*/
private Integer presentPrice;
/**
* 购买总金额单位
*
* 用途类似 {@link #presentTotal}
*/
private Integer buyTotal;
/**
* 优惠总金额单位
*/
private Integer discountTotal;
/**
* 最终总金额单位
*
* 注意presentPrice * quantity 不一定等于 presentTotal
* 因为存在无法整除的情况
* 举个例子presentPrice = 8.33 quantity = 3 的情况presentTotal 有可能是 24.99 也可能是 25
* 所以需要存储一个该字段
*/
private Integer presentTotal;
}
@Data
public static class Spu {
/**
* SPU 编号
*/
private Integer id;
// ========== 基本信息 =========
/**
* SPU 名字
*/
private String name;
/**
* 分类编号
*/
private Integer cid;
/**
* 商品主图地址
*
* 数组以逗号分隔
*
* 建议尺寸800*800像素你可以拖拽图片调整顺序最多上传15张
*/
private List<String> picUrls;
}
@Schema(description = "费用(合计)")
@Data
@AllArgsConstructor
public static class Fee {
@Schema(description = "购买总价", required = true, example = "1024")
private Integer buyPrice;
/**
* 优惠总价
*
* 注意满多少元包邮不算在优惠中
*/
private Integer discountTotal;
/**
* 邮费
*/
private Integer postageTotal;
/**
* 最终价格
*
* 计算公式 = 总价 - 优惠总价 + 邮费
*/
private Integer presentTotal;
}
}

View File

@ -22,6 +22,11 @@ public class AppTradeOrderPageItemRespVO {
@Schema(description = "购买的商品数量", required = true, example = "10")
private Integer productCount;
// ========== 价格 + 支付基本信息 ==========
@Schema(description = "应付金额,单位:分", required = true, example = "1000")
private Integer payPrice;
/**
* 订单项数组
*/

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.trade.controller.app.order.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.List;
@Schema(description = "用户 App - 交易订单结算 Request VO")
@Data
public class AppTradeOrderSettlementReqVO {
@Schema(description = "收件地址编号", example = "1")
private Long addressId;
@Schema(description = "优惠劵编号", example = "1024")
private Long couponId;
@Schema(description = "购物车项的编号数组", required = true, example = "true")
@NotEmpty(message = "购物车项不能为空")
private List<Long> cartIds;
}

View File

@ -0,0 +1,116 @@
package cn.iocoder.yudao.module.trade.controller.app.order.vo;
import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Schema(description = "用户 App - 交易订单结算信息 Response VO")
@Data
public class AppTradeOrderSettlementRespVO {
@Schema(description = "购物项数组", required = true)
private List<Item> items;
@Schema(description = "费用", required = true)
private Price price;
@Schema(description = "收件地址", required = true)
private Address address;
@Schema(description = "购物项")
@Data
public static class Item {
// ========== SPU 信息 ==========
@Schema(description = "SPU 编号", required = true, example = "2048")
private Long spuId;
@Schema(description = "SPU 名字", required = true, example = "Apple iPhone 12")
private String spuName;
// ========== SKU 信息 ==========
@Schema(description = "SKU 编号", required = true, example = "1024")
private Integer skuId;
@Schema(description = "价格,单位:分", required = true, example = "100")
private Integer price;
@Schema(description = "图片地址", required = true, example = "https://www.iocoder.cn/1.png")
private String picUrl;
@Schema(description = "属性数组", required = true, example = "100")
private List<AppProductPropertyValueDetailRespVO> properties;
// ========== 购物车信息 ==========
@Schema(description = "购物车编号", required = true, example = "100")
private Long cartId;
@Schema(description = "购买数量", required = true, example = "1")
private Integer count;
}
@Schema(description = "费用(合计)")
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Price {
@Schema(description = "商品原价(总),单位:分", required = true, example = "500")
private Integer originalPrice;
@Schema(description = "运费金额,单位:分", required = true, example = "50")
private Integer deliveryPrice;
@Schema(description = "优惠劵减免金额,单位:分", required = true, example = "100")
private Integer couponPrice;
@Schema(description = "积分抵扣的金额,单位:分", required = true, example = "50")
private Integer pointPrice;
@Schema(description = "实际支付金额(总),单位:分", required = true, example = "450")
private Integer payPrice;
}
@Schema(description = "费用(合计)")
@Data
public static class Address {
@Schema(description = "编号", required = true, example = "1")
private Long id;
@Schema(description = "收件人名称", required = true, example = "小王")
private String name;
@Schema(description = "手机号", required = true, example = "15601691300")
private String mobile;
@Schema(description = "省份编号", required = true, example = "1")
private Long provinceId;
@Schema(description = "省份名字", required = true, example = "北京")
private String provinceName;
@Schema(description = "城市编号", required = true, example = "1")
private Long cityId;
@Schema(description = "城市名字", required = true, example = "北京")
private String cityName;
@Schema(description = "地区编号", required = true, example = "1")
private Long districtId;
@Schema(description = "地区名字", required = true, example = "朝阳区")
private String districtName;
@Schema(description = "详细地址", required = true, example = "望京悠乐汇 A 座")
private String detailAddress;
@Schema(description = "是否默认收件地址", required = true, example = "true")
private Boolean defaulted;
}
}

View File

@ -50,7 +50,6 @@ public interface TradeOrderConvert {
@Mapping(source = "address.name", target = "receiverName"),
@Mapping(source = "address.mobile", target = "receiverMobile"),
@Mapping(source = "address.areaId", target = "receiverAreaId"),
@Mapping(source = "address.postCode", target = "receiverPostCode"),
@Mapping(source = "address.detailAddress", target = "receiverDetailAddress"),
})
TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO,

View File

@ -212,10 +212,6 @@ public class TradeOrderDO extends BaseDO {
* 收件人地区编号
*/
private Integer receiverAreaId;
/**
* 收件人邮编
*/
private Integer receiverPostCode;
/**
* 收件人详细地址
*/

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.order;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
@ -42,6 +43,12 @@ public class TradeOrderItemDO extends BaseDO {
* 关联 {@link TradeOrderDO#getId()}
*/
private Long orderId;
/**
* 购物车项编号
*
* 关联 {@link TradeCartDO#getId()}
*/
private Long cartId;
// ========== 商品基本信息; 冗余较多字段减少关联查询 ==========
/**

View File

@ -30,7 +30,6 @@ import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO.Item;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO;
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
@ -49,7 +48,8 @@ import java.time.LocalDateTime;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
@ -92,7 +92,8 @@ public class TradeOrderServiceImpl implements TradeOrderService {
@Transactional(rollbackFor = Exception.class)
public Long createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
// 商品 SKU 检查可售状态库存
List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems());
// List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems()); // TODO 芋艿临时关闭
List<ProductSkuRespDTO> skus = null;
// 商品 SPU 检查可售状态
List<ProductSpuRespDTO> spus = validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId));
// 用户收件地址的校验
@ -112,28 +113,28 @@ public class TradeOrderServiceImpl implements TradeOrderService {
return tradeOrderDO.getId();
}
/**
* 校验商品 SKU 是否可出售
*
* @param items 商品 SKU
* @return 商品 SKU 数组
*/
private List<ProductSkuRespDTO> validateSkuSaleable(List<Item> items) {
List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(convertSet(items, Item::getSkuId));
// SKU 不存在
if (items.size() != skus.size()) {
throw exception(ORDER_CREATE_SKU_NOT_FOUND);
}
// 校验库存不足
Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
items.forEach(item -> {
ProductSkuRespDTO sku = skuMap.get(item.getSkuId());
if (item.getCount() > sku.getStock()) {
throw exception(ErrorCodeConstants.ORDER_CREATE_SKU_STOCK_NOT_ENOUGH);
}
});
return skus;
}
// /**
// * 校验商品 SKU 是否可出售
// *
// * @param items 商品 SKU
// * @return 商品 SKU 数组
// */
// private List<ProductSkuRespDTO> validateSkuSaleable(List<Item> items) {
// List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(convertSet(items, Item::getSkuId));
// // SKU 不存在
// if (items.size() != skus.size()) {
// throw exception(ORDER_CREATE_SKU_NOT_FOUND);
// }
// // 校验库存不足
// Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
// items.forEach(item -> {
// ProductSkuRespDTO sku = skuMap.get(item.getSkuId());
// if (item.getCount() > sku.getStock()) {
// throw exception(ErrorCodeConstants.ORDER_CREATE_SKU_STOCK_NOT_ENOUGH);
// }
// });
// return skus;
// }
/**
* 校验商品 SPU 是否可出售
@ -506,6 +507,9 @@ public class TradeOrderServiceImpl implements TradeOrderService {
@Override
public List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds) {
if (CollUtil.isEmpty(orderIds)) {
return Collections.emptyList();
}
return tradeOrderItemMapper.selectListByOrderId(orderIds);
}

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.trade.service.order;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.member.api.address.AddressApi;
@ -93,10 +92,12 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
// 准备参数
Long userId = 100L;
String userIp = "127.0.0.1";
AppTradeOrderCreateReqVO reqVO = new AppTradeOrderCreateReqVO()
.setAddressId(10L).setCouponId(101L).setRemark("我是备注").setFromCart(true)
.setItems(Arrays.asList(new AppTradeOrderCreateReqVO.Item().setSkuId(1L).setCount(3),
new AppTradeOrderCreateReqVO.Item().setSkuId(2L).setCount(4)));
// AppTradeOrderCreateReqVO reqVO = new AppTradeOrderCreateReqVO()
// .setAddressId(10L).setCouponId(101L).setRemark("我是备注").setFromCart(true)
// .setItems(Arrays.asList(new AppTradeOrderCreateReqVO.Item().setSkuId(1L).setCount(3),
// new AppTradeOrderCreateReqVO.Item().setSkuId(2L).setCount(4)));
AppTradeOrderCreateReqVO reqVO = null;
// TODO 芋艿重新高下
// mock 方法商品 SKU 检查
ProductSkuRespDTO sku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(1L).setSpuId(11L)
.setPrice(50).setStock(100)
@ -183,7 +184,6 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
assertEquals(tradeOrderDO.getReceiverName(), "芋艿");
assertEquals(tradeOrderDO.getReceiverMobile(), "15601691300");
assertEquals(tradeOrderDO.getReceiverAreaId(), 3306);
assertEquals(tradeOrderDO.getReceiverPostCode(), 85757);
assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村");
assertEquals(tradeOrderDO.getAfterSaleStatus(), TradeOrderAfterSaleStatusEnum.NONE.getStatus());
assertEquals(tradeOrderDO.getRefundPrice(), 0);

View File

@ -1,10 +1,11 @@
package cn.iocoder.yudao.module.member.controller.app.address.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
// TODO 芋艿example 缺失
/**
* 用户收件地址 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
@ -24,10 +25,6 @@ public class AppAddressBaseVO {
@NotNull(message = "地区编号不能为空")
private Long areaId;
@Schema(description = "邮编", required = true)
@NotEmpty(message = "邮编不能为空")
private String postCode;
@Schema(description = "收件详细地址", required = true)
@NotNull(message = "收件详细地址不能为空")
private String detailAddress;

View File

@ -40,10 +40,6 @@ public class AddressDO extends BaseDO {
* 地区编号
*/
private Long areaId;
/**
* 邮编
*/
private String postCode;
/**
* 收件详细地址
*/

View File

@ -55,6 +55,10 @@ public class PayOrderBaseVO {
@NotNull(message = "支付金额,单位:分不能为空")
private Long amount;
@Schema(description = "支付金额,单位:分", required = true)
@NotNull(message = "支付金额,单位:分不能为空")
private Long price;
@Schema(description = "渠道手续费,单位:百分比")
private Double channelFeeRate;

View File

@ -1,19 +1,18 @@
package cn.iocoder.yudao.module.pay.controller.app.order;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderRespVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO;
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
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 org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@ -28,12 +27,20 @@ import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getCli
public class AppPayOrderController {
@Resource
private PayOrderService orderService;
private PayOrderService payOrderService;
// TODO 芋艿临时 demo技术打样
@GetMapping("/get")
@Operation(summary = "获得支付订单")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
public CommonResult<PayOrderRespVO> getOrder(@RequestParam("id") Long id) {
return success(PayOrderConvert.INSTANCE.convert(payOrderService.getOrder(id)));
}
@PostMapping("/submit")
@Operation(summary = "提交支付订单")
public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody AppPayOrderSubmitReqVO reqVO) {
PayOrderSubmitRespVO respVO = orderService.submitPayOrder(reqVO, getClientIP());
PayOrderSubmitRespVO respVO = payOrderService.submitPayOrder(reqVO, getClientIP());
return success(PayOrderConvert.INSTANCE.convert3(respVO));
}

View File

@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespD
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO;
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
@ -28,6 +27,7 @@ public interface PayOrderConvert {
PayOrderConvert INSTANCE = Mappers.getMapper(PayOrderConvert.class);
@Mapping(source = "amount", target = "price")
PayOrderRespVO convert(PayOrderDO bean);
PayOrderRespDTO convert2(PayOrderDO order);