mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-27 01:32:03 +08:00
Merge remote-tracking branch 'origin/feature/mall_product' into brokerate
This commit is contained in:
commit
73e4976ae4
@ -4,18 +4,18 @@
|
|||||||
DROP TABLE IF EXISTS `pay_wallet`;
|
DROP TABLE IF EXISTS `pay_wallet`;
|
||||||
CREATE TABLE `pay_wallet`
|
CREATE TABLE `pay_wallet`
|
||||||
(
|
(
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
|
||||||
`user_id` bigint NOT NULL COMMENT '用户编号',
|
`user_id` bigint NOT NULL COMMENT '用户编号',
|
||||||
`user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型',
|
`user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型',
|
||||||
`balance` int NOT NULL DEFAULT 0 COMMENT '余额,单位分',
|
`balance` int NOT NULL DEFAULT 0 COMMENT '余额,单位分',
|
||||||
`total_expense` int NOT NULL DEFAULT 0 COMMENT '累计支出,单位分',
|
`total_expense` int NOT NULL DEFAULT 0 COMMENT '累计支出,单位分',
|
||||||
`total_recharge` int NOT NULL DEFAULT 0 COMMENT '累计充值,单位分',
|
`total_recharge` int NOT NULL DEFAULT 0 COMMENT '累计充值,单位分',
|
||||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
PRIMARY KEY (`id`) USING BTREE
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
) ENGINE=InnoDB COMMENT='会员钱包表';
|
) ENGINE=InnoDB COMMENT='会员钱包表';
|
||||||
|
|
||||||
@ -41,3 +41,33 @@ CREATE TABLE `pay_wallet_transaction`
|
|||||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
PRIMARY KEY (`id`) USING BTREE
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
) ENGINE=InnoDB COMMENT='会员钱包流水表';
|
) ENGINE=InnoDB COMMENT='会员钱包流水表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 会员钱包充值
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `pay_wallet_recharge`;
|
||||||
|
CREATE TABLE `pay_wallet_recharge`
|
||||||
|
(
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
|
||||||
|
`wallet_id` bigint NOT NULL COMMENT '会员钱包 id',
|
||||||
|
`price` int NOT NULL COMMENT '用户实际到账余额,例如充 100 送 20,则该值是 120',
|
||||||
|
`pay_price` int NOT NULL COMMENT '实际支付金额',
|
||||||
|
`wallet_bonus` int NOT NULL COMMENT '钱包赠送金额',
|
||||||
|
`pay_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否已支付:[0:未支付 1:已经支付过]',
|
||||||
|
`pay_order_id` bigint NULL COMMENT '支付订单编号',
|
||||||
|
`pay_channel_code` varchar(16) NULL COMMENT '支付成功的支付渠道',
|
||||||
|
`pay_time` datetime NULL COMMENT '订单支付时间',
|
||||||
|
`pay_refund_id` bigint NULL COMMENT '支付退款单编号',
|
||||||
|
`refund_price` int NOT NULL DEFAULT 0 COMMENT '退款金额,包含赠送金额',
|
||||||
|
`refund_pay_price` int NOT NULL DEFAULT 0 COMMENT '退款支付金额',
|
||||||
|
`refund_wallet_bonus` int NOT NULL DEFAULT 0 COMMENT '退款钱包赠送金额',
|
||||||
|
`refund_time` datetime NULL COMMENT '退款时间',
|
||||||
|
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE=InnoDB COMMENT='会员钱包充值';
|
||||||
|
|
||||||
|
@ -59,15 +59,14 @@ public class ProductSkuRespDTO {
|
|||||||
* 商品体积,单位:m^3 平米
|
* 商品体积,单位:m^3 平米
|
||||||
*/
|
*/
|
||||||
private Double volume;
|
private Double volume;
|
||||||
|
// TODO @puhui999:firstBrokeragePrice ;尴尬,我当时打错了;secondBrokeragePrice
|
||||||
// TODO @puhui:这 2 字段,需要改下;firstBrokerageRecord、secondBrokerageRecord;和分佣保持一致;
|
|
||||||
/**
|
/**
|
||||||
* 一级分销的佣金,单位:分
|
* 一级分销的佣金,单位:分
|
||||||
*/
|
*/
|
||||||
private Integer subCommissionFirstPrice;
|
private Integer firstBrokerageRecord;
|
||||||
/**
|
/**
|
||||||
* 二级分销的佣金,单位:分
|
* 二级分销的佣金,单位:分
|
||||||
*/
|
*/
|
||||||
private Integer subCommissionSecondPrice;
|
private Integer secondBrokerageRecord;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -51,10 +51,10 @@ public class ProductSkuBaseVO {
|
|||||||
private Double volume;
|
private Double volume;
|
||||||
|
|
||||||
@Schema(description = "一级分销的佣金,单位:分", example = "199")
|
@Schema(description = "一级分销的佣金,单位:分", example = "199")
|
||||||
private Integer subCommissionFirstPrice;
|
private Integer firstBrokerageRecord;
|
||||||
|
|
||||||
@Schema(description = "二级分销的佣金,单位:分", example = "19")
|
@Schema(description = "二级分销的佣金,单位:分", example = "19")
|
||||||
private Integer subCommissionSecondPrice;
|
private Integer secondBrokerageRecord;
|
||||||
|
|
||||||
@Schema(description = "属性数组")
|
@Schema(description = "属性数组")
|
||||||
private List<Property> properties;
|
private List<Property> properties;
|
||||||
|
@ -81,11 +81,11 @@ public class ProductSkuDO extends BaseDO {
|
|||||||
/**
|
/**
|
||||||
* 一级分销的佣金,单位:分
|
* 一级分销的佣金,单位:分
|
||||||
*/
|
*/
|
||||||
private Integer subCommissionFirstPrice;
|
private Integer firstBrokerageRecord;
|
||||||
/**
|
/**
|
||||||
* 二级分销的佣金,单位:分
|
* 二级分销的佣金,单位:分
|
||||||
*/
|
*/
|
||||||
private Integer subCommissionSecondPrice;
|
private Integer secondBrokerageRecord;
|
||||||
|
|
||||||
// ========== 营销相关字段 =========
|
// ========== 营销相关字段 =========
|
||||||
|
|
||||||
|
@ -92,8 +92,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
|||||||
o.setMarketPrice(generaInt());
|
o.setMarketPrice(generaInt());
|
||||||
o.setStock(generaInt());
|
o.setStock(generaInt());
|
||||||
o.setWarnStock(10);
|
o.setWarnStock(10);
|
||||||
o.setSubCommissionFirstPrice(generaInt());
|
o.setFirstBrokerageRecord(generaInt());
|
||||||
o.setSubCommissionSecondPrice(generaInt());
|
o.setSecondBrokerageRecord(generaInt());
|
||||||
// 限制分数为两位数
|
// 限制分数为两位数
|
||||||
o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
||||||
o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
||||||
@ -143,8 +143,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
|||||||
o.setMarketPrice(generaInt());
|
o.setMarketPrice(generaInt());
|
||||||
o.setStock(generaInt());
|
o.setStock(generaInt());
|
||||||
o.setWarnStock(10);
|
o.setWarnStock(10);
|
||||||
o.setSubCommissionFirstPrice(generaInt());
|
o.setFirstBrokerageRecord(generaInt());
|
||||||
o.setSubCommissionSecondPrice(generaInt());
|
o.setSecondBrokerageRecord(generaInt());
|
||||||
// 限制分数为两位数
|
// 限制分数为两位数
|
||||||
o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
||||||
o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
|
||||||
|
@ -10,9 +10,9 @@ public interface BargainActivityApi {
|
|||||||
/**
|
/**
|
||||||
* 更新砍价活动库存
|
* 更新砍价活动库存
|
||||||
*
|
*
|
||||||
* @param activityId 砍价活动编号
|
* @param id 砍价活动编号
|
||||||
* @param count 购买数量
|
* @param count 购买数量
|
||||||
*/
|
*/
|
||||||
void updateBargainActivityStock(Long activityId, Integer count);
|
void updateBargainActivityStock(Long id, Integer count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package cn.iocoder.yudao.module.promotion.api.combination;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
|
||||||
|
|
||||||
|
// TODO @puhui999:是不是改成 CombinationActivityApi
|
||||||
|
/**
|
||||||
|
* 拼团活动 Api 接口
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
public interface CombinationApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新活动库存
|
||||||
|
*
|
||||||
|
* @param reqDTO 请求
|
||||||
|
*/
|
||||||
|
// TODO @puhui999:应该是更新哇?还是校验哈;
|
||||||
|
void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package cn.iocoder.yudao.module.promotion.api.combination.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拼团活动更新活动库存 Request DTO
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CombinationActivityUpdateStockReqDTO {
|
||||||
|
|
||||||
|
// TODO @puhui999:是不是一个 activityId、count、skuId 参数就完事啦。
|
||||||
|
|
||||||
|
@NotNull(message = "活动编号不能为空")
|
||||||
|
private Long activityId;
|
||||||
|
|
||||||
|
@NotNull(message = "购买数量不能为空")
|
||||||
|
private Integer count;
|
||||||
|
|
||||||
|
@NotNull(message = "活动商品不能为空")
|
||||||
|
private Item item;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Valid
|
||||||
|
public static class Item {
|
||||||
|
|
||||||
|
@NotNull(message = "SPU 编号不能为空")
|
||||||
|
private Long spuId;
|
||||||
|
|
||||||
|
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||||
|
private Long skuId;
|
||||||
|
|
||||||
|
@NotNull(message = "购买数量不能为空")
|
||||||
|
private Integer count;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.api.combination.dto;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
// TODO @芋艿:这块要在看看
|
// TODO @芋艿:这块要在看看
|
||||||
@ -14,65 +13,27 @@ import javax.validation.constraints.NotNull;
|
|||||||
@Data
|
@Data
|
||||||
public class CombinationRecordCreateReqDTO {
|
public class CombinationRecordCreateReqDTO {
|
||||||
|
|
||||||
/**
|
// TODO @puhui999:注释还是要的哈
|
||||||
* 拼团活动编号
|
|
||||||
*/
|
|
||||||
@NotNull(message = "拼团活动编号不能为空")
|
@NotNull(message = "拼团活动编号不能为空")
|
||||||
private Long activityId;
|
private Long activityId;
|
||||||
/**
|
|
||||||
* spu 编号
|
|
||||||
*/
|
|
||||||
@NotNull(message = "spu 编号不能为空")
|
@NotNull(message = "spu 编号不能为空")
|
||||||
private Long spuId;
|
private Long spuId;
|
||||||
/**
|
|
||||||
* sku 编号
|
|
||||||
*/
|
|
||||||
@NotNull(message = "sku 编号不能为空")
|
@NotNull(message = "sku 编号不能为空")
|
||||||
private Long skuId;
|
private Long skuId;
|
||||||
/**
|
|
||||||
* 用户编号
|
|
||||||
*/
|
|
||||||
@NotNull(message = "用户编号不能为空")
|
|
||||||
private Long userId;
|
|
||||||
/**
|
|
||||||
* 订单编号
|
|
||||||
*/
|
|
||||||
@NotNull(message = "订单编号不能为空")
|
@NotNull(message = "订单编号不能为空")
|
||||||
private Long orderId;
|
private Long orderId;
|
||||||
/**
|
|
||||||
* 团长编号
|
@NotNull(message = "用户编号不能为空")
|
||||||
*/
|
private Long userId;
|
||||||
|
|
||||||
@NotNull(message = "团长编号不能为空")
|
@NotNull(message = "团长编号不能为空")
|
||||||
private Long headId;
|
private Long headId;
|
||||||
/**
|
|
||||||
* 商品名字
|
|
||||||
*/
|
|
||||||
@NotEmpty(message = "商品名字不能为空")
|
|
||||||
private String spuName;
|
|
||||||
/**
|
|
||||||
* 商品图片
|
|
||||||
*/
|
|
||||||
@NotEmpty(message = "商品图片不能为空")
|
|
||||||
private String picUrl;
|
|
||||||
/**
|
|
||||||
* 拼团商品单价
|
|
||||||
*/
|
|
||||||
@NotNull(message = "拼团商品单价不能为空")
|
@NotNull(message = "拼团商品单价不能为空")
|
||||||
private Integer combinationPrice;
|
private Integer combinationPrice;
|
||||||
/**
|
|
||||||
* 用户昵称
|
|
||||||
*/
|
|
||||||
@NotEmpty(message = "用户昵称不能为空")
|
|
||||||
private String nickname;
|
|
||||||
/**
|
|
||||||
* 用户头像
|
|
||||||
*/
|
|
||||||
@NotEmpty(message = "用户头像不能为空")
|
|
||||||
private String avatar;
|
|
||||||
/**
|
|
||||||
* 开团状态:正在开团 拼团成功 拼团失败
|
|
||||||
*/
|
|
||||||
@NotNull(message = "开团状态不能为空")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ package cn.iocoder.yudao.module.promotion.api.seckill.dto;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新秒杀库存 request DTO
|
* 更新秒杀库存 request DTO
|
||||||
@ -12,37 +13,28 @@ import java.util.List;
|
|||||||
@Data
|
@Data
|
||||||
public class SeckillActivityUpdateStockReqDTO {
|
public class SeckillActivityUpdateStockReqDTO {
|
||||||
|
|
||||||
// TODO @puhui999:参数校验
|
// TODO @puhui999:可以不用 dto,直接 activityId、skuId、count 即可
|
||||||
|
|
||||||
// TODO @puhui999:秒杀的话,一次只能购买一种商品哈;不能多个哈;
|
@NotNull(message = "活动编号不能为空")
|
||||||
|
|
||||||
/**
|
|
||||||
* 活动编号
|
|
||||||
*/
|
|
||||||
private Long activityId;
|
private Long activityId;
|
||||||
/**
|
|
||||||
* 总购买数量
|
@NotNull(message = "购买数量不能为空")
|
||||||
*/
|
|
||||||
private Integer count;
|
private Integer count;
|
||||||
/**
|
|
||||||
* 活动商品
|
@NotNull(message = "活动商品不能为空")
|
||||||
*/
|
private Item item;
|
||||||
private List<Item> items;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@Valid
|
||||||
public static class Item {
|
public static class Item {
|
||||||
|
|
||||||
/**
|
@NotNull(message = "SPU 编号不能为空")
|
||||||
* SPU 编号
|
|
||||||
*/
|
|
||||||
private Long spuId;
|
private Long spuId;
|
||||||
/**
|
|
||||||
* SKU 编号
|
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||||
*/
|
|
||||||
private Long skuId;
|
private Long skuId;
|
||||||
/**
|
|
||||||
* 购买数量
|
@NotNull(message = "购买数量不能为空")
|
||||||
*/
|
|
||||||
private Integer count;
|
private Integer count;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
|
ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
|
||||||
ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
|
ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
|
||||||
ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
|
ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
|
||||||
ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "更新秒杀活动库存失败,原因秒杀库存不足");
|
ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足");
|
||||||
|
|
||||||
// ========== 秒杀时段 1013009000 ==========
|
// ========== 秒杀时段 1013009000 ==========
|
||||||
ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
|
ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
|
||||||
@ -65,24 +65,26 @@ public interface ErrorCodeConstants {
|
|||||||
// ========== 拼团活动 1013010000 ==========
|
// ========== 拼团活动 1013010000 ==========
|
||||||
ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
|
ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
|
||||||
ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010001, "存在商品参加了其它拼团活动");
|
ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010001, "存在商品参加了其它拼团活动");
|
||||||
ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
|
ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
|
||||||
ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除");
|
ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除");
|
||||||
ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013010004, "拼团不存在");
|
ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010004, "拼团失败,原因:拼团活动已关闭");
|
||||||
|
|
||||||
// ========== 拼团记录 1013011000 ==========
|
// ========== 拼团记录 1013011000 ==========
|
||||||
ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011000, "拼团失败,已参与过该拼团");
|
ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013011000, "拼团不存在");
|
||||||
ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011001, "拼团失败,父拼团不存在");
|
ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011001, "拼团失败,已参与过该拼团");
|
||||||
ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011002, "拼团失败,拼团人数已满");
|
ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011002, "拼团失败,父拼团不存在");
|
||||||
ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011003, "拼团失败,已参与其它拼团");
|
ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011003, "拼团失败,拼团人数已满");
|
||||||
ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011004, "拼团失败,活动已经结束");
|
ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011004, "拼团失败,已参与其它拼团");
|
||||||
ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011005, "拼团失败,单次限购超出");
|
ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011005, "拼团失败,活动已经结束");
|
||||||
ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,单次限购超出");
|
ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,原因:单次限购超出");
|
||||||
|
ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011007, "拼团失败,原因:超出总购买次数");
|
||||||
|
|
||||||
// ========== 砍价活动 1013012000 ==========
|
// ========== 砍价活动 1013012000 ==========
|
||||||
ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在");
|
ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在");
|
||||||
ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013012001, "存在商品参加了其它砍价活动");
|
ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013012001, "存在商品参加了其它砍价活动");
|
||||||
ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013012002, "砍价活动已关闭不能修改");
|
ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013012002, "砍价活动已关闭不能修改");
|
||||||
ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013012003, "砍价活动未关闭或未结束,不能删除");
|
ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013012003, "砍价活动未关闭或未结束,不能删除");
|
||||||
|
ErrorCode BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013012004, "砍价失败,原因:该砍价活动库存不足");
|
||||||
|
|
||||||
// ========== 砍价记录 1013013000 ==========
|
// ========== 砍价记录 1013013000 ==========
|
||||||
ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1013013000, "砍价记录不存在");
|
ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1013013000, "砍价记录不存在");
|
||||||
|
@ -29,6 +29,11 @@
|
|||||||
<artifactId>yudao-module-product-api</artifactId>
|
<artifactId>yudao-module-product-api</artifactId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-module-trade-api</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.boot</groupId>
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<artifactId>yudao-module-member-api</artifactId>
|
<artifactId>yudao-module-member-api</artifactId>
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
package cn.iocoder.yudao.module.promotion.api.bargain;
|
package cn.iocoder.yudao.module.promotion.api.bargain;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
|
|
||||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
|
|
||||||
import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
|
import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
||||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.BARGAIN_ACTIVITY_NOT_EXISTS;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 砍价活动 Api 接口实现类
|
* 砍价活动 Api 接口实现类
|
||||||
*
|
*
|
||||||
@ -22,20 +17,8 @@ public class BargainActivityApiImpl implements BargainActivityApi {
|
|||||||
private BargainActivityService bargainActivityService;
|
private BargainActivityService bargainActivityService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBargainActivityStock(Long activityId, Integer count) {
|
public void updateBargainActivityStock(Long id, Integer count) {
|
||||||
// TODO @puhui999:可以整个实现到 bargainActivityService 中
|
bargainActivityService.updateBargainActivityStock(id, count);
|
||||||
// 查询砍价活动
|
|
||||||
BargainActivityDO activity = bargainActivityService.getBargainActivity(activityId);
|
|
||||||
if (activity == null) {
|
|
||||||
throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新砍价库存
|
|
||||||
// TODO @puhui999:考虑下并发更新问题
|
|
||||||
BargainActivityUpdateReqVO reqVO = new BargainActivityUpdateReqVO();
|
|
||||||
reqVO.setId(activityId);
|
|
||||||
reqVO.setStock(activity.getStock() - count);
|
|
||||||
bargainActivityService.updateBargainActivity(reqVO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package cn.iocoder.yudao.module.promotion.api.combination;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拼团活动 Api 接口实现类
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class CombinationApiImpl implements CombinationApi {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CombinationActivityService activityService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
|
||||||
|
activityService.validateCombination(reqDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,20 +1,10 @@
|
|||||||
package cn.iocoder.yudao.module.promotion.api.seckill;
|
package cn.iocoder.yudao.module.promotion.api.seckill;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
|
||||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
|
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
|
|
||||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
|
|
||||||
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
|
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
||||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_UPDATE_STOCK_FAIL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 秒杀活动接口 Api 接口实现类
|
* 秒杀活动接口 Api 接口实现类
|
||||||
@ -27,58 +17,9 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
|
|||||||
@Resource
|
@Resource
|
||||||
private SeckillActivityService activityService;
|
private SeckillActivityService activityService;
|
||||||
|
|
||||||
// TODO @puhui:建议这块弄到 activityService 实现哈;
|
|
||||||
// TODO @puhui:这个方法,要考虑事务性
|
|
||||||
@Override
|
@Override
|
||||||
public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
|
public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
|
||||||
// TODO @puhui999:长方法,最好有 1.1 1.2 2.1 这种步骤哈;
|
activityService.updateSeckillStock(updateStockReqDTO);
|
||||||
SeckillActivityDO seckillActivity = activityService.getSeckillActivity(updateStockReqDTO.getActivityId());
|
|
||||||
if (seckillActivity.getStock() < updateStockReqDTO.getCount()) {
|
|
||||||
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
|
||||||
}
|
|
||||||
// 获取活动商品
|
|
||||||
// TODO @puhui999:在一个方法里,dos 和 dolist 最好保持一致,要么用 s,要么用 list 哈;
|
|
||||||
List<SeckillProductDO> productDOs = activityService.getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
|
|
||||||
// TODO @puhui999:这个是不是搞成 CollectionUtils.convertMultiMap()
|
|
||||||
List<SeckillActivityUpdateStockReqDTO.Item> items = updateStockReqDTO.getItems();
|
|
||||||
Map<Long, List<Long>> map = new HashMap<>();
|
|
||||||
items.forEach(item -> {
|
|
||||||
if (map.containsKey(item.getSpuId())) {
|
|
||||||
List<Long> skuIds = map.get(item.getSpuId());
|
|
||||||
skuIds.add(item.getSkuId());
|
|
||||||
map.put(item.getSpuId(), skuIds);
|
|
||||||
} else {
|
|
||||||
List<Long> list = new ArrayList<>();
|
|
||||||
list.add(item.getSkuId());
|
|
||||||
map.put(item.getSpuId(), list);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// 过滤出购买的商品
|
|
||||||
// TODO @puhui999:productDOList 可以简化成 productList;一般来说,do 之类不用带着哈,在变量里;
|
|
||||||
List<SeckillProductDO> productDOList = CollectionUtils.filterList(productDOs, item -> map.get(item.getSpuId()).contains(item.getSkuId()));
|
|
||||||
Map<Long, SeckillActivityUpdateStockReqDTO.Item> productDOMap = CollectionUtils.convertMap(items, SeckillActivityUpdateStockReqDTO.Item::getSkuId, p -> p);
|
|
||||||
// 检查活动商品库存是否充足
|
|
||||||
// TODO @puhui999:避免 b 这种无业务含义的变量;
|
|
||||||
boolean b = CollectionUtils.anyMatch(productDOList, item -> {
|
|
||||||
SeckillActivityUpdateStockReqDTO.Item item1 = productDOMap.get(item.getSkuId());
|
|
||||||
return (item.getStock() < item1.getCount()) || (item.getStock() - item1.getCount()) < 0;
|
|
||||||
});
|
|
||||||
if (b) {
|
|
||||||
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
|
||||||
}
|
|
||||||
// TODO @puhui999:类似 doList,应该和下面的 update 逻辑粘的更紧密一点;so 在空行的时候,应该挪到 74 之后里去;甚至更合理,应该是 79 之后;说白了,逻辑要分块,每个模块涉及的代码要紧密在一起;
|
|
||||||
List<SeckillProductDO> doList = CollectionUtils.convertList(productDOList, item -> {
|
|
||||||
item.setStock(item.getStock() - productDOMap.get(item.getSkuId()).getCount());
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 更新活动库存
|
|
||||||
// TODO @puhui999:考虑下并发更新
|
|
||||||
seckillActivity.setStock(seckillActivity.getStock() + updateStockReqDTO.getCount());
|
|
||||||
seckillActivity.setTotalStock(seckillActivity.getTotalStock() - updateStockReqDTO.getCount());
|
|
||||||
activityService.updateSeckillActivity(seckillActivity);
|
|
||||||
// 更新活动商品库存
|
|
||||||
activityService.updateSeckillActivityProductList(doList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
|
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -28,4 +29,18 @@ public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
|
|||||||
return selectList(BargainActivityDO::getStatus, status);
|
return selectList(BargainActivityDO::getStatus, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新活动库存
|
||||||
|
*
|
||||||
|
* @param id 活动编号
|
||||||
|
* @param count 扣减的库存数量
|
||||||
|
* @return 影响的行数
|
||||||
|
*/
|
||||||
|
default int updateActivityStock(Long id, int count) {
|
||||||
|
return update(null, new LambdaUpdateWrapper<BargainActivityDO>()
|
||||||
|
.eq(BargainActivityDO::getId, id)
|
||||||
|
.gt(BargainActivityDO::getStock, 0) // TODO @puhui999:不是 > 0,是要大于 count 哈
|
||||||
|
.setSql("stock = stock - " + count));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
|
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -32,4 +33,19 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
|
|||||||
.eqIfPresent(SeckillActivityDO::getStatus, status));
|
.eqIfPresent(SeckillActivityDO::getStatus, status));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新活动库存
|
||||||
|
*
|
||||||
|
* @param id 活动编号
|
||||||
|
* @param count 扣减的库存数量
|
||||||
|
* @return 影响的行数
|
||||||
|
*/
|
||||||
|
default int updateActivityStock(Long id, int count) {
|
||||||
|
return update(null, new LambdaUpdateWrapper<SeckillActivityDO>()
|
||||||
|
.eq(SeckillActivityDO::getId, id)
|
||||||
|
.gt(SeckillActivityDO::getTotalStock, 0)
|
||||||
|
.setSql("stock = stock + " + count)
|
||||||
|
.setSql("totalStock = totalStock - " + count));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
|
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -23,4 +24,18 @@ public interface SeckillProductMapper extends BaseMapperX<SeckillProductDO> {
|
|||||||
return selectList(SeckillProductDO::getActivityId, ids);
|
return selectList(SeckillProductDO::getActivityId, ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新活动库存
|
||||||
|
*
|
||||||
|
* @param id 活动编号
|
||||||
|
* @param count 扣减的库存数量
|
||||||
|
* @return 影响的行数
|
||||||
|
*/
|
||||||
|
default int updateActivityStock(Long id, int count) {
|
||||||
|
return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
|
||||||
|
.eq(SeckillProductDO::getId, id)
|
||||||
|
.gt(SeckillProductDO::getStock, 0) // TODO @puhui999:不是 > 0,是要大于 count 哈
|
||||||
|
.setSql("stock = stock - " + count));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,14 @@ public interface BargainActivityService {
|
|||||||
*/
|
*/
|
||||||
void updateBargainActivity(@Valid BargainActivityUpdateReqVO updateReqVO);
|
void updateBargainActivity(@Valid BargainActivityUpdateReqVO updateReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新砍价活动库存
|
||||||
|
*
|
||||||
|
* @param id 砍价活动编号
|
||||||
|
* @param count 购买数量
|
||||||
|
*/
|
||||||
|
void updateBargainActivityStock(Long id, Integer count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除砍价活动
|
* 删除砍价活动
|
||||||
*
|
*
|
||||||
@ -53,5 +61,4 @@ public interface BargainActivityService {
|
|||||||
*/
|
*/
|
||||||
PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
|
PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ public class BargainActivityServiceImpl implements BargainActivityService {
|
|||||||
private ProductSkuApi productSkuApi;
|
private ProductSkuApi productSkuApi;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Long createBargainActivity(BargainActivityCreateReqVO createReqVO) {
|
public Long createBargainActivity(BargainActivityCreateReqVO createReqVO) {
|
||||||
// 校验商品 SPU 是否存在是否参加的别的活动
|
// 校验商品 SPU 是否存在是否参加的别的活动
|
||||||
validateBargainConflict(createReqVO.getSpuId(), null);
|
validateBargainConflict(createReqVO.getSpuId(), null);
|
||||||
@ -53,6 +54,7 @@ public class BargainActivityServiceImpl implements BargainActivityService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void updateBargainActivity(BargainActivityUpdateReqVO updateReqVO) {
|
public void updateBargainActivity(BargainActivityUpdateReqVO updateReqVO) {
|
||||||
// 校验存在
|
// 校验存在
|
||||||
BargainActivityDO activityDO = validateBargainActivityExists(updateReqVO.getId());
|
BargainActivityDO activityDO = validateBargainActivityExists(updateReqVO.getId());
|
||||||
@ -70,6 +72,22 @@ public class BargainActivityServiceImpl implements BargainActivityService {
|
|||||||
bargainActivityMapper.updateById(updateObj);
|
bargainActivityMapper.updateById(updateObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void updateBargainActivityStock(Long id, Integer count) {
|
||||||
|
// 查询砍价活动
|
||||||
|
BargainActivityDO activity = getBargainActivity(id);
|
||||||
|
if (activity == null) {
|
||||||
|
throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新砍价库存
|
||||||
|
int updateCount = bargainActivityMapper.updateActivityStock(id, count);
|
||||||
|
if (updateCount == 0) {
|
||||||
|
throw exception(BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void validateBargainConflict(Long spuId, Long activityId) {
|
private void validateBargainConflict(Long spuId, Long activityId) {
|
||||||
// 查询所有开启的砍价活动
|
// 查询所有开启的砍价活动
|
||||||
List<BargainActivityDO> activityList = bargainActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
List<BargainActivityDO> activityList = bargainActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.promotion.service.combination;
|
package cn.iocoder.yudao.module.promotion.service.combination;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
|
||||||
@ -72,4 +73,11 @@ public interface CombinationActivityService {
|
|||||||
*/
|
*/
|
||||||
List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
|
List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新拼图活动库存
|
||||||
|
*
|
||||||
|
* @param reqDTO 请求
|
||||||
|
*/
|
||||||
|
void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
|||||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
|
||||||
@ -16,8 +17,12 @@ import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product
|
|||||||
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
|
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
|
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
|
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
|
||||||
|
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
|
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper;
|
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper;
|
||||||
|
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
@ -28,8 +33,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
|
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
|
||||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
|
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
|
||||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||||
@ -49,10 +54,16 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
|||||||
@Resource
|
@Resource
|
||||||
private CombinationProductMapper combinationProductMapper;
|
private CombinationProductMapper combinationProductMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
@Lazy // TODO @puhui999:我感觉 validateCombination 可以挪到 CombinationRecordServiceImpl 中,因为它更偏向能不能创建拼团记录;
|
||||||
|
private CombinationRecordService combinationRecordService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ProductSpuApi productSpuApi;
|
private ProductSpuApi productSpuApi;
|
||||||
@Resource
|
@Resource
|
||||||
private ProductSkuApi productSkuApi;
|
private ProductSkuApi productSkuApi;
|
||||||
|
@Resource
|
||||||
|
private TradeOrderApi tradeOrderApi;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@ -97,7 +108,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
|||||||
* 校验拼团商品是否都存在
|
* 校验拼团商品是否都存在
|
||||||
*
|
*
|
||||||
* @param spuId 商品 SPU 编号
|
* @param spuId 商品 SPU 编号
|
||||||
* @param products 秒杀商品
|
* @param products 拼团商品
|
||||||
*/
|
*/
|
||||||
private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
|
private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
|
||||||
// 1. 校验商品 spu 是否存在
|
// 1. 校验商品 spu 是否存在
|
||||||
@ -123,7 +134,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
|||||||
CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId());
|
CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId());
|
||||||
// 校验状态
|
// 校验状态
|
||||||
if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
|
if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
|
||||||
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
|
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE);
|
||||||
}
|
}
|
||||||
// 校验商品冲突
|
// 校验商品冲突
|
||||||
validateProductConflict(updateReqVO.getSpuId(), updateReqVO.getId());
|
validateProductConflict(updateReqVO.getSpuId(), updateReqVO.getId());
|
||||||
@ -205,4 +216,36 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
|||||||
return combinationProductMapper.selectListByActivityIds(activityIds);
|
return combinationProductMapper.selectListByActivityIds(activityIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
|
||||||
|
// 1.1 校验拼团活动是否存在
|
||||||
|
CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
|
||||||
|
// 1.2 校验活动是否开启
|
||||||
|
if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
|
||||||
|
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
|
||||||
|
}
|
||||||
|
// 1.3 校验是否超出单次限购数量
|
||||||
|
if (activity.getSingleLimitCount() < reqDTO.getCount()) {
|
||||||
|
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 校验是否超出总限购数量
|
||||||
|
// TODO @puhui999:userId 应该接口传递哈;要保证 service 无状态
|
||||||
|
List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(
|
||||||
|
getLoginUserId(), reqDTO.getActivityId());
|
||||||
|
// TODO @puhui999:最好 if true return;减少括号层数
|
||||||
|
if (CollUtil.isNotEmpty(recordList)) {
|
||||||
|
// 过滤出拼团成功的
|
||||||
|
// TODO @puhui999:count 要不存一个在 record 里?
|
||||||
|
List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
|
||||||
|
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
|
||||||
|
Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList,
|
||||||
|
CombinationRecordDO::getOrderId,
|
||||||
|
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
|
||||||
|
if (activity.getTotalLimitCount() < countSum) {
|
||||||
|
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,19 @@ package cn.iocoder.yudao.module.promotion.service.combination;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||||
|
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||||
|
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
||||||
|
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||||
|
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||||
|
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
|
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
|
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
|
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
|
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
|
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
|
||||||
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
|
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
@ -31,11 +38,20 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
|||||||
public class CombinationRecordServiceImpl implements CombinationRecordService {
|
public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
|
@Lazy
|
||||||
private CombinationActivityService combinationActivityService;
|
private CombinationActivityService combinationActivityService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CombinationRecordMapper recordMapper;
|
private CombinationRecordMapper recordMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MemberUserApi memberUserApi;
|
||||||
|
@Resource
|
||||||
|
@Lazy
|
||||||
|
private ProductSpuApi productSpuApi;
|
||||||
|
@Resource
|
||||||
|
@Lazy
|
||||||
|
private ProductSkuApi productSkuApi;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
|
public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
|
||||||
@ -102,21 +118,29 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
|||||||
// 1.5 父拼团是否存在,是否已经满了
|
// 1.5 父拼团是否存在,是否已经满了
|
||||||
if (reqDTO.getHeadId() != null) {
|
if (reqDTO.getHeadId() != null) {
|
||||||
// 查询进行中的父拼团
|
// 查询进行中的父拼团
|
||||||
CombinationRecordDO recordDO1 = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
|
CombinationRecordDO record = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
|
||||||
if (recordDO1 == null) {
|
if (record == null) {
|
||||||
throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
|
throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
// 校验拼团是否满足要求
|
// 校验拼团是否满足要求
|
||||||
if (ObjectUtil.equal(recordDO1.getUserCount(), recordDO1.getUserSize())) {
|
if (ObjectUtil.equal(record.getUserCount(), record.getUserSize())) {
|
||||||
throw exception(COMBINATION_RECORD_USER_FULL);
|
throw exception(COMBINATION_RECORD_USER_FULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 创建拼团记录
|
// 2. 创建拼团记录
|
||||||
|
// TODO @puhui999:可以把 user、spu、sku 一起放 convert 里哈;
|
||||||
CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
|
CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
|
||||||
record.setVirtualGroup(false);
|
record.setVirtualGroup(false);
|
||||||
record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
|
record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
|
||||||
record.setUserSize(activity.getUserSize());
|
record.setUserSize(activity.getUserSize());
|
||||||
|
MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
|
||||||
|
record.setNickname(user.getNickname());
|
||||||
|
record.setAvatar(user.getAvatar());
|
||||||
|
ProductSpuRespDTO spu = productSpuApi.getSpu(record.getSpuId());
|
||||||
|
record.setSpuName(spu.getName());
|
||||||
|
ProductSkuRespDTO sku = productSkuApi.getSku(record.getSkuId());
|
||||||
|
record.setPicUrl(sku.getPicUrl());
|
||||||
recordMapper.insert(record);
|
recordMapper.insert(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.promotion.service.seckill;
|
package cn.iocoder.yudao.module.promotion.service.seckill;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
|
||||||
@ -34,18 +35,11 @@ public interface SeckillActivityService {
|
|||||||
void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
|
void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新秒杀活动
|
* 更新秒杀库存
|
||||||
*
|
*
|
||||||
* @param activityDO 秒杀活动
|
* @param updateStockReqDTO 更新信息
|
||||||
*/
|
*/
|
||||||
void updateSeckillActivity(SeckillActivityDO activityDO);
|
void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO);
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新秒杀活动商品
|
|
||||||
*
|
|
||||||
* @param productList 活动商品列表
|
|
||||||
*/
|
|
||||||
void updateSeckillActivityProductList(List<SeckillProductDO> productList);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭秒杀活动
|
* 关闭秒杀活动
|
||||||
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
|||||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
|
||||||
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
|
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
|
||||||
@ -145,13 +146,36 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateSeckillActivity(SeckillActivityDO activityDO) {
|
@Transactional(rollbackFor = Exception.class)
|
||||||
seckillActivityMapper.updateById(activityDO);
|
public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
|
||||||
}
|
// 1、校验秒杀活动是否存在
|
||||||
|
SeckillActivityDO seckillActivity = getSeckillActivity(updateStockReqDTO.getActivityId());
|
||||||
|
// 1.1、校验库存是否充足
|
||||||
|
if (seckillActivity.getTotalStock() < updateStockReqDTO.getCount()) {
|
||||||
|
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
// 2、获取活动商品
|
||||||
public void updateSeckillActivityProductList(List<SeckillProductDO> productList) {
|
List<SeckillProductDO> products = getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
|
||||||
seckillProductMapper.updateBatch(productList);
|
// 2.1、过滤出购买的商品
|
||||||
|
SeckillProductDO product = findFirst(products, item -> ObjectUtil.equal(updateStockReqDTO.getItem().getSkuId(), item.getSkuId()));
|
||||||
|
// 2.2、检查活动商品库存是否充足
|
||||||
|
boolean isSufficient = product == null || (product.getStock() == 0 || (product.getStock() < updateStockReqDTO.getItem().getCount()) || (product.getStock() - updateStockReqDTO.getItem().getCount()) < 0);
|
||||||
|
if (isSufficient) {
|
||||||
|
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3、更新活动商品库存
|
||||||
|
int updateCount = seckillProductMapper.updateActivityStock(product.getId(), updateStockReqDTO.getItem().getCount());
|
||||||
|
if (updateCount == 0) {
|
||||||
|
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4、更新活动库存
|
||||||
|
updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), updateStockReqDTO.getCount());
|
||||||
|
if (updateCount == 0) {
|
||||||
|
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;
|
|||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
// TODO @疯狂:是不是不需要这个啦?
|
||||||
/**
|
/**
|
||||||
* 分销 API 接口
|
* 分销 API 接口
|
||||||
*
|
*
|
||||||
@ -31,6 +32,7 @@ public interface BrokerageApi {
|
|||||||
*/
|
*/
|
||||||
default boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime) {
|
default boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime) {
|
||||||
// 注册时间在30秒内的,都算新用户
|
// 注册时间在30秒内的,都算新用户
|
||||||
|
// TODO @疯狂:这个要不抽到 service 里哈?
|
||||||
boolean isNewUser = LocalDateTimeUtils.afterNow(registerTime.minusSeconds(30));
|
boolean isNewUser = LocalDateTimeUtils.afterNow(registerTime.minusSeconds(30));
|
||||||
return bindUser(userId, bindUserId, isNewUser);
|
return bindUser(userId, bindUserId, isNewUser);
|
||||||
}
|
}
|
||||||
@ -43,5 +45,8 @@ public interface BrokerageApi {
|
|||||||
* @param isNewUser 是否为新用户
|
* @param isNewUser 是否为新用户
|
||||||
* @return 是否绑定
|
* @return 是否绑定
|
||||||
*/
|
*/
|
||||||
boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull Boolean isNewUser);
|
boolean bindUser(@NotNull(message = "用户编号不能为空") Long userId,
|
||||||
|
@NotNull(message = "推广员编号不能为空") Long bindUserId,
|
||||||
|
@NotNull Boolean isNewUser);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.trade.api.order;
|
package cn.iocoder.yudao.module.trade.api.order;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 订单 API 接口
|
* 订单 API 接口
|
||||||
*
|
*
|
||||||
@ -16,4 +18,13 @@ public interface TradeOrderApi {
|
|||||||
*/
|
*/
|
||||||
Long validateOrder(Long userId, Long orderItemId);
|
Long validateOrder(Long userId, Long orderItemId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取订单项商品购买数量总和
|
||||||
|
*
|
||||||
|
* @param orderIds 订单编号
|
||||||
|
* @param skuIds sku 编号
|
||||||
|
* @return 订单项商品购买数量总和
|
||||||
|
*/
|
||||||
|
Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,9 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000023, "交易订单发货失败,砍价未成功");
|
ErrorCode ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000023, "交易订单发货失败,砍价未成功");
|
||||||
ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1011000024, "交易订单发货失败,发货类型不是快递");
|
ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1011000024, "交易订单发货失败,发货类型不是快递");
|
||||||
ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1011000025, "交易订单取消失败,订单不是【待支付】状态");
|
ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1011000025, "交易订单取消失败,订单不是【待支付】状态");
|
||||||
|
ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1011000026, "支付订单调价失败,原因:支付订单已付款,不能调价");
|
||||||
|
ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1011000027, "支付订单调价失败,原因:价格没有变化");
|
||||||
|
ErrorCode ORDER_UPDATE_PRICE_FAIL_NOT_ITEM = new ErrorCode(1011000028, "支付订单调价失败,原因:订单项不存在");
|
||||||
|
|
||||||
// ========== After Sale 模块 1011000100 ==========
|
// ========== After Sale 模块 1011000100 ==========
|
||||||
ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");
|
ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");
|
||||||
|
@ -6,6 +6,7 @@ import lombok.Getter;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
// TODO @疯狂:是不是搞成层级,类似 level 这样?因为本质上,它是 1 级、2 级、3 级这样的关系哈
|
||||||
/**
|
/**
|
||||||
* 分销用户类型枚举
|
* 分销用户类型枚举
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.enums.order;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单操作类型的枚举
|
||||||
|
*
|
||||||
|
* @author 陈賝
|
||||||
|
* @since 2023/7/6 15:31
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum TradeOrderOperateTypeEnum {
|
||||||
|
|
||||||
|
MEMBER_CREATE(1, "用户下单"),
|
||||||
|
TEST(2, "用户({nickname})做了({thing})"),
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private final Integer type;
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private final String content;
|
||||||
|
|
||||||
|
}
|
@ -6,6 +6,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND;
|
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND;
|
||||||
@ -32,4 +33,9 @@ public class TradeOrderApiImpl implements TradeOrderApi {
|
|||||||
return item.getOrderId();
|
return item.getOrderId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
|
||||||
|
return tradeOrderQueryService.getOrderItemCountSumByOrderIdAndSkuId(orderIds, skuIds);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -76,10 +76,9 @@ public class TradeAfterSaleController {
|
|||||||
public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
|
public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
|
||||||
// 查询订单
|
// 查询订单
|
||||||
TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id);
|
TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id);
|
||||||
// TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
|
if (afterSale == null) {
|
||||||
// if (afterSale == null) {
|
return success(null);
|
||||||
// return success(null, AFTER_SALE_NOT_FOUND.getMsg());
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// 查询订单
|
// 查询订单
|
||||||
TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId());
|
TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId());
|
||||||
|
@ -55,10 +55,11 @@ public class BrokerageRecordController {
|
|||||||
public CommonResult<PageResult<BrokerageRecordRespVO>> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) {
|
public CommonResult<PageResult<BrokerageRecordRespVO>> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) {
|
||||||
PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO);
|
PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO);
|
||||||
|
|
||||||
|
// 查询用户信息
|
||||||
Set<Long> userIds = convertSet(pageResult.getList(), BrokerageRecordDO::getUserId);
|
Set<Long> userIds = convertSet(pageResult.getList(), BrokerageRecordDO::getUserId);
|
||||||
userIds.addAll(convertList(pageResult.getList(), BrokerageRecordDO::getSourceUserId));
|
userIds.addAll(convertList(pageResult.getList(), BrokerageRecordDO::getSourceUserId));
|
||||||
Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
|
Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
|
||||||
|
// 拼接数据
|
||||||
return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult, userMap));
|
return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult, userMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,10 +67,9 @@ public class TradeOrderController {
|
|||||||
public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
|
public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
|
||||||
// 查询订单
|
// 查询订单
|
||||||
TradeOrderDO order = tradeOrderQueryService.getOrder(id);
|
TradeOrderDO order = tradeOrderQueryService.getOrder(id);
|
||||||
// TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
|
if (order == null) {
|
||||||
// if (order == null) {
|
return success(null);
|
||||||
// return success(null, ORDER_NOT_FOUND.getMsg());
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// 查询订单项
|
// 查询订单项
|
||||||
List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);
|
List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);
|
||||||
|
@ -31,19 +31,15 @@ public class TradeOrderPageReqVO extends PageParam {
|
|||||||
@Mobile
|
@Mobile
|
||||||
private String userMobile;
|
private String userMobile;
|
||||||
|
|
||||||
|
@Schema(description = "配送方式", example = "1")
|
||||||
|
private Integer deliveryType;
|
||||||
|
|
||||||
@Schema(description = "发货物流公司编号", example = "1")
|
@Schema(description = "发货物流公司编号", example = "1")
|
||||||
private Long logisticsId;
|
private Long logisticsId;
|
||||||
|
|
||||||
@Schema(description = "自提门店编号", example = "[1,2]")
|
@Schema(description = "自提门店编号", example = "[1,2]")
|
||||||
private List<Long> pickUpStoreIds;
|
private List<Long> pickUpStoreIds;
|
||||||
|
|
||||||
@Schema(description = "收件人名称", example = "小红")
|
|
||||||
private String receiverName;
|
|
||||||
|
|
||||||
@Schema(description = "收件人手机", example = "1560")
|
|
||||||
@Mobile
|
|
||||||
private String receiverMobile;
|
|
||||||
|
|
||||||
@Schema(description = "订单类型", example = "1")
|
@Schema(description = "订单类型", example = "1")
|
||||||
private Integer type;
|
private Integer type;
|
||||||
|
|
||||||
@ -61,5 +57,5 @@ public class TradeOrderPageReqVO extends PageParam {
|
|||||||
@Schema(description = "订单来源", example = "10")
|
@Schema(description = "订单来源", example = "10")
|
||||||
@InEnum(value = TerminalEnum.class, message = "订单来源 {value}")
|
@InEnum(value = TerminalEnum.class, message = "订单来源 {value}")
|
||||||
private Integer terminal;
|
private Integer terminal;
|
||||||
// TODO 添加配送方式筛选
|
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ public class AppBrokerageUserMySummaryRespVO {
|
|||||||
@Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234")
|
@Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234")
|
||||||
private Integer frozenPrice;
|
private Integer frozenPrice;
|
||||||
|
|
||||||
@Schema(description = "分销用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
@Schema(description = "分销用户数量(一级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||||
private Integer firstBrokerageUserCount;
|
private Integer firstBrokerageUserCount;
|
||||||
|
|
||||||
@Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
@Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.trade.controller.app.order;
|
package cn.iocoder.yudao.module.trade.controller.app.order;
|
||||||
|
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||||
@ -11,8 +12,11 @@ import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
|
|||||||
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
|
||||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
||||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
||||||
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
|
||||||
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
||||||
|
import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog;
|
||||||
|
import cn.iocoder.yudao.module.trade.framework.order.core.utils.TradeOrderLogUtils;
|
||||||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
||||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
|
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
|
||||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
|
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
|
||||||
@ -61,7 +65,10 @@ public class AppTradeOrderController {
|
|||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@Operation(summary = "创建订单")
|
@Operation(summary = "创建订单")
|
||||||
@PreAuthenticated
|
@PreAuthenticated
|
||||||
|
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.TEST)
|
||||||
public CommonResult<AppTradeOrderCreateRespVO> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO) {
|
public CommonResult<AppTradeOrderCreateRespVO> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO) {
|
||||||
|
TradeOrderLogUtils.setOrderInfo(10L, 1, 2,
|
||||||
|
MapUtil.<String, Object>builder().put("nickname", "小明").put("thing", "种土豆").build());
|
||||||
TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), getClientIP(), createReqVO);
|
TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), getClientIP(), createReqVO);
|
||||||
return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
|
return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
|
||||||
}
|
}
|
||||||
@ -81,10 +88,9 @@ public class AppTradeOrderController {
|
|||||||
public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) {
|
public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) {
|
||||||
// 查询订单
|
// 查询订单
|
||||||
TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
|
TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
|
||||||
// TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
|
if (order == null) {
|
||||||
// if (order == null) {
|
return success(null);
|
||||||
// return success(null, ORDER_NOT_FOUND.getMsg());
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// 查询订单项
|
// 查询订单项
|
||||||
List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId());
|
List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId());
|
||||||
|
@ -52,15 +52,12 @@ public interface BrokerageRecordConvert {
|
|||||||
|
|
||||||
default PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> pageResult, Map<Long, MemberUserRespDTO> userMap) {
|
default PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> pageResult, Map<Long, MemberUserRespDTO> userMap) {
|
||||||
PageResult<BrokerageRecordRespVO> result = convertPage(pageResult);
|
PageResult<BrokerageRecordRespVO> result = convertPage(pageResult);
|
||||||
|
|
||||||
for (BrokerageRecordRespVO respVO : result.getList()) {
|
for (BrokerageRecordRespVO respVO : result.getList()) {
|
||||||
Optional.ofNullable(userMap.get(respVO.getUserId())).ifPresent(user ->
|
Optional.ofNullable(userMap.get(respVO.getUserId())).ifPresent(user ->
|
||||||
respVO.setUserNickname(user.getNickname()).setUserAvatar(user.getAvatar()));
|
respVO.setUserNickname(user.getNickname()).setUserAvatar(user.getAvatar()));
|
||||||
|
|
||||||
Optional.ofNullable(userMap.get(respVO.getSourceUserId())).ifPresent(user ->
|
Optional.ofNullable(userMap.get(respVO.getSourceUserId())).ifPresent(user ->
|
||||||
respVO.setSourceUserNickname(user.getNickname()).setSourceUserAvatar(user.getAvatar()));
|
respVO.setSourceUserNickname(user.getNickname()).setSourceUserAvatar(user.getAvatar()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,18 +35,18 @@ public interface BrokerageUserConvert {
|
|||||||
Map<Long, Long> brokerageUserCountMap,
|
Map<Long, Long> brokerageUserCountMap,
|
||||||
Map<Long, UserBrokerageSummaryBO> userOrderSummaryMap) {
|
Map<Long, UserBrokerageSummaryBO> userOrderSummaryMap) {
|
||||||
PageResult<BrokerageUserRespVO> result = convertPage(pageResult);
|
PageResult<BrokerageUserRespVO> result = convertPage(pageResult);
|
||||||
for (BrokerageUserRespVO vo : result.getList()) {
|
for (BrokerageUserRespVO userVO : result.getList()) {
|
||||||
// 用户信息
|
// 用户信息
|
||||||
copyTo(userMap.get(vo.getId()), vo);
|
copyTo(userMap.get(userVO.getId()), userVO);
|
||||||
|
|
||||||
// 推广用户数量
|
// 推广用户数量
|
||||||
vo.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, vo.getId(), 0));
|
userVO.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, userVO.getId(), 0));
|
||||||
// 推广订单数量、推广订单金额
|
// 推广订单数量、推广订单金额
|
||||||
Optional<UserBrokerageSummaryBO> orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(vo.getId()));
|
Optional<UserBrokerageSummaryBO> orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(userVO.getId()));
|
||||||
vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0))
|
userVO.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0))
|
||||||
.setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0));
|
.setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0));
|
||||||
// todo 已提现次数、已提现金额
|
// todo 已提现次数、已提现金额
|
||||||
vo.setWithdrawCount(0).setWithdrawPrice(0);
|
userVO.setWithdrawCount(0).setWithdrawPrice(0);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,9 @@ import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDT
|
|||||||
import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
|
import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
|
||||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
|
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
|
||||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
|
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
|
||||||
import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
|
import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
|
||||||
@ -32,6 +34,8 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEn
|
|||||||
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
|
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
|
||||||
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
||||||
import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
|
import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
@ -254,21 +258,15 @@ public interface TradeOrderConvert {
|
|||||||
AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
|
AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
|
||||||
|
|
||||||
@Mappings({
|
@Mappings({
|
||||||
@Mapping(target = "activityId", source = "createReqVO.combinationActivityId"),
|
@Mapping(target = "activityId", source = "afterOrderCreateReqBO.combinationActivityId"),
|
||||||
@Mapping(target = "spuId", source = "orderItem.spuId"),
|
@Mapping(target = "spuId", source = "afterOrderCreateReqBO.spuId"),
|
||||||
@Mapping(target = "skuId", source = "orderItem.skuId"),
|
@Mapping(target = "skuId", source = "afterOrderCreateReqBO.skuId"),
|
||||||
@Mapping(target = "userId", source = "order.userId"),
|
@Mapping(target = "orderId", source = "afterOrderCreateReqBO.orderId"),
|
||||||
@Mapping(target = "orderId", source = "order.id"),
|
@Mapping(target = "userId", source = "afterOrderCreateReqBO.userId"),
|
||||||
@Mapping(target = "headId", source = "createReqVO.combinationHeadId"),
|
@Mapping(target = "headId", source = "afterOrderCreateReqBO.combinationHeadId"),
|
||||||
@Mapping(target = "spuName", source = "orderItem.spuName"),
|
@Mapping(target = "combinationPrice", source = "afterOrderCreateReqBO.payPrice"),
|
||||||
@Mapping(target = "picUrl", source = "orderItem.picUrl"),
|
|
||||||
@Mapping(target = "combinationPrice", source = "orderItem.payPrice"),
|
|
||||||
@Mapping(target = "nickname", source = "user.nickname"),
|
|
||||||
@Mapping(target = "avatar", source = "user.avatar"),
|
|
||||||
@Mapping(target = "status", ignore = true)
|
|
||||||
})
|
})
|
||||||
CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem,
|
CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO afterOrderCreateReqBO);
|
||||||
AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
|
|
||||||
|
|
||||||
List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
|
List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
|
||||||
|
|
||||||
@ -279,11 +277,29 @@ public interface TradeOrderConvert {
|
|||||||
TradeOrderDO convert(TradeOrderRemarkReqVO reqVO);
|
TradeOrderDO convert(TradeOrderRemarkReqVO reqVO);
|
||||||
|
|
||||||
default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) {
|
default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) {
|
||||||
return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId()))
|
return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId())
|
||||||
.setSourceUserId(item.getUserId())
|
|
||||||
.setBasePrice(item.getPayPrice() * item.getCount())
|
.setBasePrice(item.getPayPrice() * item.getCount())
|
||||||
.setFirstFixedPrice(sku.getSubCommissionFirstPrice())
|
.setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) // TODO @疯狂:标题类似:木晴冰雪成功购买云时代的JVM原理与实战;茫农成功购买深入拆解消息队列47讲
|
||||||
.setSecondFixedPrice(sku.getSubCommissionSecondPrice())
|
.setFirstFixedPrice(sku.getFirstBrokerageRecord()).setSecondFixedPrice(sku.getSecondBrokerageRecord());
|
||||||
.setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Mapping(target = "activityId", source = "reqBO.seckillActivityId")
|
||||||
|
SeckillActivityUpdateStockReqDTO convert(TradeBeforeOrderCreateReqBO reqBO);
|
||||||
|
|
||||||
|
@Mapping(target = "activityId", source = "reqBO.combinationActivityId")
|
||||||
|
CombinationActivityUpdateStockReqDTO convert1(TradeBeforeOrderCreateReqBO reqBO);
|
||||||
|
|
||||||
|
TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
|
||||||
|
|
||||||
|
@Mappings({
|
||||||
|
@Mapping(target = "combinationActivityId", source = "createReqVO.combinationActivityId"),
|
||||||
|
@Mapping(target = "combinationHeadId", source = "createReqVO.combinationHeadId"),
|
||||||
|
@Mapping(target = "spuId", source = "orderItem.spuId"),
|
||||||
|
@Mapping(target = "skuId", source = "orderItem.skuId"),
|
||||||
|
@Mapping(target = "orderId", source = "tradeOrderDO.id"),
|
||||||
|
@Mapping(target = "userId", source = "userId"),
|
||||||
|
@Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"),
|
||||||
|
})
|
||||||
|
TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -85,13 +85,13 @@ public class BrokerageRecordDO extends BaseDO {
|
|||||||
/**
|
/**
|
||||||
* 来源用户类型
|
* 来源用户类型
|
||||||
* <p>
|
* <p>
|
||||||
* 枚举 {@link BrokerageUserTypeEnum}
|
* 枚举 {@link BrokerageUserTypeEnum},被推广用户和 {@link #userId} 的推广层级关系
|
||||||
*/
|
*/
|
||||||
private Integer sourceUserType;
|
private Integer sourceUserType;
|
||||||
/**
|
/**
|
||||||
* 来源用户编号
|
* 来源用户编号
|
||||||
* <p>
|
* <p>
|
||||||
* 关联 MemberUserDO.id
|
* 关联 MemberUserDO.id 字段,被推广用户的编号
|
||||||
*/
|
*/
|
||||||
private Long sourceUserId;
|
private Long sourceUserId;
|
||||||
|
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.dal.dataobject.order;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单日志 DO
|
||||||
|
*
|
||||||
|
* @author 陈賝
|
||||||
|
*/
|
||||||
|
@TableName("trade_order_log")
|
||||||
|
@KeySequence("trade_order_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class TradeOrderLogDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户类型 - 系统
|
||||||
|
*
|
||||||
|
* 例如说:Job 自动过期订单时,通过系统自动操作
|
||||||
|
*/
|
||||||
|
public static final Integer USER_TYPE_SYSTEM = 0;
|
||||||
|
/**
|
||||||
|
* 用户编号 - 系统
|
||||||
|
*/
|
||||||
|
public static final Long USER_ID_SYSTEM = 0L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编号
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*
|
||||||
|
* 关联 AdminUserDO 的 id 字段、或者 MemberUserDO 的 id 字段
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*
|
||||||
|
* 枚举 {@link UserTypeEnum}
|
||||||
|
*/
|
||||||
|
private Integer userType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单号
|
||||||
|
*
|
||||||
|
* 关联 {@link TradeOrderDO#getId()}
|
||||||
|
*/
|
||||||
|
private Long orderId;
|
||||||
|
/**
|
||||||
|
* 操作前状态
|
||||||
|
*/
|
||||||
|
private Integer beforeStatus;
|
||||||
|
/**
|
||||||
|
* 操作后状态
|
||||||
|
*/
|
||||||
|
private Integer afterStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作类型
|
||||||
|
*
|
||||||
|
* {@link TradeOrderOperateTypeEnum}
|
||||||
|
*/
|
||||||
|
private Integer operateType;
|
||||||
|
/**
|
||||||
|
* 订单日志信息
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
}
|
@ -26,7 +26,7 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
|
|||||||
default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) {
|
default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) {
|
||||||
boolean sourceUserTypeCondition = reqVO.getSourceUserType() != null &&
|
boolean sourceUserTypeCondition = reqVO.getSourceUserType() != null &&
|
||||||
!BrokerageUserTypeEnum.ALL.getType().equals(reqVO.getSourceUserType());
|
!BrokerageUserTypeEnum.ALL.getType().equals(reqVO.getSourceUserType());
|
||||||
|
// 分页查询
|
||||||
return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>()
|
return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>()
|
||||||
.eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId())
|
.eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId())
|
||||||
.eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType())
|
.eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType())
|
||||||
@ -54,7 +54,8 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
|
|||||||
BrokerageRecordDO::getUserId, userId);
|
BrokerageRecordDO::getUserId, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Select("SELECT COUNT(1), SUM(price) FROM trade_brokerage_record WHERE user_id = #{userId} AND biz_type = #{bizType} AND status = #{status}")
|
@Select("SELECT COUNT(1), SUM(price) FROM trade_brokerage_record " +
|
||||||
|
"WHERE user_id = #{userId} AND biz_type = #{bizType} AND status = #{status}")
|
||||||
UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId,
|
UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId,
|
||||||
@Param("bizType") Integer bizType,
|
@Param("bizType") Integer bizType,
|
||||||
@Param("status") Integer status);
|
@Param("status") Integer status);
|
||||||
|
@ -36,8 +36,9 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
|
|||||||
} else if (BrokerageUserTypeEnum.SECOND.getType().equals(reqVO.getUserType())) {
|
} else if (BrokerageUserTypeEnum.SECOND.getType().equals(reqVO.getUserType())) {
|
||||||
buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper);
|
buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper);
|
||||||
} else {
|
} else {
|
||||||
|
// TODO @疯狂:要不要把这个逻辑,挪到 Service 里,算出子用户有哪些,然后 IN?
|
||||||
buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper);
|
buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper);
|
||||||
buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper.or());
|
buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper.or()); // 通过 or 实现多个条件
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,8 +46,8 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
|
|||||||
wrapper.eq(BrokerageUserDO::getBindUserId, bindUserId);
|
wrapper.eq(BrokerageUserDO::getBindUserId, bindUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void buildSecondBindUserCondition(Long bindUserId, LambdaQueryWrapper<BrokerageUserDO> w) {
|
static void buildSecondBindUserCondition(Long bindUserId, LambdaQueryWrapper<BrokerageUserDO> wrapper) {
|
||||||
w.inSql(BrokerageUserDO::getBindUserId, StrUtil.format("SELECT id FROM trade_brokerage_user WHERE bind_user_id = {}", bindUserId));
|
wrapper.inSql(BrokerageUserDO::getBindUserId, StrUtil.format("SELECT id FROM trade_brokerage_user WHERE bind_user_id = {}", bindUserId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -142,4 +143,5 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
|
|||||||
|
|
||||||
@Select("SELECT COUNT(1) from trade_brokerage_user WHERE bind_user_id IN (SELECT id FROM trade_brokerage_user WHERE bind_user_id = #{bindUserId})")
|
@Select("SELECT COUNT(1) from trade_brokerage_user WHERE bind_user_id IN (SELECT id FROM trade_brokerage_user WHERE bind_user_id = #{bindUserId})")
|
||||||
Long selectCountByBindUserIdInBindUserId(Long bindUserId);
|
Long selectCountByBindUserIdInBindUserId(Long bindUserId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
|
|||||||
default List<TradeOrderItemDO> selectListByOrderIdAnSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
|
default List<TradeOrderItemDO> selectListByOrderIdAnSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
|
||||||
return selectList(new LambdaQueryWrapperX<TradeOrderItemDO>()
|
return selectList(new LambdaQueryWrapperX<TradeOrderItemDO>()
|
||||||
.in(TradeOrderItemDO::getOrderId, orderIds)
|
.in(TradeOrderItemDO::getOrderId, orderIds)
|
||||||
.eq(TradeOrderItemDO::getSkuId, skuIds));
|
.in(TradeOrderItemDO::getSkuId, skuIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
default TradeOrderItemDO selectByIdAndUserId(Long orderItemId, Long loginUserId) {
|
default TradeOrderItemDO selectByIdAndUserId(Long orderItemId, Long loginUserId) {
|
||||||
|
@ -27,13 +27,12 @@ public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> {
|
|||||||
return selectPage(reqVO, new LambdaQueryWrapperX<TradeOrderDO>()
|
return selectPage(reqVO, new LambdaQueryWrapperX<TradeOrderDO>()
|
||||||
.likeIfPresent(TradeOrderDO::getNo, reqVO.getNo())
|
.likeIfPresent(TradeOrderDO::getNo, reqVO.getNo())
|
||||||
.eqIfPresent(TradeOrderDO::getUserId, reqVO.getUserId())
|
.eqIfPresent(TradeOrderDO::getUserId, reqVO.getUserId())
|
||||||
|
.eqIfPresent(TradeOrderDO::getDeliveryType, reqVO.getDeliveryType())
|
||||||
.inIfPresent(TradeOrderDO::getUserId, userIds)
|
.inIfPresent(TradeOrderDO::getUserId, userIds)
|
||||||
.likeIfPresent(TradeOrderDO::getReceiverName, reqVO.getReceiverName())
|
|
||||||
.likeIfPresent(TradeOrderDO::getReceiverMobile, reqVO.getReceiverMobile())
|
|
||||||
.eqIfPresent(TradeOrderDO::getType, reqVO.getType())
|
.eqIfPresent(TradeOrderDO::getType, reqVO.getType())
|
||||||
.eqIfPresent(TradeOrderDO::getStatus, reqVO.getStatus())
|
.eqIfPresent(TradeOrderDO::getStatus, reqVO.getStatus())
|
||||||
.eqIfPresent(TradeOrderDO::getPayChannelCode, reqVO.getPayChannelCode())
|
.eqIfPresent(TradeOrderDO::getPayChannelCode, reqVO.getPayChannelCode())
|
||||||
.eqIfPresent(TradeOrderDO::getTerminal,reqVO.getTerminal())
|
.eqIfPresent(TradeOrderDO::getTerminal, reqVO.getTerminal())
|
||||||
.eqIfPresent(TradeOrderDO::getLogisticsId, reqVO.getLogisticsId())
|
.eqIfPresent(TradeOrderDO::getLogisticsId, reqVO.getLogisticsId())
|
||||||
.inIfPresent(TradeOrderDO::getPickUpStoreId, reqVO.getPickUpStoreIds())
|
.inIfPresent(TradeOrderDO::getPickUpStoreId, reqVO.getPickUpStoreIds())
|
||||||
.betweenIfPresent(TradeOrderDO::getCreateTime, reqVO.getCreateTime()));
|
.betweenIfPresent(TradeOrderDO::getCreateTime, reqVO.getCreateTime()));
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.framework.order.core.annotations;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||||
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交易订单的操作日志 AOP 注解
|
||||||
|
*
|
||||||
|
* @author 陈賝
|
||||||
|
* @since 2023/7/6 15:37
|
||||||
|
*/
|
||||||
|
@Target({METHOD, ANNOTATION_TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface TradeOrderLog {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作类型
|
||||||
|
*/
|
||||||
|
TradeOrderOperateTypeEnum operateType();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.framework.order.core.aop;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
|
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO;
|
||||||
|
import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.TradeOrderLogService;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.logger.TradeOrderLogCreateReqBO;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
|
import static java.util.Collections.emptyMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交易订单的操作日志的记录 AOP 切面
|
||||||
|
*
|
||||||
|
* @author 陈賝
|
||||||
|
* @since 2023/6/13 13:54
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Aspect
|
||||||
|
@Slf4j
|
||||||
|
public class TradeOrderLogAspect {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单编号
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Long> ORDER_ID = new ThreadLocal<>();
|
||||||
|
/**
|
||||||
|
* 操作前的状态
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Integer> BEFORE_STATUS = new ThreadLocal<>();
|
||||||
|
/**
|
||||||
|
* 操作后的状态
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Integer> AFTER_STATUS = new ThreadLocal<>();
|
||||||
|
/**
|
||||||
|
* 拓展参数 Map,用于格式化操作内容
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Map<String, Object>> EXTS = new ThreadLocal<>();
|
||||||
|
|
||||||
|
public TradeOrderLogAspect() {
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TradeOrderLogService orderLogService;
|
||||||
|
|
||||||
|
@AfterReturning("@annotation(orderLog)")
|
||||||
|
public void doAfterReturning(JoinPoint joinPoint, TradeOrderLog orderLog) {
|
||||||
|
try {
|
||||||
|
// 1.1 操作用户
|
||||||
|
Integer userType = getUserType();
|
||||||
|
Long userId = getUserId();
|
||||||
|
// 1.2 订单信息
|
||||||
|
Long orderId = ORDER_ID.get();
|
||||||
|
Integer beforeStatus = BEFORE_STATUS.get();
|
||||||
|
Integer afterStatus = AFTER_STATUS.get();
|
||||||
|
Map<String, Object> exts = ObjectUtil.defaultIfNull(EXTS.get(), emptyMap());
|
||||||
|
String content = StrUtil.format(orderLog.operateType().getContent(), exts);
|
||||||
|
|
||||||
|
// 2.1 记录日志
|
||||||
|
TradeOrderLogCreateReqBO createBO = new TradeOrderLogCreateReqBO()
|
||||||
|
.setUserId(userId).setUserType(userType)
|
||||||
|
.setOrderId(orderId).setBeforeStatus(beforeStatus).setAfterStatus(afterStatus)
|
||||||
|
.setOperateType(orderLog.operateType().getType()).setContent(content);
|
||||||
|
orderLogService.createOrderLog(createBO);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// todo 芋艿:清理上下文
|
||||||
|
log.error("[doAfterReturning][orderLog({}) 订单日志错误]", toJsonString(orderLog), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得用户类型
|
||||||
|
*
|
||||||
|
* 如果没有,则约定为 {@link TradeOrderLogDO#getUserType()} 系统
|
||||||
|
*
|
||||||
|
* @return 用户类型
|
||||||
|
*/
|
||||||
|
private static Integer getUserType() {
|
||||||
|
return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserType(), TradeOrderLogDO.USER_TYPE_SYSTEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得用户编号
|
||||||
|
*
|
||||||
|
* 如果没有,则约定为 {@link TradeOrderLogDO#getUserId()} 系统
|
||||||
|
*
|
||||||
|
* @return 用户类型
|
||||||
|
*/
|
||||||
|
private static Long getUserId() {
|
||||||
|
return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserId(), TradeOrderLogDO.USER_ID_SYSTEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus, Map<String, Object> exts) {
|
||||||
|
ORDER_ID.set(id);
|
||||||
|
BEFORE_STATUS.set(beforeStatus);
|
||||||
|
AFTER_STATUS.set(afterStatus);
|
||||||
|
EXTS.set(exts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.framework.order.core.utils;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.trade.framework.order.core.aop.TradeOrderLogAspect;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交易订单的操作日志 Utils
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class TradeOrderLogUtils {
|
||||||
|
|
||||||
|
public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus) {
|
||||||
|
TradeOrderLogAspect.setOrderInfo(id, beforeStatus, afterStatus, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus,
|
||||||
|
Map<String, Object> exts) {
|
||||||
|
TradeOrderLogAspect.setOrderInfo(id, beforeStatus, afterStatus, exts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,6 +5,7 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,6 +31,7 @@ public class BrokerageAddReqBO {
|
|||||||
/**
|
/**
|
||||||
* 一级佣金(固定)
|
* 一级佣金(固定)
|
||||||
*/
|
*/
|
||||||
|
@NotNull(message = "一级佣金(固定)不能为空")
|
||||||
private Integer firstFixedPrice;
|
private Integer firstFixedPrice;
|
||||||
/**
|
/**
|
||||||
* 二级佣金(固定)
|
* 二级佣金(固定)
|
||||||
@ -39,10 +41,13 @@ public class BrokerageAddReqBO {
|
|||||||
/**
|
/**
|
||||||
* 来源用户编号
|
* 来源用户编号
|
||||||
*/
|
*/
|
||||||
|
@NotNull(message = "来源用户编号不能为空")
|
||||||
private Long sourceUserId;
|
private Long sourceUserId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 佣金记录标题
|
* 佣金记录标题
|
||||||
*/
|
*/
|
||||||
|
@NotEmpty(message = "佣金记录标题不能为空")
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.brokerage.record;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.BooleanUtil;
|
import cn.hutool.core.util.BooleanUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
|
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
|
||||||
@ -154,21 +155,24 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
|
|||||||
int totalBrokerage = 0;
|
int totalBrokerage = 0;
|
||||||
List<BrokerageRecordDO> records = new ArrayList<>();
|
List<BrokerageRecordDO> records = new ArrayList<>();
|
||||||
for (BrokerageAddReqBO item : list) {
|
for (BrokerageAddReqBO item : list) {
|
||||||
Integer fixedPrice = 0;
|
// 计算金额
|
||||||
|
Integer fixedPrice;
|
||||||
if (BrokerageUserTypeEnum.FIRST.equals(sourceUserType)) {
|
if (BrokerageUserTypeEnum.FIRST.equals(sourceUserType)) {
|
||||||
fixedPrice = item.getFirstFixedPrice();
|
fixedPrice = item.getFirstFixedPrice();
|
||||||
} else if (BrokerageUserTypeEnum.SECOND.equals(sourceUserType)) {
|
} else if (BrokerageUserTypeEnum.SECOND.equals(sourceUserType)) {
|
||||||
fixedPrice = item.getSecondFixedPrice();
|
fixedPrice = item.getSecondFixedPrice();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(StrUtil.format("来源用户({}) 不合法", sourceUserType));
|
||||||
}
|
}
|
||||||
|
int brokeragePrice = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice);
|
||||||
int brokeragePerItem = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice);
|
if (brokeragePrice <= 0) {
|
||||||
if (brokeragePerItem <= 0) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
totalBrokerage += brokeragePrice;
|
||||||
|
// 创建记录实体
|
||||||
records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(),
|
records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(),
|
||||||
brokerageFrozenDays, brokeragePerItem, unfreezeTime, item.getTitle(),
|
brokerageFrozenDays, brokeragePrice, unfreezeTime, item.getTitle(),
|
||||||
item.getSourceUserId(), sourceUserType.getType()));
|
item.getSourceUserId(), sourceUserType.getType()));
|
||||||
totalBrokerage += brokeragePerItem;
|
|
||||||
}
|
}
|
||||||
if (CollUtil.isEmpty(records)) {
|
if (CollUtil.isEmpty(records)) {
|
||||||
return;
|
return;
|
||||||
|
@ -134,7 +134,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
|
|||||||
@Override
|
@Override
|
||||||
public Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType) {
|
public Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType) {
|
||||||
switch (userType) {
|
switch (userType) {
|
||||||
case ALL:
|
case ALL: // TODO @疯狂:ALL 是不是不用搞个枚举,默认为空就是不过滤哈~
|
||||||
Long firstCount = brokerageUserMapper.selectCountByBindUserId(bindUserId);
|
Long firstCount = brokerageUserMapper.selectCountByBindUserId(bindUserId);
|
||||||
Long secondCount = brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId);
|
Long secondCount = brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId);
|
||||||
return firstCount + secondCount;
|
return firstCount + secondCount;
|
||||||
@ -183,7 +183,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
|
|||||||
public Boolean getUserBrokerageEnabled(Long userId) {
|
public Boolean getUserBrokerageEnabled(Long userId) {
|
||||||
// 全局分销功能是否开启
|
// 全局分销功能是否开启
|
||||||
TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();
|
TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();
|
||||||
if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) {
|
if (tradeConfig == null || BooleanUtil.isFalse(tradeConfig.getBrokerageEnabled())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.service.order;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.logger.TradeOrderLogCreateReqBO;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交易下单日志 Service 接口
|
||||||
|
*
|
||||||
|
* @author 陈賝
|
||||||
|
* @since 2023/7/6 15:44
|
||||||
|
*/
|
||||||
|
public interface TradeOrderLogService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建交易下单日志
|
||||||
|
*
|
||||||
|
* @param logDTO 日志记录
|
||||||
|
* @author 陈賝
|
||||||
|
* @since 2023/7/6 15:45
|
||||||
|
*/
|
||||||
|
@Async
|
||||||
|
void createOrderLog(TradeOrderLogCreateReqBO logDTO);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.service.order;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.logger.TradeOrderLogCreateReqBO;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交易下单日志 Service 实现类
|
||||||
|
*
|
||||||
|
* @author 陈賝
|
||||||
|
* @since 2023/7/6 15:44
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class TradeOrderLogServiceImpl implements TradeOrderLogService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createOrderLog(TradeOrderLogCreateReqBO createReqBO) {
|
||||||
|
// TODO 芋艿:存储还没搞
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -119,4 +119,13 @@ public interface TradeOrderQueryService {
|
|||||||
*/
|
*/
|
||||||
List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds);
|
List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取订单项商品购买数量总和
|
||||||
|
*
|
||||||
|
* @param orderIds 订单编号
|
||||||
|
* @param skuIds sku 编号
|
||||||
|
* @return 订单项商品购买数量总和
|
||||||
|
*/
|
||||||
|
Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
|
|||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
|
||||||
@ -167,4 +168,10 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
|
|||||||
return tradeOrderItemMapper.selectListByOrderId(orderIds);
|
return tradeOrderItemMapper.selectListByOrderId(orderIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
|
||||||
|
List<TradeOrderItemDO> tradeOrderItems = tradeOrderItemMapper.selectListByOrderIdAnSkuId(orderIds, skuIds);
|
||||||
|
return CollectionUtils.getSumValue(tradeOrderItems, TradeOrderItemDO::getCount, Integer::sum);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,11 @@ import cn.hutool.core.util.StrUtil;
|
|||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
|
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.module.member.api.address.AddressApi;
|
import cn.iocoder.yudao.module.member.api.address.AddressApi;
|
||||||
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
|
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
|
||||||
import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
|
import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
|
||||||
import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
|
import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
|
||||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
|
||||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
|
||||||
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
|
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
|
||||||
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
|
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
|
||||||
import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
|
import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
|
||||||
@ -24,15 +21,10 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
|||||||
import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
|
import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
|
||||||
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
|
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
||||||
import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
|
|
||||||
import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
|
import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
|
||||||
import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
|
import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
|
||||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
|
|
||||||
import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
|
import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
|
||||||
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
|
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
|
||||||
import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
|
|
||||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
|
|
||||||
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO;
|
||||||
@ -53,12 +45,14 @@ import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
|
|||||||
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
|
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.*;
|
import cn.iocoder.yudao.module.trade.enums.order.*;
|
||||||
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
||||||
import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
|
|
||||||
import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
|
import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
|
||||||
import cn.iocoder.yudao.module.trade.service.cart.CartService;
|
import cn.iocoder.yudao.module.trade.service.cart.CartService;
|
||||||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
||||||
import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
|
import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
|
||||||
import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO;
|
import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler;
|
||||||
import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
|
import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
|
||||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||||
@ -70,14 +64,13 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
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.*;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_EQUAL;
|
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID;
|
|
||||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,6 +90,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||||||
@Resource
|
@Resource
|
||||||
private TradeOrderNoRedisDAO orderNoRedisDAO;
|
private TradeOrderNoRedisDAO orderNoRedisDAO;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private List<TradeOrderHandler> tradeOrderHandlers;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CartService cartService;
|
private CartService cartService;
|
||||||
@Resource
|
@Resource
|
||||||
@ -119,12 +115,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||||||
@Resource
|
@Resource
|
||||||
private BargainRecordApi bargainRecordApi;
|
private BargainRecordApi bargainRecordApi;
|
||||||
@Resource
|
@Resource
|
||||||
private SeckillActivityApi seckillActivityApi;
|
|
||||||
@Resource
|
|
||||||
private BargainActivityApi bargainActivityApi;
|
|
||||||
@Resource
|
|
||||||
private MemberUserApi memberUserApi;
|
|
||||||
@Resource
|
|
||||||
private MemberLevelApi memberLevelApi;
|
private MemberLevelApi memberLevelApi;
|
||||||
@Resource
|
@Resource
|
||||||
private MemberPointApi memberPointApi;
|
private MemberPointApi memberPointApi;
|
||||||
@ -189,7 +179,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
|
public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
|
||||||
// 1. 价格计算
|
// 1、执行订单创建前置处理器
|
||||||
|
// TODO @puhui999:最好也抽个 beforeOrderCreate 方法;
|
||||||
|
TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
|
||||||
|
beforeOrderCreateReqBO.setOrderType(validateActivity(createReqVO));
|
||||||
|
beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
|
||||||
|
// TODO @puhui999:这里有个纠结点;handler 的定义是只处理指定类型的订单的拓展逻辑;还是通用的 handler,类似可以处理优惠劵等等
|
||||||
|
tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
|
||||||
|
|
||||||
|
// 2. 价格计算
|
||||||
TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
|
TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
|
||||||
|
|
||||||
// 2.1 插入 TradeOrderDO 订单
|
// 2.1 插入 TradeOrderDO 订单
|
||||||
@ -199,37 +197,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||||||
|
|
||||||
// 3. 订单创建完后的逻辑
|
// 3. 订单创建完后的逻辑
|
||||||
afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
|
afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
|
||||||
// 3.1 拼团的特殊逻辑
|
|
||||||
// TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去
|
|
||||||
// 拼团
|
|
||||||
if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
|
|
||||||
createCombinationRecord(userId, createReqVO, orderItems, order);
|
|
||||||
}
|
|
||||||
// 3.2 秒杀的特殊逻辑
|
|
||||||
if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
|
|
||||||
|
|
||||||
}
|
|
||||||
// 3.3 砍价的特殊逻辑
|
|
||||||
|
|
||||||
// TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
|
// TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) {
|
|
||||||
MemberUserRespDTO user = memberUserApi.getUser(userId);
|
|
||||||
List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
|
|
||||||
// TODO 拼团一次应该只能选择一种规格的商品
|
|
||||||
TradeOrderItemDO orderItemDO = orderItems.get(0);
|
|
||||||
if (CollUtil.isNotEmpty(recordRespDTOS)) {
|
|
||||||
List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
|
|
||||||
List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
|
|
||||||
CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
|
|
||||||
combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
|
|
||||||
CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO @puhui999:订单超时,自动取消;
|
// TODO @puhui999:订单超时,自动取消;
|
||||||
|
|
||||||
@ -311,23 +283,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||||||
private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
|
private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
|
||||||
TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
|
TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
|
||||||
TradePriceCalculateRespBO calculateRespBO) {
|
TradePriceCalculateRespBO calculateRespBO) {
|
||||||
Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum);
|
// 执行订单创建后置处理器
|
||||||
// 1)如果是秒杀商品:额外扣减秒杀的库存;
|
tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, tradeOrderDO, orderItems.get(0))));
|
||||||
if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) {
|
|
||||||
SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO();
|
|
||||||
updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId());
|
|
||||||
updateStockReqDTO.setCount(count);
|
|
||||||
updateStockReqDTO.setItems(CollectionUtils.convertList(orderItems, item -> {
|
|
||||||
SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item();
|
|
||||||
item1.setSpuId(item.getSpuId());
|
|
||||||
item1.setSkuId(item.getSkuId());
|
|
||||||
item1.setCount(item.getCount());
|
|
||||||
return item1;
|
|
||||||
}));
|
|
||||||
seckillActivityApi.updateSeckillStock(updateStockReqDTO);
|
|
||||||
}
|
|
||||||
// 2)如果是砍价活动:额外扣减砍价的库存;
|
|
||||||
bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count);
|
|
||||||
// 扣减积分 TODO 芋艿:待实现,需要前置;
|
// 扣减积分 TODO 芋艿:待实现,需要前置;
|
||||||
// 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
|
// 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
|
||||||
|
|
||||||
@ -352,6 +310,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||||||
// 增加订单日志 TODO 芋艿:待实现
|
// 增加订单日志 TODO 芋艿:待实现
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) {
|
private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) {
|
||||||
// 创建支付单,用于后续的支付
|
// 创建支付单,用于后续的支付
|
||||||
PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
|
PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
|
||||||
@ -562,35 +521,68 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
// TODO @puhui999:考虑事务性
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) {
|
public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) {
|
||||||
// 校验交易订单
|
// 1、校验交易订单
|
||||||
TradeOrderDO order = validateOrderExists(reqVO.getId());
|
TradeOrderDO order = validateOrderExists(reqVO.getId());
|
||||||
if (order.getPayStatus()) {
|
if (order.getPayStatus()) {
|
||||||
throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
|
throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
|
||||||
}
|
}
|
||||||
|
// 2、校验订单项
|
||||||
|
List<TradeOrderItemDO> items = tradeOrderItemMapper.selectListByOrderId(order.getId());
|
||||||
|
if (CollUtil.isEmpty(items)) {
|
||||||
|
throw exception(ORDER_UPDATE_PRICE_FAIL_NOT_ITEM);
|
||||||
|
}
|
||||||
|
// 3、校验调价金额是否变化
|
||||||
if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) {
|
if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) {
|
||||||
throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL);
|
throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的
|
// 4、更新订单
|
||||||
List<TradeOrderItemDO> itemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId());
|
TradeOrderDO update = new TradeOrderDO();
|
||||||
// TradeOrderItemDO 需要做 adjustPrice 的分摊
|
update.setId(order.getId());
|
||||||
int price = reqVO.getAdjustPrice() / itemDOs.size();
|
update.setAdjustPrice(reqVO.getAdjustPrice());
|
||||||
itemDOs.forEach(item -> {
|
int orderPayPrice = order.getAdjustPrice() != null ? (order.getPayPrice() - order.getAdjustPrice())
|
||||||
item.setAdjustPrice(price);
|
+ reqVO.getAdjustPrice() : order.getPayPrice() + reqVO.getAdjustPrice();
|
||||||
});
|
update.setPayPrice(orderPayPrice);
|
||||||
// 更新 TradeOrderItem
|
|
||||||
// TODO @puhui999:不要整个对象去更新哈;应该 new 一下;
|
|
||||||
tradeOrderItemMapper.updateBatch(itemDOs);
|
|
||||||
// 更新订单
|
|
||||||
// TODO @puhui999:要考虑多次修改价格,不能单单的 payPrice + 价格;
|
|
||||||
TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO);
|
|
||||||
update.setPayPrice(update.getPayPrice() + update.getAdjustPrice());
|
|
||||||
// TODO @芋艿:改价时,赠送的积分,要不要做改动???
|
|
||||||
tradeOrderMapper.updateById(update);
|
tradeOrderMapper.updateById(update);
|
||||||
// 更新支付订单
|
// TODO @芋艿:改价时,赠送的积分,要不要做改动???
|
||||||
payOrderApi.updatePayOrderPriceById(order.getPayOrderId(), update.getPayPrice());
|
|
||||||
|
// TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的
|
||||||
|
// TODO:先按 adjustPrice 实现,没明白 payPrice 怎么搞哈哈哈
|
||||||
|
// TODO @puhui999:就是对比新老 adjustPrice 的差值,然后计算补充的 adjustPrice 最终值;另外,可以不用区分 items.size 是不是 > 1 哈;应该是一致的逻辑;分摊的逻辑,有点类似 dividePrice 方法噢;
|
||||||
|
// 5、更新 TradeOrderItem
|
||||||
|
if (items.size() > 1) {
|
||||||
|
// TradeOrderItemDO 需要做 adjustPrice 的分摊
|
||||||
|
int price = reqVO.getAdjustPrice() / items.size();
|
||||||
|
int remainderPrice = reqVO.getAdjustPrice() % items.size();
|
||||||
|
List<TradeOrderItemDO> orders = new ArrayList<>();
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
// 把平摊后剩余的金额加到第一个订单项
|
||||||
|
if (remainderPrice != 0 && i == 0) {
|
||||||
|
orders.add(convertOrderItemPrice(items.get(i), price + remainderPrice));
|
||||||
|
}
|
||||||
|
orders.add(convertOrderItemPrice(items.get(i), price));
|
||||||
|
}
|
||||||
|
tradeOrderItemMapper.updateBatch(orders);
|
||||||
|
} else {
|
||||||
|
TradeOrderItemDO orderItem = items.get(0);
|
||||||
|
TradeOrderItemDO updateItem = convertOrderItemPrice(orderItem, reqVO.getAdjustPrice());
|
||||||
|
tradeOrderItemMapper.updateById(updateItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6、更新支付订单
|
||||||
|
payOrderApi.updatePayOrderPrice(order.getPayOrderId(), update.getPayPrice());
|
||||||
|
}
|
||||||
|
|
||||||
|
private TradeOrderItemDO convertOrderItemPrice(TradeOrderItemDO orderItem, Integer price) {
|
||||||
|
TradeOrderItemDO newOrderItem = new TradeOrderItemDO();
|
||||||
|
newOrderItem.setId(orderItem.getId());
|
||||||
|
newOrderItem.setAdjustPrice(price);
|
||||||
|
int payPrice = orderItem.getAdjustPrice() != null ? (orderItem.getPayPrice() - orderItem.getAdjustPrice())
|
||||||
|
+ price : orderItem.getPayPrice() + price;
|
||||||
|
newOrderItem.setPayPrice(payPrice);
|
||||||
|
return newOrderItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -733,6 +725,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||||||
throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
|
throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来
|
||||||
|
tradeOrderHandlers.forEach(handler -> handler.rollbackStock());
|
||||||
|
|
||||||
// 2.回滚库存
|
// 2.回滚库存
|
||||||
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
|
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
|
||||||
productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));
|
productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.service.order.bo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
// TODO 芋艿:在想想这些参数的定义
|
||||||
|
/**
|
||||||
|
* 订单创建之后 Request BO
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TradeAfterOrderCreateReqBO {
|
||||||
|
|
||||||
|
// ========== 拼团活动相关字段 ==========
|
||||||
|
|
||||||
|
@Schema(description = "拼团活动编号", example = "1024")
|
||||||
|
private Long combinationActivityId;
|
||||||
|
|
||||||
|
@Schema(description = "拼团团长编号", example = "2048")
|
||||||
|
private Long combinationHeadId;
|
||||||
|
|
||||||
|
@NotNull(message = "SPU 编号不能为空")
|
||||||
|
private Long spuId;
|
||||||
|
|
||||||
|
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||||
|
private Long skuId;
|
||||||
|
|
||||||
|
@NotNull(message = "订单编号不能为空")
|
||||||
|
private Long orderId;
|
||||||
|
|
||||||
|
@NotNull(message = "用户编号不能为空")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@NotNull(message = "支付金额不能为空")
|
||||||
|
private Integer payPrice;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.service.order.bo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
// TODO 芋艿:在想想这些参数的定义
|
||||||
|
/**
|
||||||
|
* 订单创建之前 Request BO
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TradeBeforeOrderCreateReqBO {
|
||||||
|
|
||||||
|
@NotNull(message = "订单类型不能为空")
|
||||||
|
private Integer orderType;
|
||||||
|
|
||||||
|
// ========== 秒杀活动相关字段 ==========
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动编号", example = "1024")
|
||||||
|
private Long seckillActivityId;
|
||||||
|
|
||||||
|
// ========== 拼团活动相关字段 ==========
|
||||||
|
|
||||||
|
@Schema(description = "拼团活动编号", example = "1024")
|
||||||
|
private Long combinationActivityId;
|
||||||
|
|
||||||
|
@Schema(description = "拼团团长编号", example = "2048")
|
||||||
|
private Long combinationHeadId;
|
||||||
|
|
||||||
|
@Schema(description = "砍价活动编号", example = "123")
|
||||||
|
private Long bargainActivityId;
|
||||||
|
|
||||||
|
@NotNull(message = "购买数量不能为空")
|
||||||
|
private Integer count;
|
||||||
|
|
||||||
|
@NotNull(message = "活动商品不能为空")
|
||||||
|
private Item item;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Valid
|
||||||
|
public static class Item {
|
||||||
|
|
||||||
|
@NotNull(message = "SPU 编号不能为空")
|
||||||
|
private Long spuId;
|
||||||
|
|
||||||
|
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||||
|
private Long skuId;
|
||||||
|
|
||||||
|
@NotNull(message = "购买数量不能为空")
|
||||||
|
private Integer count;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.service.order.bo.logger;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单日志的创建 Request BO
|
||||||
|
*
|
||||||
|
* @author 陈賝
|
||||||
|
* @since 2023/7/6 15:27
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TradeOrderLogCreateReqBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
@NotNull(message = "用户编号不能为空")
|
||||||
|
private Long userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "用户类型不能为空")
|
||||||
|
private Integer userType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单编号
|
||||||
|
*/
|
||||||
|
@NotNull(message = "订单编号")
|
||||||
|
private Long orderId;
|
||||||
|
/**
|
||||||
|
* 操作前状态
|
||||||
|
*/
|
||||||
|
private Integer beforeStatus;
|
||||||
|
/**
|
||||||
|
* 操作后状态
|
||||||
|
*/
|
||||||
|
@NotNull(message = "操作后的状态不能为空")
|
||||||
|
private Integer afterStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作类型
|
||||||
|
*/
|
||||||
|
private Integer operateType;
|
||||||
|
/**
|
||||||
|
* 操作明细
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.service.order.handler;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
|
||||||
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 砍价订单 handler 实现类
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class TradeBargainHandler implements TradeOrderHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BargainActivityApi bargainActivityApi;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
|
||||||
|
// 如果是秒杀订单
|
||||||
|
if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 额外扣减砍价的库存
|
||||||
|
bargainActivityApi.updateBargainActivityStock(reqBO.getBargainActivityId(), reqBO.getCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rollbackStock() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.service.order.handler;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.combination.CombinationApi;
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
|
||||||
|
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
|
||||||
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拼团订单 handler 接口实现类
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class TradeCombinationHandler implements TradeOrderHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CombinationApi combinationApi;
|
||||||
|
@Resource
|
||||||
|
private CombinationRecordApi combinationRecordApi;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
|
||||||
|
// 如果是拼团订单;
|
||||||
|
if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), reqBO.getOrderType())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验是否满足拼团活动相关限制
|
||||||
|
combinationApi.validateCombination(TradeOrderConvert.INSTANCE.convert1(reqBO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
|
||||||
|
// 创建砍价记录
|
||||||
|
combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(reqBO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rollbackStock() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.service.order.handler;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单活动特殊逻辑处理器 handler 接口
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
public interface TradeOrderHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单创建前
|
||||||
|
*
|
||||||
|
* @param reqBO 请求
|
||||||
|
*/
|
||||||
|
void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单创建后
|
||||||
|
*
|
||||||
|
* @param reqBO 请求
|
||||||
|
*/
|
||||||
|
void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回滚活动相关库存
|
||||||
|
*/
|
||||||
|
void rollbackStock();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.service.order.handler;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
|
||||||
|
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
|
||||||
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
|
||||||
|
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 秒杀订单 handler 实现类
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class TradeSeckillHandler implements TradeOrderHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SeckillActivityApi seckillActivityApi;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
|
||||||
|
// 如果是秒杀订单:额外扣减秒杀的库存;
|
||||||
|
if (ObjectUtil.notEqual(TradeOrderTypeEnum.SECKILL.getType(), reqBO.getOrderType())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
seckillActivityApi.updateSeckillStock(TradeOrderConvert.INSTANCE.convert(reqBO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rollbackStock() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -29,13 +29,12 @@ public interface PayOrderApi {
|
|||||||
*/
|
*/
|
||||||
PayOrderRespDTO getOrder(Long id);
|
PayOrderRespDTO getOrder(Long id);
|
||||||
|
|
||||||
// TODO @puhui999:可以去掉 byId;然后 payOrderId 参数改成 id;
|
|
||||||
/**
|
/**
|
||||||
* 更新支付订单价格
|
* 更新支付订单价格
|
||||||
*
|
*
|
||||||
* @param payOrderId 支付单编号
|
* @param id 支付单编号
|
||||||
* @param payPrice 支付单价格
|
* @param payPrice 支付单价格
|
||||||
*/
|
*/
|
||||||
void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
|
void updatePayOrderPrice(Long id, Integer payPrice);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,19 +21,17 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001004, "已存在相同的渠道");
|
ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001004, "已存在相同的渠道");
|
||||||
|
|
||||||
// ========== ORDER 模块 1007002000 ==========
|
// ========== ORDER 模块 1007002000 ==========
|
||||||
ErrorCode ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
|
ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
|
||||||
ErrorCode ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
|
ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
|
||||||
ErrorCode ORDER_STATUS_IS_SUCCESS = new ErrorCode(1007002002, "订单已支付,请刷新页面");
|
ErrorCode PAY_ORDER_STATUS_IS_SUCCESS = new ErrorCode(1007002002, "订单已支付,请刷新页面");
|
||||||
ErrorCode ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
|
ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
|
||||||
ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
|
ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
|
||||||
ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
|
ErrorCode PAY_ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
|
||||||
ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1007002006, "支付订单调价失败,原因:支付订单已付款,不能调价");
|
|
||||||
ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1007002007, "支付订单调价失败,原因:价格没有变化");
|
|
||||||
|
|
||||||
// ========== ORDER 模块(拓展单) 1007003000 ==========
|
// ========== ORDER 模块(拓展单) 1007003000 ==========
|
||||||
ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
|
ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
|
||||||
ErrorCode ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
|
ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
|
||||||
ErrorCode ORDER_EXTENSION_IS_PAID = new ErrorCode(1007003002, "订单已支付,请等待支付结果");
|
ErrorCode PAY_ORDER_EXTENSION_IS_PAID = new ErrorCode(1007003002, "订单已支付,请等待支付结果");
|
||||||
|
|
||||||
// ========== 支付模块(退款) 1007006000 ==========
|
// ========== 支付模块(退款) 1007006000 ==========
|
||||||
ErrorCode REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
|
ErrorCode REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
|
||||||
@ -48,6 +46,11 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode WALLET_TRANSACTION_NOT_FOUND = new ErrorCode(1007007002, "未找到对应的钱包交易");
|
ErrorCode WALLET_TRANSACTION_NOT_FOUND = new ErrorCode(1007007002, "未找到对应的钱包交易");
|
||||||
ErrorCode WALLET_REFUND_AMOUNT_ERROR = new ErrorCode(1007007003, "钱包退款金额不对");
|
ErrorCode WALLET_REFUND_AMOUNT_ERROR = new ErrorCode(1007007003, "钱包退款金额不对");
|
||||||
ErrorCode WALLET_REFUND_EXIST = new ErrorCode(1007007004, "已经存在钱包退款");
|
ErrorCode WALLET_REFUND_EXIST = new ErrorCode(1007007004, "已经存在钱包退款");
|
||||||
|
ErrorCode WALLET_RECHARGE_NOT_FOUND = new ErrorCode(1007007005, "钱包充值记录不存在");
|
||||||
|
ErrorCode WALLET_RECHARGE_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007007006, "钱包充值更新支付状态失败,钱包充值记录不是【未支付】状态");
|
||||||
|
ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_ID_ERROR = new ErrorCode(1007007007, "钱包充值更新支付状态失败,支付单编号不匹配");
|
||||||
|
ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007007008, "钱包充值更新支付状态失败,支付单状态不是【支付成功】状态");
|
||||||
|
ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_PRICE_NOT_MATCH = new ErrorCode(1007007009, "钱包充值更新支付状态失败,支付单金额不匹配");
|
||||||
|
|
||||||
// ========== 示例订单 1007900000 ==========
|
// ========== 示例订单 1007900000 ==========
|
||||||
ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
|
ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
|
||||||
|
@ -32,8 +32,8 @@ public class PayOrderApiImpl implements PayOrderApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
|
public void updatePayOrderPrice(Long id, Integer payPrice) {
|
||||||
payOrderService.updatePayOrderPriceById(payOrderId, payPrice);
|
payOrderService.updatePayOrderPrice(id, payPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.controller.app.wallet;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
|
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateRespVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargeConvert;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.service.wallet.PayWalletRechargeService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
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 javax.annotation.Resource;
|
||||||
|
import javax.annotation.security.PermitAll;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||||
|
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType;
|
||||||
|
|
||||||
|
@Tag(name = "用户 APP - 钱包充值")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pay/wallet-recharge")
|
||||||
|
@Validated
|
||||||
|
@Slf4j
|
||||||
|
public class AppPayWalletRechargeController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PayWalletRechargeService payWalletRechargeService;
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
@Operation(summary = "创建钱包充值记录")
|
||||||
|
public CommonResult<AppPayWalletRechargeCreateRespVO> createWalletRecharge(@Valid @RequestBody AppPayWalletRechargeCreateReqVO reqVO) {
|
||||||
|
PayWalletRechargeDO walletRecharge = payWalletRechargeService.createWalletRecharge(getLoginUserId(),
|
||||||
|
getLoginUserType(), reqVO);
|
||||||
|
return success(PayWalletRechargeConvert.INSTANCE.convert(walletRecharge));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/update-paid")
|
||||||
|
@Operation(summary = "更新钱包充值为已充值") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob
|
||||||
|
@PermitAll // 无需登录,安全由 内部校验实现
|
||||||
|
@OperateLog(enable = false) // 禁用操作日志,因为没有操作人
|
||||||
|
public CommonResult<Boolean> updateWalletRechargerPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
|
||||||
|
payWalletRechargeService.updateWalletRechargerPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
|
||||||
|
notifyReqDTO.getPayOrderId());
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,6 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.DecimalMin;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Schema(description = "用户 APP - 创建钱包充值 Request VO")
|
||||||
|
@Data
|
||||||
|
public class AppPayWalletRechargeCreateReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
|
||||||
|
@NotNull(message = "支付金额不能为空")
|
||||||
|
@DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零")
|
||||||
|
private Integer payPrice;
|
||||||
|
|
||||||
|
@Schema(description = "钱包赠送金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
|
||||||
|
@NotNull(message = "钱包赠送金额不能为空")
|
||||||
|
@DecimalMin(value = "0", message = "钱包赠送金额必须大于等于零")
|
||||||
|
private Integer walletBonus;
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "用户 APP - 创建钱包充值 Resp VO")
|
||||||
|
@Data
|
||||||
|
public class AppPayWalletRechargeCreateRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "钱包充值编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||||
|
private Long payOrderId;
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.convert.wallet;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateRespVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface PayWalletRechargeConvert {
|
||||||
|
|
||||||
|
PayWalletRechargeConvert INSTANCE = Mappers.getMapper(PayWalletRechargeConvert.class);
|
||||||
|
|
||||||
|
PayWalletRechargeDO convert(AppPayWalletRechargeCreateReqVO vo);
|
||||||
|
|
||||||
|
default PayWalletRechargeDO convert(Long walletId, AppPayWalletRechargeCreateReqVO vo) {
|
||||||
|
PayWalletRechargeDO walletRecharge = convert(vo);
|
||||||
|
return walletRecharge.setWalletId(walletId)
|
||||||
|
.setPrice(walletRecharge.getPayPrice() + walletRecharge.getWalletBonus());
|
||||||
|
}
|
||||||
|
|
||||||
|
AppPayWalletRechargeCreateRespVO convert(PayWalletRechargeDO bean);
|
||||||
|
|
||||||
|
}
|
@ -42,6 +42,19 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> {
|
|||||||
.ge(PayWalletDO::getBalance, price); // cas 逻辑
|
.ge(PayWalletDO::getBalance, price); // cas 逻辑
|
||||||
return update(null, lambdaUpdateWrapper);
|
return update(null, lambdaUpdateWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当充值的时候,更新钱包
|
||||||
|
* @param price 钱包金额
|
||||||
|
* @param id 钱包 id
|
||||||
|
*/
|
||||||
|
default int updateWhenRecharge(Integer price, Long id){
|
||||||
|
LambdaUpdateWrapper<PayWalletDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<PayWalletDO>()
|
||||||
|
.setSql(" balance = balance + " + price
|
||||||
|
+ ", total_recharge = total_recharge + " + price)
|
||||||
|
.eq(PayWalletDO::getId, id);
|
||||||
|
return update(null, lambdaUpdateWrapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
|
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_EXTENSION_NOT_FOUND;
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_EXTENSION_NOT_FOUND;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FOUND;
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FOUND;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,8 +98,8 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
|
|||||||
PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
|
PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
|
||||||
// 支付交易拓展单不存在, 返回关闭状态
|
// 支付交易拓展单不存在, 返回关闭状态
|
||||||
if (orderExtension == null) {
|
if (orderExtension == null) {
|
||||||
return PayOrderRespDTO.closedOf(String.valueOf(ORDER_EXTENSION_NOT_FOUND.getCode()),
|
return PayOrderRespDTO.closedOf(String.valueOf(PAY_ORDER_EXTENSION_NOT_FOUND.getCode()),
|
||||||
ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, "");
|
PAY_ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, "");
|
||||||
}
|
}
|
||||||
// 关闭状态
|
// 关闭状态
|
||||||
if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) {
|
if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) {
|
||||||
|
@ -25,7 +25,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static cn.hutool.core.util.ObjectUtil.*;
|
import static cn.hutool.core.util.ObjectUtil.notEqual;
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
|
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
|
||||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
@ -156,7 +156,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
|
|||||||
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
|
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
|
||||||
if (payOrder == null) {
|
if (payOrder == null) {
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
|
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
|
||||||
throw exception(ORDER_NOT_FOUND);
|
throw exception(PAY_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 2.2 校验支付单已支付
|
// 2.2 校验支付单已支付
|
||||||
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
|
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
|
||||||
|
@ -101,10 +101,10 @@ public interface PayOrderService {
|
|||||||
/**
|
/**
|
||||||
* 更新支付订单价格
|
* 更新支付订单价格
|
||||||
*
|
*
|
||||||
* @param payOrderId 支付单编号
|
* @param id 支付单编号
|
||||||
* @param payPrice 支付单价格
|
* @param payPrice 支付单价格
|
||||||
*/
|
*/
|
||||||
void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
|
void updatePayOrderPrice(Long id, Integer payPrice);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得支付订单
|
* 获得支付订单
|
||||||
|
@ -160,7 +160,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
getSelf().notifyOrder(channel, unifiedOrderResp);
|
getSelf().notifyOrder(channel, unifiedOrderResp);
|
||||||
// 如有渠道错误码,则抛出业务异常,提示用户
|
// 如有渠道错误码,则抛出业务异常,提示用户
|
||||||
if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
|
if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
|
||||||
throw exception(ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
|
throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
|
||||||
unifiedOrderResp.getChannelErrorMsg());
|
unifiedOrderResp.getChannelErrorMsg());
|
||||||
}
|
}
|
||||||
// 此处需要读取最新的状态
|
// 此处需要读取最新的状态
|
||||||
@ -172,16 +172,16 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
private PayOrderDO validateOrderCanSubmit(Long id) {
|
private PayOrderDO validateOrderCanSubmit(Long id) {
|
||||||
PayOrderDO order = orderMapper.selectById(id);
|
PayOrderDO order = orderMapper.selectById(id);
|
||||||
if (order == null) { // 是否存在
|
if (order == null) { // 是否存在
|
||||||
throw exception(ORDER_NOT_FOUND);
|
throw exception(PAY_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (PayOrderStatusEnum.isSuccess(order.getStatus())) { // 校验状态,发现已支付
|
if (PayOrderStatusEnum.isSuccess(order.getStatus())) { // 校验状态,发现已支付
|
||||||
throw exception(ORDER_STATUS_IS_SUCCESS);
|
throw exception(PAY_ORDER_STATUS_IS_SUCCESS);
|
||||||
}
|
}
|
||||||
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
|
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
|
||||||
throw exception(ORDER_STATUS_IS_NOT_WAITING);
|
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
|
if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
|
||||||
throw exception(ORDER_IS_EXPIRED);
|
throw exception(PAY_ORDER_IS_EXPIRED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 【重要】校验是否支付拓展单已支付,只是没有回调、或者数据不正常
|
// 【重要】校验是否支付拓展单已支付,只是没有回调、或者数据不正常
|
||||||
@ -202,7 +202,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) {
|
if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) {
|
||||||
log.warn("[validateOrderCanSubmit][order({}) 的 extension({}) 已支付,可能是数据不一致]",
|
log.warn("[validateOrderCanSubmit][order({}) 的 extension({}) 已支付,可能是数据不一致]",
|
||||||
id, orderExtension.getId());
|
id, orderExtension.getId());
|
||||||
throw exception(ORDER_EXTENSION_IS_PAID);
|
throw exception(PAY_ORDER_EXTENSION_IS_PAID);
|
||||||
}
|
}
|
||||||
// 情况二:调用三方接口,查询支付单状态,是不是已支付
|
// 情况二:调用三方接口,查询支付单状态,是不是已支付
|
||||||
PayClient payClient = payClientFactory.getPayClient(orderExtension.getChannelId());
|
PayClient payClient = payClientFactory.getPayClient(orderExtension.getChannelId());
|
||||||
@ -214,7 +214,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
if (respDTO != null && PayOrderStatusRespEnum.isSuccess(respDTO.getStatus())) {
|
if (respDTO != null && PayOrderStatusRespEnum.isSuccess(respDTO.getStatus())) {
|
||||||
log.warn("[validateOrderCanSubmit][order({}) 的 PayOrderRespDTO({}) 已支付,可能是回调延迟]",
|
log.warn("[validateOrderCanSubmit][order({}) 的 PayOrderRespDTO({}) 已支付,可能是回调延迟]",
|
||||||
id, toJsonString(respDTO));
|
id, toJsonString(respDTO));
|
||||||
throw exception(ORDER_EXTENSION_IS_PAID);
|
throw exception(PAY_ORDER_EXTENSION_IS_PAID);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -254,9 +254,10 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
* 通知并更新订单的支付结果
|
* 通知并更新订单的支付结果
|
||||||
*
|
*
|
||||||
* @param channel 支付渠道
|
* @param channel 支付渠道
|
||||||
* @param notify 通知
|
* @param notify 通知
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class) // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
// 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效
|
||||||
public void notifyOrder(PayChannelDO channel, PayOrderRespDTO notify) {
|
public void notifyOrder(PayChannelDO channel, PayOrderRespDTO notify) {
|
||||||
// 情况一:支付成功的回调
|
// 情况一:支付成功的回调
|
||||||
if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
|
if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
|
||||||
@ -295,21 +296,21 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
// 1. 查询 PayOrderExtensionDO
|
// 1. 查询 PayOrderExtensionDO
|
||||||
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
|
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
|
||||||
if (orderExtension == null) {
|
if (orderExtension == null) {
|
||||||
throw exception(ORDER_EXTENSION_NOT_FOUND);
|
throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
||||||
log.info("[updateOrderExtensionSuccess][orderExtension({}) 已经是已支付,无需更新]", orderExtension.getId());
|
log.info("[updateOrderExtensionSuccess][orderExtension({}) 已经是已支付,无需更新]", orderExtension.getId());
|
||||||
return orderExtension;
|
return orderExtension;
|
||||||
}
|
}
|
||||||
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
|
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
|
||||||
throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 更新 PayOrderExtensionDO
|
// 2. 更新 PayOrderExtensionDO
|
||||||
int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
|
int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
|
||||||
PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build());
|
PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build());
|
||||||
if (updateCounts == 0) { // 校验状态,必须是待支付
|
if (updateCounts == 0) { // 校验状态,必须是待支付
|
||||||
throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
log.info("[updateOrderExtensionSuccess][orderExtension({}) 更新为已支付]", orderExtension.getId());
|
log.info("[updateOrderExtensionSuccess][orderExtension({}) 更新为已支付]", orderExtension.getId());
|
||||||
return orderExtension;
|
return orderExtension;
|
||||||
@ -318,17 +319,17 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
/**
|
/**
|
||||||
* 更新 PayOrderDO 支付成功
|
* 更新 PayOrderDO 支付成功
|
||||||
*
|
*
|
||||||
* @param channel 支付渠道
|
* @param channel 支付渠道
|
||||||
* @param orderExtension 支付拓展单
|
* @param orderExtension 支付拓展单
|
||||||
* @param notify 通知回调
|
* @param notify 通知回调
|
||||||
* @return 是否之前已经成功回调
|
* @return 是否之前已经成功回调
|
||||||
*/
|
*/
|
||||||
private Boolean updateOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
|
private Boolean updateOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
|
||||||
PayOrderRespDTO notify) {
|
PayOrderRespDTO notify) {
|
||||||
// 1. 判断 PayOrderDO 是否处于待支付
|
// 1. 判断 PayOrderDO 是否处于待支付
|
||||||
PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
|
PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(ORDER_NOT_FOUND);
|
throw exception(PAY_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
|
if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
|
||||||
&& Objects.equals(order.getExtensionId(), orderExtension.getId())) {
|
&& Objects.equals(order.getExtensionId(), orderExtension.getId())) {
|
||||||
@ -336,7 +337,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
|
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
|
||||||
throw exception(ORDER_STATUS_IS_NOT_WAITING);
|
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 更新 PayOrderDO
|
// 2. 更新 PayOrderDO
|
||||||
@ -346,10 +347,10 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
.successTime(notify.getSuccessTime()).extensionId(orderExtension.getId()).no(orderExtension.getNo())
|
.successTime(notify.getSuccessTime()).extensionId(orderExtension.getId()).no(orderExtension.getNo())
|
||||||
.channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
|
.channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
|
||||||
.channelFeeRate(channel.getFeeRate())
|
.channelFeeRate(channel.getFeeRate())
|
||||||
.channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate()))
|
.channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate()))
|
||||||
.build());
|
.build());
|
||||||
if (updateCounts == 0) { // 校验状态,必须是待支付
|
if (updateCounts == 0) { // 校验状态,必须是待支付
|
||||||
throw exception(ORDER_STATUS_IS_NOT_WAITING);
|
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
log.info("[updateOrderExtensionSuccess][order({}) 更新为已支付]", order.getId());
|
log.info("[updateOrderExtensionSuccess][order({}) 更新为已支付]", order.getId());
|
||||||
return false;
|
return false;
|
||||||
@ -363,7 +364,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
// 1. 查询 PayOrderExtensionDO
|
// 1. 查询 PayOrderExtensionDO
|
||||||
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
|
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
|
||||||
if (orderExtension == null) {
|
if (orderExtension == null) {
|
||||||
throw exception(ORDER_EXTENSION_NOT_FOUND);
|
throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新
|
if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新
|
||||||
log.info("[updateOrderExtensionClosed][orderExtension({}) 已经是支付关闭,无需更新]", orderExtension.getId());
|
log.info("[updateOrderExtensionClosed][orderExtension({}) 已经是支付关闭,无需更新]", orderExtension.getId());
|
||||||
@ -375,7 +376,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
|
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
|
||||||
throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 更新 PayOrderExtensionDO
|
// 2. 更新 PayOrderExtensionDO
|
||||||
@ -383,7 +384,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify))
|
PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify))
|
||||||
.channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build());
|
.channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build());
|
||||||
if (updateCounts == 0) { // 校验状态,必须是待支付
|
if (updateCounts == 0) { // 校验状态,必须是待支付
|
||||||
throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
log.info("[updateOrderExtensionClosed][orderExtension({}) 更新为支付关闭]", orderExtension.getId());
|
log.info("[updateOrderExtensionClosed][orderExtension({}) 更新为支付关闭]", orderExtension.getId());
|
||||||
}
|
}
|
||||||
@ -392,10 +393,10 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
|
public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
|
||||||
PayOrderDO order = orderMapper.selectById(id);
|
PayOrderDO order = orderMapper.selectById(id);
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(ORDER_NOT_FOUND);
|
throw exception(PAY_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
|
if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
|
||||||
throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
|
throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
|
||||||
}
|
}
|
||||||
if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
|
if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
|
||||||
throw exception(REFUND_PRICE_EXCEED);
|
throw exception(REFUND_PRICE_EXCEED);
|
||||||
@ -407,16 +408,21 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
.setStatus(PayOrderStatusEnum.REFUND.getStatus());
|
.setStatus(PayOrderStatusEnum.REFUND.getStatus());
|
||||||
int updateCount = orderMapper.updateByIdAndStatus(id, order.getStatus(), updateObj);
|
int updateCount = orderMapper.updateByIdAndStatus(id, order.getStatus(), updateObj);
|
||||||
if (updateCount == 0) {
|
if (updateCount == 0) {
|
||||||
throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
|
throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
|
public void updatePayOrderPrice(Long id, Integer payPrice) {
|
||||||
// TODO @puhui999:不能直接这样修改哈;应该只有未支付状态的订单才可以改;另外,如果价格如果没变,可以直接 return 哈;
|
PayOrderDO order = orderMapper.selectById(id);
|
||||||
PayOrderDO order = orderMapper.selectById(payOrderId);
|
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(ORDER_NOT_FOUND);
|
throw exception(PAY_ORDER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (ObjectUtil.notEqual(PayOrderStatusEnum.WAITING.getStatus(), order.getStatus())) {
|
||||||
|
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
||||||
|
}
|
||||||
|
if (ObjectUtil.equal(order.getPrice(), payPrice)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
order.setPrice(payPrice);
|
order.setPrice(payPrice);
|
||||||
|
@ -160,11 +160,11 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
|
private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
|
||||||
PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
|
PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(ORDER_NOT_FOUND);
|
throw exception(PAY_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 校验状态,必须是已支付、或者已退款
|
// 校验状态,必须是已支付、或者已退款
|
||||||
if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
|
if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
|
||||||
throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
|
throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验金额,退款金额不能大于原定的金额
|
// 校验金额,退款金额不能大于原定的金额
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.service.wallet;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钱包充值 Service 接口
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
public interface PayWalletRechargeService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建钱包充值记录
|
||||||
|
* @param userId 用户 id
|
||||||
|
* @param userType 用户类型
|
||||||
|
* @param vo 钱包充值请求 vo
|
||||||
|
* @return 钱包充值记录
|
||||||
|
*/
|
||||||
|
PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, AppPayWalletRechargeCreateReqVO vo);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新钱包充值成功
|
||||||
|
* @param walletRechargeId 钱包充值 id
|
||||||
|
* @param payOrderId 支付订单 id
|
||||||
|
*/
|
||||||
|
void updateWalletRechargerPaid(Long walletRechargeId, Long payOrderId);
|
||||||
|
}
|
@ -0,0 +1,135 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.service.wallet;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargeConvert;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletRechargeMapper;
|
||||||
|
import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static cn.hutool.core.util.ObjectUtil.notEqual;
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
||||||
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钱包充值 Service 实现类
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
|
||||||
|
/**
|
||||||
|
* TODO 放到 配置文件中
|
||||||
|
*/
|
||||||
|
private static final Long WALLET_PAY_APP_ID = 8L;
|
||||||
|
|
||||||
|
private static final String WALLET_RECHARGE_ORDER_SUBJECT = "钱包余额充值";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PayWalletRechargeMapper walletRechargeMapper;
|
||||||
|
@Resource
|
||||||
|
private PayWalletService payWalletService;
|
||||||
|
@Resource
|
||||||
|
private PayOrderService payOrderService;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, AppPayWalletRechargeCreateReqVO vo) {
|
||||||
|
// 1. 获取钱包
|
||||||
|
PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType);
|
||||||
|
// 2. 新增钱包充值记录
|
||||||
|
PayWalletRechargeDO walletRecharge = PayWalletRechargeConvert.INSTANCE.convert(wallet.getId(), vo);
|
||||||
|
walletRechargeMapper.insert(walletRecharge);
|
||||||
|
// 3.创建支付单
|
||||||
|
Long payOrderId = payOrderService.createOrder(new PayOrderCreateReqDTO()
|
||||||
|
.setAppId(WALLET_PAY_APP_ID).setUserIp(getClientIP())
|
||||||
|
.setMerchantOrderId(walletRecharge.getId().toString()) // 业务的订单编号
|
||||||
|
.setSubject(WALLET_RECHARGE_ORDER_SUBJECT).setBody("").setPrice(walletRecharge.getPayPrice())
|
||||||
|
.setExpireTime(addTime(Duration.ofHours(2L))));
|
||||||
|
// 4.更新钱包充值记录中支付订单
|
||||||
|
walletRechargeMapper.updateById(new PayWalletRechargeDO().setPayOrderId(payOrderId)
|
||||||
|
.setId(walletRecharge.getId()));
|
||||||
|
return walletRechargeMapper.selectById(walletRecharge.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void updateWalletRechargerPaid(Long walletRechargeId, Long payOrderId) {
|
||||||
|
// 1. 获取钱包充值记录
|
||||||
|
PayWalletRechargeDO walletRecharge = walletRechargeMapper.selectById(walletRechargeId);
|
||||||
|
if (walletRecharge == null) {
|
||||||
|
log.error("[updateWalletRechargerPaid],钱包充值记录不存在,钱包充值 Id:{} ", walletRechargeId);
|
||||||
|
throw exception(WALLET_RECHARGE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
// 2. 校验钱包充值是否可以支付
|
||||||
|
PayOrderDO payOrderDO = validateWalletRechargerCanPaid(walletRecharge, payOrderId);
|
||||||
|
// 3. 更新钱包充值的支付状态
|
||||||
|
int updateCount = walletRechargeMapper.updateByIdAndPaid(walletRechargeId,false, new PayWalletRechargeDO().setId(walletRechargeId)
|
||||||
|
.setPayStatus(true).setPayTime(LocalDateTime.now())
|
||||||
|
.setPayChannelCode(payOrderDO.getChannelCode()));
|
||||||
|
if (updateCount == 0) {
|
||||||
|
throw exception(WALLET_RECHARGE_UPDATE_PAID_STATUS_NOT_UNPAID);
|
||||||
|
}
|
||||||
|
// 4. 更新钱包余额
|
||||||
|
payWalletService.addWalletBalance(walletRecharge.getWalletId(), String.valueOf(walletRechargeId),
|
||||||
|
PayWalletBizTypeEnum.RECHARGE, walletRecharge.getPrice());
|
||||||
|
}
|
||||||
|
|
||||||
|
private PayOrderDO validateWalletRechargerCanPaid(PayWalletRechargeDO walletRecharge, Long payOrderId) {
|
||||||
|
|
||||||
|
// 1.1 校验充值记录的支付状态
|
||||||
|
if (walletRecharge.getPayStatus()) {
|
||||||
|
log.error("[validateWalletRechargerCanPaid][钱包({}) 不处于未支付状态! 钱包数据是:{}]",
|
||||||
|
walletRecharge.getId(), toJsonString(walletRecharge));
|
||||||
|
throw exception(WALLET_RECHARGE_UPDATE_PAID_STATUS_NOT_UNPAID);
|
||||||
|
}
|
||||||
|
// 1.2 校验支付订单匹配
|
||||||
|
if (notEqual(walletRecharge.getPayOrderId(), payOrderId)) { // 支付单号
|
||||||
|
log.error("[validateWalletRechargerCanPaid][钱包({}) 支付单不匹配({}),请进行处理! 钱包数据是:{}]",
|
||||||
|
walletRecharge.getId(), payOrderId, toJsonString(walletRecharge));
|
||||||
|
throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_ID_ERROR);
|
||||||
|
}
|
||||||
|
// 2.1 校验支付单是否存在
|
||||||
|
PayOrderDO payOrder = payOrderService.getOrder(payOrderId);
|
||||||
|
if (payOrder == null) {
|
||||||
|
log.error("[validateWalletRechargerCanPaid][钱包({}) payOrder({}) 不存在,请进行处理!]",
|
||||||
|
walletRecharge.getId(), payOrderId);
|
||||||
|
throw exception(PAY_ORDER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
// 2.2 校验支付单已支付
|
||||||
|
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
|
||||||
|
log.error("[validateWalletRechargerCanPaid][钱包({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]",
|
||||||
|
walletRecharge.getId(), payOrderId, toJsonString(payOrder));
|
||||||
|
throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_STATUS_NOT_SUCCESS);
|
||||||
|
}
|
||||||
|
// 2.3 校验支付金额一致
|
||||||
|
if (notEqual(payOrder.getPrice(), walletRecharge.getPayPrice())) {
|
||||||
|
log.error("[validateDemoOrderCanPaid][钱包({}) payOrder({}) 支付金额不匹配,请进行处理!钱包 数据是:{},payOrder 数据是:{}]",
|
||||||
|
walletRecharge.getId(), payOrderId, toJsonString(walletRecharge), toJsonString(payOrder));
|
||||||
|
throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_PRICE_NOT_MATCH);
|
||||||
|
}
|
||||||
|
// 2.4 校验支付订单的商户订单匹配
|
||||||
|
if (notEqual(payOrder.getMerchantOrderId(), walletRecharge.getId().toString())) {
|
||||||
|
log.error("[validateDemoOrderCanPaid][钱包({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]",
|
||||||
|
walletRecharge.getId(), payOrderId, toJsonString(payOrder));
|
||||||
|
throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_ID_ERROR);
|
||||||
|
}
|
||||||
|
return payOrder;
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,13 @@ public interface PayWalletService {
|
|||||||
*/
|
*/
|
||||||
PayWalletDO getOrCreateWallet(Long userId, Integer userType);
|
PayWalletDO getOrCreateWallet(Long userId, Integer userType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取钱包信息
|
||||||
|
*
|
||||||
|
* @param walletId 钱包 id
|
||||||
|
*/
|
||||||
|
PayWalletDO getWallet(Long walletId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 钱包订单支付
|
* 钱包订单支付
|
||||||
*
|
*
|
||||||
@ -56,14 +63,13 @@ public interface PayWalletService {
|
|||||||
/**
|
/**
|
||||||
* 增加钱包余额
|
* 增加钱包余额
|
||||||
*
|
*
|
||||||
* @param userId 用户 id
|
* @param walletId 钱包 id
|
||||||
* @param userType 用户类型
|
|
||||||
* @param bizId 业务关联 id
|
* @param bizId 业务关联 id
|
||||||
* @param bizType 业务关联分类
|
* @param bizType 业务关联分类
|
||||||
* @param price 增加金额
|
* @param price 增加金额
|
||||||
* @return 钱包流水
|
* @return 钱包流水
|
||||||
*/
|
*/
|
||||||
PayWalletTransactionDO addWalletBalance(Long userId, Integer userType,
|
PayWalletTransactionDO addWalletBalance(Long walletId, String bizId,
|
||||||
Long bizId, PayWalletBizTypeEnum bizType, Integer price);
|
PayWalletBizTypeEnum bizType, Integer price);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -55,13 +55,18 @@ public class PayWalletServiceImpl implements PayWalletService {
|
|||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PayWalletDO getWallet(Long walletId) {
|
||||||
|
return walletMapper.selectById(walletId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price) {
|
public PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price) {
|
||||||
// 1. 判断支付交易拓展单是否存
|
// 1. 判断支付交易拓展单是否存
|
||||||
PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
|
PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
|
||||||
if (orderExtension == null) {
|
if (orderExtension == null) {
|
||||||
throw exception(ORDER_EXTENSION_NOT_FOUND);
|
throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 2. 扣减余额
|
// 2. 扣减余额
|
||||||
return reduceWalletBalance(userId, userType, orderExtension.getOrderId(), PAYMENT, price);
|
return reduceWalletBalance(userId, userType, orderExtension.getOrderId(), PAYMENT, price);
|
||||||
@ -80,7 +85,7 @@ public class PayWalletServiceImpl implements PayWalletService {
|
|||||||
PayWalletDO wallet = walletMapper.selectById(walletId);
|
PayWalletDO wallet = walletMapper.selectById(walletId);
|
||||||
Assert.notNull(wallet, "钱包 {} 不存在", walletId);
|
Assert.notNull(wallet, "钱包 {} 不存在", walletId);
|
||||||
// 2. 增加余额
|
// 2. 增加余额
|
||||||
return addWalletBalance(wallet.getUserId(), wallet.getUserType(), payRefund.getId(), PAYMENT_REFUND, refundPrice);
|
return addWalletBalance(walletId, String.valueOf(payRefund.getId()), PAYMENT_REFUND, refundPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,25 +144,33 @@ public class PayWalletServiceImpl implements PayWalletService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType,
|
public PayWalletTransactionDO addWalletBalance(Long walletId,
|
||||||
Long bizId, PayWalletBizTypeEnum bizType, Integer price) {
|
String bizId, PayWalletBizTypeEnum bizType, Integer price) {
|
||||||
// 1. 获取钱包
|
// 1. 获取钱包
|
||||||
PayWalletDO payWallet = getOrCreateWallet(userId, userType);
|
PayWalletDO payWallet = getWallet(walletId);
|
||||||
|
|
||||||
|
if (payWallet == null) {
|
||||||
|
log.error("[addWalletBalance],用户钱包({})不存在.", walletId);
|
||||||
|
throw exception(WALLET_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
switch (bizType) {
|
switch (bizType) {
|
||||||
case PAYMENT_REFUND: {
|
case PAYMENT_REFUND: {
|
||||||
// 更新退款
|
// 退款更新
|
||||||
walletMapper.updateWhenConsumptionRefund(price, payWallet.getId());
|
walletMapper.updateWhenConsumptionRefund(price, payWallet.getId());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RECHARGE: {
|
case RECHARGE: {
|
||||||
//TODO
|
// 充值更新
|
||||||
|
walletMapper.updateWhenRecharge(price, payWallet.getId());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// TODO 其它类型
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 生成钱包流水
|
// 2. 生成钱包流水
|
||||||
CreateWalletTransactionBO bo = new CreateWalletTransactionBO().setWalletId(payWallet.getId())
|
CreateWalletTransactionBO bo = new CreateWalletTransactionBO().setWalletId(payWallet.getId())
|
||||||
.setPrice(price).setBalance(payWallet.getBalance()+price).setBizId(String.valueOf(bizId))
|
.setPrice(price).setBalance(payWallet.getBalance()+price).setBizId(bizId)
|
||||||
.setBizType(bizType.getType()).setTitle(bizType.getDescription());
|
.setBizType(bizType.getType()).setTitle(bizType.getDescription());
|
||||||
return walletTransactionService.createWalletTransaction(bo);
|
return walletTransactionService.createWalletTransaction(bo);
|
||||||
}
|
}
|
||||||
|
@ -261,7 +261,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
String userIp = randomString();
|
String userIp = randomString();
|
||||||
|
|
||||||
// 调用, 并断言异常
|
// 调用, 并断言异常
|
||||||
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_NOT_FOUND);
|
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -274,7 +274,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
String userIp = randomString();
|
String userIp = randomString();
|
||||||
|
|
||||||
// 调用, 并断言异常
|
// 调用, 并断言异常
|
||||||
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_NOT_WAITING);
|
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -287,7 +287,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
String userIp = randomString();
|
String userIp = randomString();
|
||||||
|
|
||||||
// 调用, 并断言异常
|
// 调用, 并断言异常
|
||||||
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_SUCCESS);
|
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_STATUS_IS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -301,7 +301,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
String userIp = randomString();
|
String userIp = randomString();
|
||||||
|
|
||||||
// 调用, 并断言异常
|
// 调用, 并断言异常
|
||||||
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_IS_EXPIRED);
|
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_IS_EXPIRED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -366,7 +366,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> orderService.submitOrder(reqVO, userIp),
|
assertServiceException(() -> orderService.submitOrder(reqVO, userIp),
|
||||||
ORDER_SUBMIT_CHANNEL_ERROR, "001", "模拟异常");
|
PAY_ORDER_SUBMIT_CHANNEL_ERROR, "001", "模拟异常");
|
||||||
// 断言,数据记录(PayOrderExtensionDO)
|
// 断言,数据记录(PayOrderExtensionDO)
|
||||||
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null);
|
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null);
|
||||||
assertNotNull(orderExtension);
|
assertNotNull(orderExtension);
|
||||||
@ -450,7 +450,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> orderService.validateOrderActuallyPaid(id),
|
assertServiceException(() -> orderService.validateOrderActuallyPaid(id),
|
||||||
ORDER_EXTENSION_IS_PAID);
|
PAY_ORDER_EXTENSION_IS_PAID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -469,7 +469,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> orderService.validateOrderActuallyPaid(id),
|
assertServiceException(() -> orderService.validateOrderActuallyPaid(id),
|
||||||
ORDER_EXTENSION_IS_PAID);
|
PAY_ORDER_EXTENSION_IS_PAID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -519,7 +519,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
ORDER_EXTENSION_NOT_FOUND);
|
PAY_ORDER_EXTENSION_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -537,7 +537,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -555,7 +555,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
ORDER_NOT_FOUND);
|
PAY_ORDER_NOT_FOUND);
|
||||||
// 断言 PayOrderExtensionDO :数据更新被回滚
|
// 断言 PayOrderExtensionDO :数据更新被回滚
|
||||||
assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
|
assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
|
||||||
}
|
}
|
||||||
@ -588,7 +588,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
ORDER_STATUS_IS_NOT_WAITING);
|
PAY_ORDER_STATUS_IS_NOT_WAITING);
|
||||||
// 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
|
// 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
|
||||||
assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
|
assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
|
||||||
}
|
}
|
||||||
@ -673,7 +673,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
ORDER_EXTENSION_NOT_FOUND);
|
PAY_ORDER_EXTENSION_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -729,7 +729,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -762,7 +762,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
|
assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
|
||||||
ORDER_NOT_FOUND);
|
PAY_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -786,7 +786,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
|
assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
|
||||||
ORDER_REFUND_FAIL_STATUS_ERROR);
|
PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -219,7 +219,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> refundService.createPayRefund(reqDTO),
|
assertServiceException(() -> refundService.createPayRefund(reqDTO),
|
||||||
ORDER_NOT_FOUND);
|
PAY_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -245,7 +245,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> refundService.createPayRefund(reqDTO),
|
assertServiceException(() -> refundService.createPayRefund(reqDTO),
|
||||||
ORDER_REFUND_FAIL_STATUS_ERROR);
|
PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
Reference in New Issue
Block a user