mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 15:21:53 +08:00
Merge branch 'feature/mall_product' of https://gitee.com/CrazyWorld/ruoyi-vue-pro into feature/mall_product
# Conflicts: # yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
This commit is contained in:
commit
057952bdeb
11
sql/mysql/member.sql
Normal file
11
sql/mysql/member.sql
Normal file
@ -0,0 +1,11 @@
|
||||
-- 查询上级菜单、排序
|
||||
SELECT parent_id, sort
|
||||
INTO @parentId, @sort
|
||||
FROM system_menu
|
||||
WHERE name = '用户等级修改'
|
||||
LIMIT 1;
|
||||
-- 新增 按钮权限
|
||||
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
|
||||
VALUES ('用户积分修改', 'member:user:update-point', 3, @sort + 1, @parentId, '', '', '', 0);
|
||||
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
|
||||
VALUES ('用户余额修改', 'member:user:update-balance', 3, @sort + 2, @parentId, '', '', '', 0);
|
@ -805,7 +805,7 @@ CREATE TABLE `member_level_record` (
|
||||
`user_id` bigint NOT NULL DEFAULT 0 COMMENT '用户编号',
|
||||
`level_id` bigint NOT NULL DEFAULT 0 COMMENT '等级编号',
|
||||
`level` int NOT NULL DEFAULT 0 COMMENT '会员等级',
|
||||
`discount_percent` tinyint NOT NULL DEFAULT 100 COMMENT '享受折扣',
|
||||
`discount_percent` int NOT NULL DEFAULT 100 COMMENT '享受折扣',
|
||||
`experience` int NOT NULL DEFAULT 0 COMMENT '升级经验',
|
||||
`user_experience` int NOT NULL DEFAULT 0 COMMENT '会员此时的经验',
|
||||
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '备注',
|
||||
@ -827,15 +827,15 @@ BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for member_point_config
|
||||
-- Table structure for member_config
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `member_point_config`;
|
||||
CREATE TABLE `member_point_config` (
|
||||
DROP TABLE IF EXISTS `member_config`;
|
||||
CREATE TABLE `member_config` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键',
|
||||
`trade_deduct_enable` bit(1) NOT NULL COMMENT '是否开启积分抵扣',
|
||||
`trade_deduct_unit_price` int NOT NULL COMMENT '积分抵扣(单位:分)',
|
||||
`trade_deduct_max_price` int NULL DEFAULT NULL COMMENT '积分抵扣最大值',
|
||||
`trade_give_point` bigint NULL DEFAULT NULL COMMENT '1 元赠送多少分',
|
||||
`point_trade_deduct_enable` bit(1) NOT NULL COMMENT '是否开启积分抵扣',
|
||||
`point_trade_deduct_unit_price` int NOT NULL COMMENT '积分抵扣(单位:分)',
|
||||
`point_trade_deduct_max_price` int NULL DEFAULT NULL COMMENT '积分抵扣最大值',
|
||||
`point_trade_give_point` bigint NULL DEFAULT NULL COMMENT '1 元赠送多少分',
|
||||
`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 '更新者',
|
||||
@ -843,13 +843,13 @@ CREATE TABLE `member_point_config` (
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员积分配置表';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员配置表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of member_point_config
|
||||
-- Records of member_config
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
INSERT INTO `member_point_config` (`id`, `trade_deduct_enable`, `trade_deduct_unit_price`, `trade_deduct_max_price`, `trade_give_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, b'1', 100, 2, 3, '1', '2023-08-20 09:54:42', '1', '2023-08-20 09:54:42', b'0', 1);
|
||||
INSERT INTO `member_config` (`id`, `point_trade_deduct_enable`, `point_trade_deduct_unit_price`, `point_trade_deduct_max_price`, `point_trade_give_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, b'1', 100, 2, 3, '1', '2023-08-20 09:54:42', '1', '2023-08-20 09:54:42', b'0', 1);
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
@ -915,7 +915,8 @@ DROP TABLE IF EXISTS `member_sign_in_config`;
|
||||
CREATE TABLE `member_sign_in_config` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '编号',
|
||||
`day` int NOT NULL COMMENT '第几天',
|
||||
`point` int NOT NULL COMMENT '奖励积分',
|
||||
`point` int NOT NULL DEFAULT 0 COMMENT '奖励积分',
|
||||
`experience` int NOT NULL DEFAULT 0 COMMENT '奖励经验',
|
||||
`status` tinyint NOT NULL COMMENT '状态',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
@ -930,18 +931,18 @@ CREATE TABLE `member_sign_in_config` (
|
||||
-- Records of member_sign_in_config
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 1, 10, 0, '', '2023-08-20 01:38:56', '', '2023-08-20 01:38:56', b'0', 0);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, 20, 0, '', '2023-08-20 01:38:56', '', '2023-08-20 01:38:56', b'0', 0);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 7, 1001, 0, '', '2023-08-20 01:38:56', '', '2023-08-20 01:38:56', b'0', 0);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 6, 12121, 0, '', '2023-08-20 01:38:56', '', '2023-08-20 01:38:56', b'0', 0);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 2, 12, 0, '', '2023-08-20 01:38:56', '', '2023-08-20 01:38:56', b'0', 0);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 1, 10, 0, '1', '2023-08-20 19:20:42', '1', '2023-08-20 19:20:56', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 7, 22, 0, '1', '2023-08-20 19:20:48', '1', '2023-08-20 19:20:48', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 2, 3, 0, '1', '2023-08-21 20:22:44', '1', '2023-08-21 20:22:44', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 3, 4, 0, '1', '2023-08-21 20:22:48', '1', '2023-08-21 20:22:48', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 4, 5, 0, '1', '2023-08-21 20:22:51', '1', '2023-08-21 20:22:51', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (11, 5, 6, 0, '1', '2023-08-21 20:22:56', '1', '2023-08-21 20:22:56', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (12, 6, 7, 0, '1', '2023-08-21 20:22:59', '1', '2023-08-21 20:22:59', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 1, 10, 10, 0, '', '2023-08-20 01:38:56', '', '2023-08-20 01:38:56', b'0', 0);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, 20, 20, 0, '', '2023-08-20 01:38:56', '', '2023-08-20 01:38:56', b'0', 0);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 7, 1001, 1001, 0, '', '2023-08-20 01:38:56', '', '2023-08-20 01:38:56', b'0', 0);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 6, 12121, 12121, 0, '', '2023-08-20 01:38:56', '', '2023-08-20 01:38:56', b'0', 0);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 3, 12, 12, 0, '', '2023-08-20 01:38:56', '', '2023-08-20 01:38:56', b'0', 0);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 1, 10, 10, 0, '1', '2023-08-20 19:20:42', '1', '2023-08-20 19:20:56', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 7, 22, 22, 0, '1', '2023-08-20 19:20:48', '1', '2023-08-20 19:20:48', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 2, 3, 3, 0, '1', '2023-08-21 20:22:44', '1', '2023-08-21 20:22:44', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 3, 4, 4, 0, '1', '2023-08-21 20:22:48', '1', '2023-08-21 20:22:48', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 4, 5, 5, 0, '1', '2023-08-21 20:22:51', '1', '2023-08-21 20:22:51', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (11, 5, 6, 6, 0, '1', '2023-08-21 20:22:56', '1', '2023-08-21 20:22:56', b'0', 1);
|
||||
INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `experience`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (12, 6, 7, 7, 0, '1', '2023-08-21 20:22:59', '1', '2023-08-21 20:22:59', b'0', 1);
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
@ -952,7 +953,8 @@ CREATE TABLE `member_sign_in_record` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '签到自增id',
|
||||
`user_id` int NULL DEFAULT NULL COMMENT '签到用户',
|
||||
`day` int NULL DEFAULT NULL COMMENT '第几天签到',
|
||||
`point` int NULL DEFAULT NULL COMMENT '签到的分数',
|
||||
`point` int NOT NULL DEFAULT 0 COMMENT '签到的积分',
|
||||
`experience` int NOT NULL DEFAULT 0 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 '更新者',
|
||||
@ -962,6 +964,8 @@ CREATE TABLE `member_sign_in_record` (
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '签到记录';
|
||||
|
||||
CREATE INDEX user_id_index ON member_sign_in_record (user_id);
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of member_sign_in_record
|
||||
-- ----------------------------
|
||||
@ -2013,20 +2017,19 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2184, '自提门店导出', 'trade:delivery:pick-up-store:export', 3, 5, 2179, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2209, '秒杀活动', '', 2, 3, 2030, 'seckill', 'ep:place', '', '', 0, b'1', b'1', b'1', '1', '2023-06-24 17:39:13', '1', '2023-06-24 18:55:15', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2262, '会员中心', '', 1, 55, 0, '/member', 'ep:bicycle', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-06-10 00:42:03', '1', '2023-08-20 09:23:56', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2275, '积分配置', '', 2, 0, 2299, 'config', 'fa:archive', 'member/point/config/index', 'PointConfig', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2023-08-20 12:01:20', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2276, '积分设置查询', 'point:config:query', 3, 1, 2275, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '', '2023-06-10 02:07:44', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2277, '积分设置创建', 'point:config:save', 3, 2, 2275, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2023-06-27 20:32:31', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2275, '会员配置', '', 2, 0, 2262, 'config', 'fa:archive', 'member/config/index', 'MemberConfig', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2023-08-20 12:01:20', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2276, '会员配置查询', 'member:config:query', 3, 1, 2275, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '', '2023-06-10 02:07:44', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2277, '会员配置创建', 'member:config:save', 3, 2, 2275, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2023-06-27 20:32:31', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2281, '签到配置', '', 2, 2, 2300, 'config', 'ep:calendar', 'member/signin/config/index', 'SignInConfig', 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '1', '2023-08-20 19:25:51', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2282, '积分签到规则查询', 'point:sign-in-config:query', 3, 1, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2283, '积分签到规则创建', 'point:sign-in-config:create', 3, 2, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2284, '积分签到规则更新', 'point:sign-in-config:update', 3, 3, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2285, '积分签到规则删除', 'point:sign-in-config:delete', 3, 4, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2287, '积分记录', '', 2, 1, 2299, 'record', 'fa:asterisk', 'member/point/record/index', 'PointRecord', 0, b'1', b'1', b'1', '', '2023-06-10 04:18:50', '1', '2023-08-20 12:01:42', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2288, '用户积分记录查询', 'point:record:query', 3, 1, 2287, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:18:50', '', '2023-06-10 04:18:50', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2287, '会员积分', '', 2, 1, 2262, 'point', 'ep:pointer', 'member/point/record/index', 'PointRecord', 0, b'1', b'1', b'1', '', '2023-06-10 04:18:50', '1', '2023-08-20 12:01:42', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2288, '会员积分记录查询', 'point:record:query', 3, 1, 2287, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:18:50', '', '2023-06-10 04:18:50', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2293, '签到记录', '', 2, 3, 2300, 'record', 'ep:chicken', 'member/signin/record/index', 'SignInRecord', 0, b'1', b'1', b'1', '', '2023-06-10 04:48:22', '1', '2023-08-20 19:26:02', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2294, '用户签到积分查询', 'point:sign-in-record:query', 3, 1, 2293, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2297, '用户签到积分删除', 'point:sign-in-record:delete', 3, 4, 2293, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2299, '会员积分', '', 1, 10, 2262, 'point', 'ep:pointer', '', '', 0, b'1', b'1', b'1', '1', '2023-06-27 22:48:51', '1', '2023-08-20 09:23:35', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2300, '会员签到', '', 1, 11, 2262, 'signin', 'ep:alarm-clock', '', '', 0, b'1', b'1', b'1', '1', '2023-06-27 22:49:53', '1', '2023-08-20 09:23:48', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2301, '回调通知', '', 2, 4, 1117, 'notify', 'example', 'pay/notify/index', 'PayNotify', 0, b'1', b'1', b'1', '', '2023-07-20 04:41:32', '1', '2023-07-20 13:45:08', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2302, '支付通知查询', 'pay:notify:query', 3, 1, 2301, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-07-20 04:41:32', '', '2023-07-20 04:41:32', b'0');
|
||||
|
3
sql/mysql/trade_order.sql
Normal file
3
sql/mysql/trade_order.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- 增加字段
|
||||
ALTER TABLE trade_order
|
||||
ADD COLUMN brokerage_user_id bigint NULL COMMENT '推广人编号' AFTER comment_status;
|
@ -6,6 +6,7 @@ import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
|
||||
/**
|
||||
* 时间工具类,用于 {@link java.time.LocalDateTime}
|
||||
@ -137,4 +138,29 @@ public class LocalDateTimeUtils {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定日期所在的月份的开始时间
|
||||
* 例如:2023-09-30 00:00:00,000
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 月份的开始时间
|
||||
*/
|
||||
public static LocalDateTime beginOfMonth(LocalDateTime date) {
|
||||
return date
|
||||
.with(TemporalAdjusters.firstDayOfMonth())
|
||||
.with(LocalTime.MIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定日期所在的月份的最后时间
|
||||
* 例如:2023-09-30 23:59:59,999
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 月份的结束时间
|
||||
*/
|
||||
public static LocalDateTime endOfMonth(LocalDateTime date) {
|
||||
return date
|
||||
.with(TemporalAdjusters.lastDayOfMonth())
|
||||
.with(LocalTime.MAX);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package cn.iocoder.yudao.module.product.api.category;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 商品分类 API 接口
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
public interface ProductCategoryApi {
|
||||
|
||||
/**
|
||||
* 校验商品分类是否有效。如下情况,视为无效:
|
||||
* 1. 商品分类编号不存在
|
||||
* 2. 商品分类被禁用
|
||||
*
|
||||
* @param ids 商品分类编号数组
|
||||
*/
|
||||
void validateCategoryList(Collection<Long> ids);
|
||||
}
|
@ -21,6 +21,14 @@ public interface ProductSpuApi {
|
||||
*/
|
||||
List<ProductSpuRespDTO> getSpuList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 批量查询 SPU 数组,并且校验是否 SPU 是否有效
|
||||
*
|
||||
* @param ids SPU 编号列表
|
||||
* @return SPU 数组
|
||||
*/
|
||||
List<ProductSpuRespDTO> getSpuListAndValidate(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得 SPU
|
||||
*
|
||||
@ -28,4 +36,12 @@ public interface ProductSpuApi {
|
||||
*/
|
||||
ProductSpuRespDTO getSpu(Long id);
|
||||
|
||||
/**
|
||||
* 校验商品是否有效。如下情况,视为无效:
|
||||
* 1. 商品编号不存在
|
||||
* 2. 商品被禁用
|
||||
*
|
||||
* @param ids 商品编号数组
|
||||
*/
|
||||
void validateSpuList(Collection<Long> ids);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ public interface ErrorCodeConstants {
|
||||
// ========== 商品 SPU 1-008-005-000 ==========
|
||||
ErrorCode SPU_NOT_EXISTS = new ErrorCode(1_008_005_000, "商品 SPU 不存在");
|
||||
ErrorCode SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR = new ErrorCode(1_008_005_001, "商品分类不正确,原因:必须使用第二级的商品分类及以下");
|
||||
ErrorCode SPU_NOT_ENABLE = new ErrorCode(1_008_005_002, "商品 SPU 不处于上架状态");
|
||||
ErrorCode SPU_NOT_ENABLE = new ErrorCode(1_008_005_002, "商品 SPU【[]】不处于上架状态");
|
||||
ErrorCode SPU_NOT_RECYCLE = new ErrorCode(1_008_005_003, "商品 SPU 不处于回收站状态");
|
||||
|
||||
// ========== 商品 SKU 1-008-006-000 ==========
|
||||
|
@ -0,0 +1,27 @@
|
||||
package cn.iocoder.yudao.module.product.api.category;
|
||||
|
||||
import cn.iocoder.yudao.module.product.service.category.ProductCategoryService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 商品分类 API 接口实现类
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProductCategoryApiImpl implements ProductCategoryApi {
|
||||
|
||||
@Resource
|
||||
private ProductCategoryService productCategoryService;
|
||||
|
||||
@Override
|
||||
public void validateCategoryList(Collection<Long> ids) {
|
||||
productCategoryService.validateCategoryList(ids);
|
||||
}
|
||||
|
||||
}
|
@ -3,9 +3,6 @@ package cn.iocoder.yudao.module.product.api.spu;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
|
||||
import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
|
||||
import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
|
||||
import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -36,9 +33,19 @@ public class ProductSpuApiImpl implements ProductSpuApi {
|
||||
return ProductSpuConvert.INSTANCE.convertList2(spuService.getSpuList(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProductSpuRespDTO> getSpuListAndValidate(Collection<Long> ids) {
|
||||
return ProductSpuConvert.INSTANCE.convertList2(spuService.validateSpuList(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProductSpuRespDTO getSpu(Long id) {
|
||||
return ProductSpuConvert.INSTANCE.convert02(spuService.getSpu(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateSpuList(Collection<Long> ids) {
|
||||
spuService.validateSpuList(ids);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCateg
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -75,4 +76,12 @@ public interface ProductCategoryService {
|
||||
*/
|
||||
List<ProductCategoryDO> getEnableCategoryList();
|
||||
|
||||
/**
|
||||
* 校验商品分类是否有效。如下情况,视为无效:
|
||||
* 1. 商品分类编号不存在
|
||||
* 2. 商品分类被禁用
|
||||
*
|
||||
* @param ids 商品分类编号数组
|
||||
*/
|
||||
void validateCategoryList(Collection<Long> ids);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package cn.iocoder.yudao.module.product.service.category;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryCreateReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryUpdateReqVO;
|
||||
@ -13,7 +15,9 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
@ -99,6 +103,26 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateCategoryList(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
// 获得商品分类信息
|
||||
List<ProductCategoryDO> categoryList = productCategoryMapper.selectBatchIds(ids);
|
||||
Map<Long, ProductCategoryDO> categoryMap = CollectionUtils.convertMap(categoryList, ProductCategoryDO::getId);
|
||||
// 校验
|
||||
ids.forEach(id -> {
|
||||
ProductCategoryDO category = categoryMap.get(id);
|
||||
if (category == null) {
|
||||
throw exception(CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
if (!CommonStatusEnum.ENABLE.getStatus().equals(category.getStatus())) {
|
||||
throw exception(CATEGORY_DISABLED, category.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProductCategoryDO getCategory(Long id) {
|
||||
return productCategoryMapper.selectById(id);
|
||||
|
@ -136,4 +136,14 @@ public interface ProductSpuService {
|
||||
*/
|
||||
Long getSpuCountByCategoryId(Long categoryId);
|
||||
|
||||
|
||||
/**
|
||||
* 校验商品是否有效。如下情况,视为无效:
|
||||
* 1. 商品编号不存在
|
||||
* 2. 商品被禁用
|
||||
*
|
||||
* @param ids 商品编号数组
|
||||
* @return 商品 SPU 列表
|
||||
*/
|
||||
List<ProductSpuDO> validateSpuList(Collection<Long> ids);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.product.service.spu;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
@ -139,6 +140,28 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProductSpuDO> validateSpuList(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 获得商品信息
|
||||
List<ProductSpuDO> spuList = productSpuMapper.selectBatchIds(ids);
|
||||
Map<Long, ProductSpuDO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuDO::getId);
|
||||
// 校验
|
||||
ids.forEach(id -> {
|
||||
ProductSpuDO spu = spuMap.get(id);
|
||||
if (spu == null) {
|
||||
throw exception(SPU_NOT_EXISTS);
|
||||
}
|
||||
if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) {
|
||||
throw exception(SPU_NOT_ENABLE, spu.getName());
|
||||
}
|
||||
});
|
||||
|
||||
return spuList;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteSpu(Long id) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.app.coupon;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||
@ -25,11 +24,9 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "用户 App - 优惠劵模板")
|
||||
@ -46,7 +43,6 @@ public class AppCouponTemplateController {
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
|
||||
// TODO 疯狂:这里应该还有个 list 接口哈;获得优惠劵模版列表,用于首页、商品页的优惠劵
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得优惠劵模版列表")
|
||||
@Parameters({
|
||||
@ -56,46 +52,28 @@ public class AppCouponTemplateController {
|
||||
})
|
||||
public CommonResult<List<AppCouponTemplateRespVO>> getCouponTemplateList(
|
||||
@RequestParam(value = "spuId", required = false) Long spuId,
|
||||
@RequestParam(value = "useType", required = false) Integer useType,
|
||||
@RequestParam(value = "productScope", required = false) Integer productScope,
|
||||
@RequestParam(value = "count", required = false, defaultValue = "10") Integer count) {
|
||||
List<AppCouponTemplateRespVO> list = new ArrayList<>();
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
AppCouponTemplateRespVO vo = new AppCouponTemplateRespVO();
|
||||
vo.setId(i + 1L);
|
||||
vo.setName("优惠劵" + (i + 1));
|
||||
vo.setTakeLimitCount(random.nextInt(10) + 1);
|
||||
vo.setUsePrice(random.nextInt(100) * 100);
|
||||
vo.setValidityType(random.nextInt(2) + 1);
|
||||
if (vo.getValidityType() == 1) {
|
||||
vo.setValidStartTime(LocalDateTime.now().plusDays(random.nextInt(10)));
|
||||
vo.setValidEndTime(LocalDateTime.now().plusDays(random.nextInt(20) + 10));
|
||||
} else {
|
||||
vo.setFixedStartTerm(random.nextInt(10));
|
||||
vo.setFixedEndTerm(random.nextInt(10) + vo.getFixedStartTerm() + 1);
|
||||
}
|
||||
vo.setDiscountType(random.nextInt(2) + 1);
|
||||
if (vo.getDiscountType() == 1) {
|
||||
vo.setDiscountPercent(null);
|
||||
vo.setDiscountPrice(random.nextInt(50) * 100);
|
||||
vo.setDiscountLimitPrice(null);
|
||||
} else {
|
||||
vo.setDiscountPercent(random.nextInt(90) + 10);
|
||||
vo.setDiscountPrice(null);
|
||||
vo.setDiscountLimitPrice(random.nextInt(200) * 100);
|
||||
}
|
||||
// TODO @疯狂:是否已领取,要不在 TemplateService 搞个 static 方法,让它基于 countMap 这种去计算,这样好点?
|
||||
vo.setTakeStatus(random.nextBoolean());
|
||||
list.add(vo);
|
||||
}
|
||||
return success(list);
|
||||
// 1.1 处理查询条件:商品范围编号
|
||||
Long productScopeValue = getProductScopeValue(productScope, spuId);
|
||||
// 1.2 处理查询条件:领取方式 = 直接领取
|
||||
List<Integer> canTakeTypes = Collections.singletonList(CouponTakeTypeEnum.USER.getValue());
|
||||
|
||||
// 2. 查询
|
||||
List<CouponTemplateDO> list = couponTemplateService.getCouponTemplateList(canTakeTypes, productScope,
|
||||
productScopeValue, count);
|
||||
|
||||
// 3.1 领取数量
|
||||
Map<Long, Boolean> canCanTakeMap = couponService.getUserCanCanTakeMap(getLoginUserId(), list);
|
||||
// 3.2 拼接返回
|
||||
return success(CouponTemplateConvert.INSTANCE.convertAppList(list, canCanTakeMap));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得优惠劵模版分页")
|
||||
public CommonResult<PageResult<AppCouponTemplateRespVO>> getCouponTemplatePage(AppCouponTemplatePageReqVO pageReqVO) {
|
||||
// 1.1 处理查询条件:商品范围编号
|
||||
Long productScopeValue = getProductScopeValue(pageReqVO);
|
||||
Long productScopeValue = getProductScopeValue(pageReqVO.getProductScope(), pageReqVO.getSpuId());
|
||||
// 1.2 处理查询条件:领取方式 = 直接领取
|
||||
List<Integer> canTakeTypes = Collections.singletonList(CouponTakeTypeEnum.USER.getValue());
|
||||
|
||||
@ -104,35 +82,30 @@ public class AppCouponTemplateController {
|
||||
CouponTemplateConvert.INSTANCE.convert(pageReqVO, canTakeTypes, pageReqVO.getProductScope(), productScopeValue));
|
||||
|
||||
// 3.1 领取数量
|
||||
Map<Long, Integer> couponTakeCountMap = new HashMap<>(0);
|
||||
Long userId = getLoginUserId();
|
||||
if (userId != null) {
|
||||
List<Long> templateIds = convertList(pageResult.getList(), CouponTemplateDO::getId,
|
||||
t -> ObjUtil.notEqual(t.getTakeLimitCount(), -1)); // 只查有设置“每人限领个数”的
|
||||
couponTakeCountMap = couponService.getTakeCountMapByTemplateIds(templateIds, userId);
|
||||
}
|
||||
Map<Long, Boolean> canCanTakeMap = couponService.getUserCanCanTakeMap(getLoginUserId(), pageResult.getList());
|
||||
// 3.2 拼接返回
|
||||
return success(CouponTemplateConvert.INSTANCE.convertAppPage(pageResult, couponTakeCountMap));
|
||||
return success(CouponTemplateConvert.INSTANCE.convertAppPage(pageResult, canCanTakeMap));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得分页查询的商品范围
|
||||
* 获得商品的使用范围编号
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 商品范围
|
||||
* @param productScope 商品范围
|
||||
* @param spuId 商品 SPU 编号
|
||||
* @return 商品范围编号
|
||||
*/
|
||||
private Long getProductScopeValue(AppCouponTemplatePageReqVO pageReqVO) {
|
||||
// 通用券:清除商品范围
|
||||
if (pageReqVO.getProductScope() == null || ObjectUtils.equalsAny(pageReqVO.getProductScope(), PromotionProductScopeEnum.ALL.getScope(), null)) {
|
||||
private Long getProductScopeValue(Integer productScope, Long spuId) {
|
||||
// 通用券:没有商品范围
|
||||
if (productScope == null || ObjectUtils.equalsAny(productScope, PromotionProductScopeEnum.ALL.getScope(), null)) {
|
||||
return null;
|
||||
}
|
||||
// 品类券:查询商品的品类
|
||||
if (Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.CATEGORY.getScope()) && pageReqVO.getSpuId() != null) {
|
||||
return Optional.ofNullable(productSpuApi.getSpu(pageReqVO.getSpuId()))
|
||||
// 品类券:查询商品的品类编号
|
||||
if (Objects.equals(productScope, PromotionProductScopeEnum.CATEGORY.getScope()) && spuId != null) {
|
||||
return Optional.ofNullable(productSpuApi.getSpu(spuId))
|
||||
.map(ProductSpuRespDTO::getCategoryId).orElse(null);
|
||||
}
|
||||
// 商品卷:直接返回
|
||||
return pageReqVO.getSpuId();
|
||||
return spuId;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public class AppCouponTemplateRespVO {
|
||||
|
||||
// ========== 用户相关字段 ==========
|
||||
|
||||
@Schema(description = "是否已领取", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean takeStatus;
|
||||
@Schema(description = "是否可以领取", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean canTake;
|
||||
|
||||
}
|
||||
|
@ -37,21 +37,25 @@ public interface CouponTemplateConvert {
|
||||
|
||||
PageResult<AppCouponTemplateRespVO> convertAppPage(PageResult<CouponTemplateDO> pageResult);
|
||||
|
||||
default PageResult<AppCouponTemplateRespVO> convertAppPage(PageResult<CouponTemplateDO> pageResult, Map<Long, Integer> couponTakeCountMap) {
|
||||
List<AppCouponTemplateRespVO> convertAppList(List<CouponTemplateDO> list);
|
||||
|
||||
default PageResult<AppCouponTemplateRespVO> convertAppPage(PageResult<CouponTemplateDO> pageResult, Map<Long, Boolean> userCanTakeMap) {
|
||||
PageResult<AppCouponTemplateRespVO> result = convertAppPage(pageResult);
|
||||
if (MapUtil.isEmpty(couponTakeCountMap)) {
|
||||
return result;
|
||||
}
|
||||
for (AppCouponTemplateRespVO template : result.getList()) {
|
||||
// 每人领取数量无限制
|
||||
if (template.getTakeLimitCount() == -1) {
|
||||
template.setTakeStatus(false);
|
||||
continue;
|
||||
}
|
||||
// 检查已领取数量是否超过限领数量
|
||||
template.setTakeStatus(MapUtil.getInt(couponTakeCountMap, template.getId(), 0) >= template.getTakeLimitCount());
|
||||
}
|
||||
copyTo(result.getList(), userCanTakeMap);
|
||||
return result;
|
||||
}
|
||||
|
||||
default List<AppCouponTemplateRespVO> convertAppList(List<CouponTemplateDO> list, Map<Long, Boolean> userCanTakeMap) {
|
||||
List<AppCouponTemplateRespVO> result = convertAppList(list);
|
||||
copyTo(result, userCanTakeMap);
|
||||
return result;
|
||||
}
|
||||
|
||||
default void copyTo(List<AppCouponTemplateRespVO> list, Map<Long, Boolean> userCanTakeMap) {
|
||||
for (AppCouponTemplateRespVO template : list) {
|
||||
// 检查已领取数量是否超过限领数量
|
||||
template.setCanTake(MapUtil.getBool(userCanTakeMap, template.getId(), false));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package cn.iocoder.yudao.module.promotion.dal.mysql.coupon;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
@ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.service.coupon.bo.CouponTakeCountBO;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.github.yulichang.toolkit.MPJWrappers;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
@ -16,9 +15,12 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
|
||||
/**
|
||||
* 优惠劵 Mapper
|
||||
*
|
||||
@ -70,14 +72,16 @@ public interface CouponMapper extends BaseMapperX<CouponDO> {
|
||||
);
|
||||
}
|
||||
|
||||
// TODO @疯狂:这个是不是搞个 Map 就可以呀?
|
||||
default List<CouponTakeCountBO> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) {
|
||||
return BeanUtil.copyToList(selectMaps(MPJWrappers.lambdaJoin(CouponDO.class)
|
||||
.select(CouponDO::getTemplateId)
|
||||
.selectCount(CouponDO::getId, CouponTakeCountBO::getCount)
|
||||
default Map<Long, Integer> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) {
|
||||
String templateIdAlias = "templateId";
|
||||
String countAlias = "count";
|
||||
List<Map<String, Object>> list = selectMaps(MPJWrappers.lambdaJoin(CouponDO.class)
|
||||
.selectAs(CouponDO::getTemplateId, templateIdAlias)
|
||||
.selectCount(CouponDO::getId, countAlias)
|
||||
.eq(CouponDO::getUserId, userId)
|
||||
.in(CouponDO::getTemplateId, templateIds)
|
||||
.groupBy(CouponDO::getTemplateId)), CouponTakeCountBO.class);
|
||||
.groupBy(CouponDO::getTemplateId));
|
||||
return convertMap(list, map -> MapUtil.getLong(map, templateIdAlias), map -> MapUtil.getInt(map, countAlias));
|
||||
}
|
||||
|
||||
default List<CouponDO> selectListByUserIdAndStatusAndUsePriceLeAndProductScope(
|
||||
|
@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@ -23,16 +24,8 @@ import java.util.function.Consumer;
|
||||
public interface CouponTemplateMapper extends BaseMapperX<CouponTemplateDO> {
|
||||
|
||||
default PageResult<CouponTemplateDO> selectPage(CouponTemplatePageReqVO reqVO) {
|
||||
// 构建可领取的查询条件, 好啰嗦 ( ╯-_-)╯┴—┴
|
||||
Consumer<LambdaQueryWrapper<CouponTemplateDO>> canTakeConsumer = null;
|
||||
if (CollUtil.isNotEmpty(reqVO.getCanTakeTypes())) {
|
||||
canTakeConsumer = w ->
|
||||
w.eq(CouponTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) // 1. 状态为可用的
|
||||
.in(CouponTemplateDO::getTakeType, reqVO.getCanTakeTypes()) // 2. 领取方式一致
|
||||
.and(ww -> ww.isNull(CouponTemplateDO::getValidEndTime) // 3. 未过期
|
||||
.or().gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now()))
|
||||
.apply(" take_count < total_count "); // 4. 剩余数量大于 0
|
||||
}
|
||||
// 构建可领取的查询条件
|
||||
Consumer<LambdaQueryWrapper<CouponTemplateDO>> canTakeConsumer = buildCanTakeQueryConsumer(reqVO.getCanTakeTypes());
|
||||
// 执行分页查询
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<CouponTemplateDO>()
|
||||
.likeIfPresent(CouponTemplateDO::getName, reqVO.getName())
|
||||
@ -48,4 +41,33 @@ public interface CouponTemplateMapper extends BaseMapperX<CouponTemplateDO> {
|
||||
|
||||
void updateTakeCount(@Param("id") Long id, @Param("incrCount") Integer incrCount);
|
||||
|
||||
default List<CouponTemplateDO> selectListByTakeType(Integer takeType) {
|
||||
return selectList(CouponTemplateDO::getTakeType, takeType);
|
||||
}
|
||||
|
||||
default List<CouponTemplateDO> selectList(List<Integer> canTakeTypes, Integer productScope, Long productScopeValue, Integer count) {
|
||||
// 构建可领取的查询条件
|
||||
Consumer<LambdaQueryWrapper<CouponTemplateDO>> canTakeConsumer = buildCanTakeQueryConsumer(canTakeTypes);
|
||||
return selectList(new LambdaQueryWrapperX<CouponTemplateDO>()
|
||||
.eqIfPresent(CouponTemplateDO::getProductScope, productScope)
|
||||
.and(productScopeValue != null, w -> w.apply("FIND_IN_SET({0}, product_scope_values)",
|
||||
productScopeValue))
|
||||
.and(canTakeConsumer != null, canTakeConsumer)
|
||||
.last(" LIMIT " + count)
|
||||
.orderByDesc(CouponTemplateDO::getId));
|
||||
}
|
||||
|
||||
static Consumer<LambdaQueryWrapper<CouponTemplateDO>> buildCanTakeQueryConsumer(List<Integer> canTakeTypes) {
|
||||
Consumer<LambdaQueryWrapper<CouponTemplateDO>> canTakeConsumer = null;
|
||||
if (CollUtil.isNotEmpty(canTakeTypes)) {
|
||||
canTakeConsumer = w ->
|
||||
w.eq(CouponTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) // 1. 状态为可用的
|
||||
.in(CouponTemplateDO::getTakeType, canTakeTypes) // 2. 领取方式一致
|
||||
.and(ww -> ww.isNull(CouponTemplateDO::getValidEndTime) // 3. 未过期
|
||||
.or().gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now()))
|
||||
.apply(" take_count < total_count "); // 4. 剩余数量大于 0
|
||||
}
|
||||
return canTakeConsumer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package cn.iocoder.yudao.module.promotion.mq.consumer.coupon;
|
||||
|
||||
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
|
||||
import cn.iocoder.yudao.module.member.mq.message.user.RegisterCouponSendMessage;
|
||||
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 针对 {@link RegisterCouponSendMessage} 的消费者
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RegisterCouponSendConsumer extends AbstractStreamMessageListener<RegisterCouponSendMessage> {
|
||||
|
||||
@Resource
|
||||
private CouponService couponService;
|
||||
|
||||
@Override
|
||||
public void onMessage(RegisterCouponSendMessage message) {
|
||||
log.info("[onMessage][消息内容({})]", message);
|
||||
couponService.takeCouponByRegister(message.getUserId());
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +1,16 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.coupon;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.service.coupon.bo.CouponTakeCountBO;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
|
||||
/**
|
||||
* 优惠劵 Service 接口
|
||||
*
|
||||
@ -119,12 +118,9 @@ public interface CouponService {
|
||||
/**
|
||||
* 【系统】给用户发送新人券
|
||||
*
|
||||
* @param templateId 优惠券模板编号
|
||||
* @param userId 用户编号列表
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
default void takeCouponByRegister(Long templateId, Long userId) {
|
||||
takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.REGISTER);
|
||||
}
|
||||
void takeCouponByRegister(Long userId);
|
||||
|
||||
/**
|
||||
* 获取会员领取指定优惠券的数量
|
||||
@ -134,11 +130,8 @@ public interface CouponService {
|
||||
* @return 领取优惠券的数量
|
||||
*/
|
||||
default Integer getTakeCount(Long templateId, Long userId) {
|
||||
return CollUtil.emptyIfNull(getTakeCountListByTemplateIds(Collections.singleton(templateId), userId))
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(CouponTakeCountBO::getCount)
|
||||
.orElse(0);
|
||||
Map<Long, Integer> map = getTakeCountMapByTemplateIds(Collections.singleton(templateId), userId);
|
||||
return MapUtil.getInt(map, templateId, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,19 +141,7 @@ public interface CouponService {
|
||||
* @param userId 用户编号
|
||||
* @return 领取优惠券的数量
|
||||
*/
|
||||
default Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId) {
|
||||
return convertMap(getTakeCountListByTemplateIds(templateIds, userId),
|
||||
CouponTakeCountBO::getTemplateId, CouponTakeCountBO::getCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计会员领取优惠券的数量
|
||||
*
|
||||
* @param templateIds 优惠券模板编号列表
|
||||
* @param userId 用户编号
|
||||
* @return 领取优惠券的数量
|
||||
*/
|
||||
List<CouponTakeCountBO> getTakeCountListByTemplateIds(Collection<Long> templateIds, Long userId);
|
||||
Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户匹配的优惠券列表
|
||||
@ -178,4 +159,13 @@ public interface CouponService {
|
||||
*/
|
||||
int expireCoupon();
|
||||
|
||||
/**
|
||||
* 获取用户是否可以领取优惠券
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param templates 优惠券列表
|
||||
* @return 是否可以领取
|
||||
*/
|
||||
Map<Long, Boolean> getUserCanCanTakeMap(Long userId, List<CouponTemplateDO> templates);
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.service.coupon;
|
||||
|
||||
import cn.hutool.core.collection.CollStreamUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@ -21,7 +20,6 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponMapper;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.service.coupon.bo.CouponTakeCountBO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@ -29,18 +27,14 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
// TODO @疯狂:注册时,赠送用户优惠劵;为了解耦,可以考虑注册时发个 MQ 消息;然后营销这里监听后消费;
|
||||
/**
|
||||
* 优惠劵 Service 实现类
|
||||
*
|
||||
@ -184,9 +178,17 @@ public class CouponServiceImpl implements CouponService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CouponTakeCountBO> getTakeCountListByTemplateIds(Collection<Long> templateIds, Long userId) {
|
||||
public void takeCouponByRegister(Long userId) {
|
||||
List<CouponTemplateDO> templates = couponTemplateService.getCouponTemplateByTakeType(CouponTakeTypeEnum.REGISTER);
|
||||
for (CouponTemplateDO template : templates) {
|
||||
takeCoupon(template.getId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.REGISTER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId) {
|
||||
if (CollUtil.isEmpty(templateIds)) {
|
||||
return ListUtil.empty();
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return couponMapper.selectCountByUserIdAndTemplateIdIn(userId, templateIds);
|
||||
}
|
||||
@ -222,6 +224,29 @@ public class CouponServiceImpl implements CouponService {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, Boolean> getUserCanCanTakeMap(Long userId, List<CouponTemplateDO> templates) {
|
||||
Map<Long, Boolean> userCanTakeMap = convertMap(templates, CouponTemplateDO::getId, templateId -> true);
|
||||
// 未登录时,都显示可以领取
|
||||
if (userId == null) {
|
||||
return userCanTakeMap;
|
||||
}
|
||||
|
||||
// 过滤领取数量无限制的
|
||||
Set<Long> templateIds = convertSet(templates, CouponTemplateDO::getId, template -> template.getTakeLimitCount() != -1);
|
||||
|
||||
// 检查用户领取的数量是否超过限制
|
||||
if (CollUtil.isNotEmpty(templateIds)) {
|
||||
Map<Long, Integer> couponTakeCountMap = this.getTakeCountMapByTemplateIds(templateIds, userId);
|
||||
for (CouponTemplateDO template : templates) {
|
||||
Integer takeCount = couponTakeCountMap.get(template.getId());
|
||||
userCanTakeMap.put(template.getId(), takeCount == null || takeCount < template.getTakeLimitCount());
|
||||
}
|
||||
}
|
||||
|
||||
return userCanTakeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过期单个优惠劵
|
||||
*
|
||||
|
@ -5,8 +5,10 @@ import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.Cou
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 优惠劵模板 Service 接口
|
||||
@ -69,4 +71,24 @@ public interface CouponTemplateService {
|
||||
*/
|
||||
void updateCouponTemplateTakeCount(Long id, int incrCount);
|
||||
|
||||
/**
|
||||
* 获得指定领取方式的优惠券模板
|
||||
*
|
||||
* @param takeType 领取方式
|
||||
* @return 优惠券模板列表
|
||||
*/
|
||||
List<CouponTemplateDO> getCouponTemplateByTakeType(CouponTakeTypeEnum takeType);
|
||||
|
||||
/**
|
||||
* 获得优惠券模板列表
|
||||
*
|
||||
* @param canTakeTypes 可领取的类型列表
|
||||
* @param productScope 商品使用范围类型
|
||||
* @param productScopeValue 商品使用范围编号
|
||||
* @param count 查询数量
|
||||
* @return 优惠券模板列表
|
||||
*/
|
||||
List<CouponTemplateDO> getCouponTemplateList(List<Integer> canTakeTypes, Integer productScope,
|
||||
Long productScopeValue, Integer count);
|
||||
|
||||
}
|
||||
|
@ -2,16 +2,22 @@ package cn.iocoder.yudao.module.promotion.service.coupon;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
|
||||
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_NOT_EXISTS;
|
||||
@ -29,9 +35,15 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
||||
@Resource
|
||||
private CouponTemplateMapper couponTemplateMapper;
|
||||
|
||||
// TODO @疯狂:新增/修改时,需要校验对应的商品、分类是否存在
|
||||
@Resource
|
||||
private ProductCategoryApi productCategoryApi;
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
|
||||
@Override
|
||||
public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) {
|
||||
// 校验商品范围
|
||||
validateProductScope(createReqVO.getProductScope(), createReqVO.getProductScopeValues());
|
||||
// 插入
|
||||
CouponTemplateDO couponTemplate = CouponTemplateConvert.INSTANCE.convert(createReqVO)
|
||||
.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
@ -48,6 +60,8 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
||||
if (updateReqVO.getTotalCount() < couponTemplate.getTakeCount()) {
|
||||
throw exception(COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL, couponTemplate.getTakeCount());
|
||||
}
|
||||
// 校验商品范围
|
||||
validateProductScope(updateReqVO.getProductScope(), updateReqVO.getProductScopeValues());
|
||||
|
||||
// 更新
|
||||
CouponTemplateDO updateObj = CouponTemplateConvert.INSTANCE.convert(updateReqVO);
|
||||
@ -78,6 +92,14 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
||||
return couponTemplate;
|
||||
}
|
||||
|
||||
private void validateProductScope(Integer productScope, List<Long> productScopeValues) {
|
||||
if (Objects.equals(PromotionProductScopeEnum.SPU.getScope(), productScope)) {
|
||||
productSpuApi.validateSpuList(productScopeValues);
|
||||
} else if (Objects.equals(PromotionProductScopeEnum.CATEGORY.getScope(), productScope)) {
|
||||
productCategoryApi.validateCategoryList(productScopeValues);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CouponTemplateDO getCouponTemplate(Long id) {
|
||||
return couponTemplateMapper.selectById(id);
|
||||
@ -93,4 +115,15 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
|
||||
couponTemplateMapper.updateTakeCount(id, incrCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CouponTemplateDO> getCouponTemplateByTakeType(CouponTakeTypeEnum takeType) {
|
||||
return couponTemplateMapper.selectListByTakeType(takeType.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CouponTemplateDO> getCouponTemplateList(List<Integer> canTakeTypes, Integer productScope,
|
||||
Long productScopeValue, Integer count) {
|
||||
return couponTemplateMapper.selectList(canTakeTypes, productScope, productScopeValue, count);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.coupon.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 优惠券领取数量 BO
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
@Data
|
||||
public class CouponTakeCountBO {
|
||||
|
||||
/**
|
||||
* 优惠劵模板编号
|
||||
*/
|
||||
private Long templateId;
|
||||
/**
|
||||
* 领取数量
|
||||
*/
|
||||
private Integer count;
|
||||
|
||||
}
|
@ -32,7 +32,6 @@ public class TradeStatisticsController {
|
||||
@Resource
|
||||
private TradeStatisticsService tradeStatisticsService;
|
||||
|
||||
// TODO @疯狂:要不这个就是 /trend/summary 的特例,前端自己查询两次?
|
||||
@GetMapping("/summary")
|
||||
@Operation(summary = "获得交易统计")
|
||||
@PreAuthorize("@ss.hasPermission('statistics:trade:query')")
|
||||
@ -40,7 +39,6 @@ public class TradeStatisticsController {
|
||||
return success(tradeStatisticsService.getTradeSummaryComparison());
|
||||
}
|
||||
|
||||
// TODO @疯狂:直接 comparison?主要 trend 和 comparison 二选一,一个是数据趋势,一个是数据对比哈;
|
||||
@GetMapping("/trend/summary")
|
||||
@Operation(summary = "获得交易状况统计")
|
||||
@PreAuthorize("@ss.hasPermission('statistics:trade:query')")
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.statistics.service.trade;
|
||||
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
||||
import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeStatisticsComparisonRespVO;
|
||||
import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeSummaryRespVO;
|
||||
import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeTrendSummaryRespVO;
|
||||
@ -13,8 +14,6 @@ import org.springframework.validation.annotation.Validated;
|
||||
import javax.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -79,18 +78,9 @@ public class TradeStatisticsServiceImpl implements TradeStatisticsService {
|
||||
* @return 交易数据
|
||||
*/
|
||||
private TradeSummaryRespBO getTradeSummaryByMonths(int months) {
|
||||
// TODO @疯狂:可以在 LocalDateUtils 封装方法;获得月份的开始;以及结束两个方法;然后这里就可以直接调用了
|
||||
// 月份开始时间
|
||||
LocalDateTime beginOfMonth = LocalDateTime.now()
|
||||
.plusMonths(months)
|
||||
.with(TemporalAdjusters.firstDayOfMonth())
|
||||
.with(LocalTime.MIN);
|
||||
// 月份截止时间
|
||||
LocalDateTime endOfToday = LocalDateTime.now()
|
||||
.plusMonths(months)
|
||||
.with(TemporalAdjusters.lastDayOfMonth())
|
||||
.with(LocalTime.MAX);
|
||||
return tradeStatisticsMapper.selectOrderCreateCountSumAndOrderPayPriceSumByTimeBetween(beginOfMonth, endOfToday);
|
||||
LocalDateTime monthDate = LocalDateTime.now().plusMonths(months);
|
||||
return tradeStatisticsMapper.selectOrderCreateCountSumAndOrderPayPriceSumByTimeBetween(
|
||||
LocalDateTimeUtils.beginOfMonth(monthDate), LocalDateTimeUtils.endOfMonth(monthDate));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageRecordConvert;
|
||||
import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageUserConvert;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
|
||||
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
|
||||
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService;
|
||||
@ -84,7 +85,7 @@ public class AppBrokerageUserController {
|
||||
LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(yesterday);
|
||||
LocalDateTime endTime = LocalDateTimeUtil.endOfDay(yesterday);
|
||||
Integer yesterdayPrice = brokerageRecordService.getSummaryPriceByUserId(brokerageUser.getId(),
|
||||
BrokerageRecordBizTypeEnum.ORDER.getType(), beginTime, endTime);
|
||||
BrokerageRecordBizTypeEnum.ORDER, BrokerageRecordStatusEnum.SETTLEMENT, beginTime, endTime);
|
||||
// 统计用户提现的佣金
|
||||
Integer withdrawPrice = brokerageWithdrawService.getWithdrawSummaryListByUserId(Collections.singleton(brokerageUser.getId()),
|
||||
BrokerageWithdrawStatusEnum.AUDIT_SUCCESS).stream()
|
||||
|
@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokera
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryRespBO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.MappingTarget;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
@ -88,8 +87,8 @@ public interface BrokerageUserConvert {
|
||||
return respVO;
|
||||
}
|
||||
|
||||
default void copyTo(IPage<AppBrokerageUserChildSummaryRespVO> pageResult, Map<Long, MemberUserRespDTO> userMap) {
|
||||
for (AppBrokerageUserChildSummaryRespVO vo : pageResult.getRecords()) {
|
||||
default void copyTo(List<AppBrokerageUserChildSummaryRespVO> list, Map<Long, MemberUserRespDTO> userMap) {
|
||||
for (AppBrokerageUserChildSummaryRespVO vo : list) {
|
||||
Optional.ofNullable(userMap.get(vo.getId())).ifPresent(user ->
|
||||
vo.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.order;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
|
||||
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
|
||||
@ -105,7 +107,12 @@ public class TradeOrderDO extends BaseDO {
|
||||
*/
|
||||
private Boolean commentStatus;
|
||||
|
||||
// TODO @疯狂:加一个推广人编号;
|
||||
/**
|
||||
* 推广人编号
|
||||
* {@link BrokerageUserDO#getId()}
|
||||
* {@link MemberUserRespDTO#getId()}
|
||||
*/
|
||||
private Long brokerageUserId;
|
||||
|
||||
// ========== 价格 + 支付基本信息 ==========
|
||||
|
||||
|
@ -80,10 +80,11 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
|
||||
}
|
||||
|
||||
@Select("SELECT SUM(price) FROM trade_brokerage_record " +
|
||||
"WHERE user_id = #{userId} AND biz_type = #{bizType} " +
|
||||
"AND create_time BETWEEN #{beginTime} AND #{endTime} AND deleted = FALSE")
|
||||
"WHERE user_id = #{userId} AND biz_type = #{bizType} AND status = #{status} " +
|
||||
"AND unfreeze_time BETWEEN #{beginTime} AND #{endTime} AND deleted = FALSE")
|
||||
Integer selectSummaryPriceByUserIdAndBizTypeAndCreateTimeBetween(@Param("userId") Long userId,
|
||||
@Param("bizType") Integer bizType,
|
||||
@Param("status") Integer status,
|
||||
@Param("beginTime") LocalDateTime beginTime,
|
||||
@Param("endTime") LocalDateTime endTime);
|
||||
|
||||
@ -98,4 +99,13 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
|
||||
@Param("beginTime") LocalDateTime beginTime,
|
||||
@Param("endTime") LocalDateTime endTime);
|
||||
|
||||
@Select("SELECT COUNT(1) FROM trade_brokerage_record " +
|
||||
"WHERE biz_type = #{bizType} AND status = #{status} AND deleted = FALSE " +
|
||||
"AND unfreeze_time BETWEEN #{beginTime} AND #{endTime} " +
|
||||
"GROUP BY user_id HAVING SUM(price) > #{brokeragePrice}")
|
||||
Integer selectCountByPriceGt(@Param("brokeragePrice") Integer brokeragePrice,
|
||||
@Param("bizType") Integer bizType,
|
||||
@Param("status") Integer status,
|
||||
@Param("beginTime") LocalDateTime beginTime,
|
||||
@Param("endTime") LocalDateTime endTime);
|
||||
}
|
||||
|
@ -138,13 +138,35 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
|
||||
@Param("beginTime") LocalDateTime beginTime,
|
||||
@Param("endTime") LocalDateTime endTime);
|
||||
|
||||
/**
|
||||
* 下级分销统计(分页)
|
||||
*
|
||||
* @param bizType 业务类型
|
||||
* @param status 状态
|
||||
* @param bindUserIds 绑定用户编号列表
|
||||
* @param sortingField 排序字段
|
||||
* @return 下级分销统计分页列表
|
||||
*/
|
||||
IPage<AppBrokerageUserChildSummaryRespVO> selectSummaryPageByUserId(Page<?> page,
|
||||
@Param("ids") List<Long> ids, // BrokerageUser 的 ids 数组
|
||||
@Param("bizType") Integer bizType,
|
||||
@Param("status") Integer status,
|
||||
@Param("bindUserIds") List<Long> bindUserIds,
|
||||
@Param("sortingField") SortingField sortingField);
|
||||
|
||||
/**
|
||||
* 下级分销统计(不分页)
|
||||
*
|
||||
* @param bizType 业务类型
|
||||
* @param status 状态
|
||||
* @param bindUserIds 绑定用户编号列表
|
||||
* @param sortingField 排序字段
|
||||
* @return 下级分销统计列表
|
||||
*/
|
||||
List<AppBrokerageUserChildSummaryRespVO> selectSummaryListByUserId(@Param("bizType") Integer bizType,
|
||||
@Param("status") Integer status,
|
||||
@Param("bindUserIds") List<Long> bindUserIds,
|
||||
@Param("sortingField") SortingField sortingField);
|
||||
|
||||
default List<BrokerageUserDO> selectListByBindUserId(Long bindUserId) {
|
||||
return selectList(BrokerageUserDO::getBindUserId, bindUserId);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokera
|
||||
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankPageReqVO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO;
|
||||
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryRespBO;
|
||||
|
||||
@ -120,11 +121,13 @@ public interface BrokerageRecordService {
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param bizType 业务类型
|
||||
* @param status 状态
|
||||
* @param beginTime 开始时间
|
||||
* @param endTime 截止时间
|
||||
* @return 用户佣金合计
|
||||
*/
|
||||
Integer getSummaryPriceByUserId(Long userId, Integer bizType, LocalDateTime beginTime, LocalDateTime endTime);
|
||||
Integer getSummaryPriceByUserId(Long userId, BrokerageRecordBizTypeEnum bizType, BrokerageRecordStatusEnum status,
|
||||
LocalDateTime beginTime, LocalDateTime endTime);
|
||||
|
||||
/**
|
||||
* 获得用户佣金排行分页列表(基于佣金总数)
|
||||
|
@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.trade.service.brokerage;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.*;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
|
||||
@ -265,9 +262,10 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getSummaryPriceByUserId(Long userId, Integer bizType, LocalDateTime beginTime, LocalDateTime endTime) {
|
||||
return brokerageRecordMapper.selectSummaryPriceByUserIdAndBizTypeAndCreateTimeBetween(userId, bizType,
|
||||
beginTime, endTime);
|
||||
public Integer getSummaryPriceByUserId(Long userId, BrokerageRecordBizTypeEnum bizType, BrokerageRecordStatusEnum status,
|
||||
LocalDateTime beginTime, LocalDateTime endTime) {
|
||||
return brokerageRecordMapper.selectSummaryPriceByUserIdAndBizTypeAndCreateTimeBetween(userId,
|
||||
bizType.getType(), status.getStatus(), beginTime, endTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -279,17 +277,18 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
|
||||
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
|
||||
}
|
||||
|
||||
// TODO @疯狂:这个要不我们先做精准的?先查询自己的推广金额,然后查询比该金额多的有多少人?
|
||||
@Override
|
||||
public Integer getUserRankByPrice(Long userId, LocalDateTime[] times) {
|
||||
AppBrokerageUserRankPageReqVO pageParam = new AppBrokerageUserRankPageReqVO().setTimes(times);
|
||||
// 取前 100 名
|
||||
pageParam.setPageSize(100);
|
||||
PageResult<AppBrokerageUserRankByPriceRespVO> pageResult = getBrokerageUserChildSummaryPageByPrice(pageParam);
|
||||
// 获得索引
|
||||
int index = CollUtil.indexOf(pageResult.getList(), user -> Objects.equals(userId, user.getId()));
|
||||
// 用户的推广金额
|
||||
Integer price = brokerageRecordMapper.selectSummaryPriceByUserIdAndBizTypeAndCreateTimeBetween(userId,
|
||||
BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus(),
|
||||
ArrayUtil.get(times, 0), ArrayUtil.get(times, 1));
|
||||
// 排在用户前面的人数
|
||||
Integer greaterCount = brokerageRecordMapper.selectCountByPriceGt(price,
|
||||
BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus(),
|
||||
ArrayUtil.get(times, 0), ArrayUtil.get(times, 1));
|
||||
// 获得排名
|
||||
return index + 1;
|
||||
return ObjUtil.defaultIfNull(greaterCount, 0) + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,6 +31,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
@ -225,25 +226,66 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
|
||||
|
||||
@Override
|
||||
public PageResult<AppBrokerageUserChildSummaryRespVO> getBrokerageUserChildSummaryPage(AppBrokerageUserChildSummaryPageReqVO pageReqVO, Long userId) {
|
||||
// 1.1 根据昵称过滤用户
|
||||
List<Long> ids = StrUtil.isBlank(pageReqVO.getNickname())
|
||||
? Collections.emptyList()
|
||||
: convertList(memberUserApi.getUserListByNickname(pageReqVO.getNickname()), MemberUserRespDTO::getId);
|
||||
// 1.2 生成推广员编号列表
|
||||
// TODO @疯狂:是不是可以先 1.2 查询出来,然后查询对应的昵称,进行过滤?避免昵称过滤返回的 id 过多;
|
||||
// 生成推广员编号列表
|
||||
List<Long> bindUserIds = buildBindUserIdsByLevel(userId, pageReqVO.getLevel());
|
||||
|
||||
// 2. 分页查询
|
||||
IPage<AppBrokerageUserChildSummaryRespVO> pageResult = brokerageUserMapper.selectSummaryPageByUserId(
|
||||
MyBatisUtils.buildPage(pageReqVO), ids, BrokerageRecordBizTypeEnum.ORDER.getType(),
|
||||
BrokerageRecordStatusEnum.SETTLEMENT.getStatus(), bindUserIds, pageReqVO.getSortingField()
|
||||
);
|
||||
// 情况一:没有昵称过滤条件时,直接使用数据库的分页查询
|
||||
if (StrUtil.isBlank(pageReqVO.getNickname())) {
|
||||
// 1.1 分页查询
|
||||
IPage<AppBrokerageUserChildSummaryRespVO> pageResult = brokerageUserMapper.selectSummaryPageByUserId(
|
||||
MyBatisUtils.buildPage(pageReqVO), BrokerageRecordBizTypeEnum.ORDER.getType(),
|
||||
BrokerageRecordStatusEnum.SETTLEMENT.getStatus(), bindUserIds, pageReqVO.getSortingField()
|
||||
);
|
||||
|
||||
// 3. 拼接数据并返回
|
||||
List<Long> userIds = convertList(pageResult.getRecords(), AppBrokerageUserChildSummaryRespVO::getId);
|
||||
Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
|
||||
BrokerageUserConvert.INSTANCE.copyTo(pageResult, userMap);
|
||||
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
|
||||
// 1.2 拼接数据并返回
|
||||
List<Long> userIds = convertList(pageResult.getRecords(), AppBrokerageUserChildSummaryRespVO::getId);
|
||||
Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
|
||||
BrokerageUserConvert.INSTANCE.copyTo(pageResult.getRecords(), userMap);
|
||||
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
|
||||
}
|
||||
|
||||
// 情况二:有昵称过滤条件时,需要跨模块(Member)过滤
|
||||
// 2.1 查询所有匹配的分销用户
|
||||
List<AppBrokerageUserChildSummaryRespVO> list = brokerageUserMapper.selectSummaryListByUserId(
|
||||
BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus(),
|
||||
bindUserIds, pageReqVO.getSortingField()
|
||||
);
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
|
||||
// 2.2 查出对应的用户信息
|
||||
List<MemberUserRespDTO> users = memberUserApi.getUserList(convertList(list, AppBrokerageUserChildSummaryRespVO::getId));
|
||||
if (CollUtil.isEmpty(users)) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
|
||||
// 2.3 根据昵称过滤出用户编号
|
||||
Map<Long, MemberUserRespDTO> userMap = users.stream()
|
||||
.filter(user -> StrUtil.contains(user.getNickname(), pageReqVO.getNickname()))
|
||||
.collect(Collectors.toMap(MemberUserRespDTO::getId, dto -> dto));
|
||||
if (CollUtil.isEmpty(userMap)) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
|
||||
// 2.4 根据用户编号过滤结果
|
||||
list.removeIf(vo -> !userMap.containsKey(vo.getId()));
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
|
||||
// 2.5 处理分页
|
||||
List<AppBrokerageUserChildSummaryRespVO> result = list.stream()
|
||||
.skip((long) (pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize())
|
||||
.limit(pageReqVO.getPageSize())
|
||||
.collect(Collectors.toList());
|
||||
if (CollUtil.isEmpty(result)) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
|
||||
// 2.6 拼接数据并返回
|
||||
BrokerageUserConvert.INSTANCE.copyTo(result, userMap);
|
||||
return new PageResult<>(result, (long) list.size());
|
||||
}
|
||||
|
||||
private boolean isUserCanBind(BrokerageUserDO user) {
|
||||
|
@ -40,6 +40,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettle
|
||||
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
|
||||
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
||||
@ -54,6 +55,7 @@ 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.brokerage.BrokerageRecordService;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService;
|
||||
import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.cart.CartService;
|
||||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
||||
@ -108,6 +110,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
private DeliveryExpressService deliveryExpressService;
|
||||
@Resource
|
||||
private TradeMessageService tradeMessageService;
|
||||
@Resource
|
||||
private BrokerageUserService brokerageUserService;
|
||||
@Resource
|
||||
private BrokerageRecordService brokerageRecordService;
|
||||
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
@ -130,8 +136,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
@Resource
|
||||
private MemberPointApi memberPointApi;
|
||||
@Resource
|
||||
private BrokerageRecordService brokerageRecordService;
|
||||
@Resource
|
||||
private ProductCommentApi productCommentApi;
|
||||
|
||||
@Resource
|
||||
@ -301,6 +305,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
// 6. 插入订单日志
|
||||
TradeOrderLogUtils.setOrderInfo(order.getId(), null, order.getStatus());
|
||||
|
||||
// 7. 设置订单推广人
|
||||
BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(order.getUserId());
|
||||
if (brokerageUser != null && brokerageUser.getBindUserId() != null) {
|
||||
tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setBrokerageUserId(brokerageUser.getBindUserId()));
|
||||
}
|
||||
|
||||
// TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ 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.product.enums.spu.ProductSpuStatusEnum;
|
||||
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.calculator.TradePriceCalculator;
|
||||
@ -20,7 +19,8 @@ import java.util.Map;
|
||||
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.convertSet;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH;
|
||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_PAY_PRICE_ILLEGAL;
|
||||
|
||||
/**
|
||||
@ -82,18 +82,7 @@ public class TradePriceServiceImpl implements TradePriceService {
|
||||
|
||||
private List<ProductSpuRespDTO> checkSpuList(List<ProductSkuRespDTO> skuList) {
|
||||
// 获得商品 SPU 数组
|
||||
List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(convertSet(skuList, ProductSkuRespDTO::getSpuId));
|
||||
|
||||
// 校验商品 SPU
|
||||
spus.forEach(spu -> {
|
||||
if (spu == null) {
|
||||
throw exception(SPU_NOT_EXISTS);
|
||||
}
|
||||
if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) {
|
||||
throw exception(SPU_NOT_ENABLE);
|
||||
}
|
||||
});
|
||||
return spus;
|
||||
return productSpuApi.getSpuListAndValidate(convertSet(skuList, ProductSkuRespDTO::getSpuId));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
|
||||
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
|
||||
import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
|
||||
import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.member.api.config.MemberConfigApi;
|
||||
import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -16,7 +16,6 @@ import java.util.Optional;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
|
||||
|
||||
// TODO @疯狂:这个可以搞个单测;
|
||||
/**
|
||||
* 赠送积分的 {@link TradePriceCalculator} 实现类
|
||||
*
|
||||
@ -28,14 +27,14 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
|
||||
public class TradePointGiveCalculator implements TradePriceCalculator {
|
||||
|
||||
@Resource
|
||||
private MemberPointApi memberPointApi;
|
||||
private MemberConfigApi memberConfigApi;
|
||||
|
||||
@Override
|
||||
public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
|
||||
// 1.1 校验积分功能是否开启
|
||||
int givePointPerYuan = Optional.ofNullable(memberPointApi.getConfig())
|
||||
.filter(config -> BooleanUtil.isTrue(config.getTradeDeductEnable()))
|
||||
.map(MemberPointConfigRespDTO::getTradeGivePoint)
|
||||
int givePointPerYuan = Optional.ofNullable(memberConfigApi.getConfig())
|
||||
.filter(config -> BooleanUtil.isTrue(config.getPointTradeDeductEnable()))
|
||||
.map(MemberConfigRespDTO::getPointTradeGivePoint)
|
||||
.orElse(0);
|
||||
if (givePointPerYuan <= 0) {
|
||||
return;
|
||||
|
@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
|
||||
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
|
||||
import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.member.api.config.MemberConfigApi;
|
||||
import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
|
||||
@ -20,7 +20,6 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
|
||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_PAY_PRICE_ILLEGAL;
|
||||
|
||||
// TODO @疯狂:搞个单测,嘿嘿;
|
||||
/**
|
||||
* 使用积分的 {@link TradePriceCalculator} 实现类
|
||||
*
|
||||
@ -32,19 +31,21 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCU
|
||||
public class TradePointUsePriceCalculator implements TradePriceCalculator {
|
||||
|
||||
@Resource
|
||||
private MemberPointApi memberPointApi;
|
||||
private MemberConfigApi memberConfigApi;
|
||||
@Resource
|
||||
private MemberUserApi memberUserApi;
|
||||
|
||||
@Override
|
||||
public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
|
||||
// 默认使用积分为 0
|
||||
result.setUsePoint(0);
|
||||
// 1.1 校验是否使用积分
|
||||
if (!BooleanUtil.isTrue(param.getPointStatus())) {
|
||||
result.setUsePoint(0);
|
||||
return;
|
||||
}
|
||||
// 1.2 校验积分抵扣是否开启
|
||||
MemberPointConfigRespDTO config = memberPointApi.getConfig();
|
||||
MemberConfigRespDTO config = memberConfigApi.getConfig();
|
||||
if (!isDeductPointEnable(config)) {
|
||||
return;
|
||||
}
|
||||
@ -76,20 +77,20 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator {
|
||||
TradePriceCalculatorHelper.recountAllPrice(result);
|
||||
}
|
||||
|
||||
private boolean isDeductPointEnable(MemberPointConfigRespDTO config) {
|
||||
private boolean isDeductPointEnable(MemberConfigRespDTO config) {
|
||||
return config != null &&
|
||||
!BooleanUtil.isTrue(config.getTradeDeductEnable()) && // 积分功能是否启用
|
||||
config.getTradeDeductUnitPrice() != null && config.getTradeDeductUnitPrice() > 0; // 有没有配置:1 积分抵扣多少分
|
||||
BooleanUtil.isTrue(config.getPointTradeDeductEnable()) && // 积分功能是否启用
|
||||
config.getPointTradeDeductUnitPrice() != null && config.getPointTradeDeductUnitPrice() > 0; // 有没有配置:1 积分抵扣多少分
|
||||
}
|
||||
|
||||
private Integer calculatePointPrice(MemberPointConfigRespDTO config, Integer usePoint, TradePriceCalculateRespBO result) {
|
||||
private Integer calculatePointPrice(MemberConfigRespDTO config, Integer usePoint, TradePriceCalculateRespBO result) {
|
||||
// 每个订单最多可以使用的积分数量
|
||||
if (config.getTradeDeductMaxPrice() != null && config.getTradeDeductMaxPrice() > 0) {
|
||||
usePoint = Math.min(usePoint, config.getTradeDeductMaxPrice());
|
||||
if (config.getPointTradeDeductMaxPrice() != null && config.getPointTradeDeductMaxPrice() > 0) {
|
||||
usePoint = Math.min(usePoint, config.getPointTradeDeductMaxPrice());
|
||||
}
|
||||
// TODO @疯狂:这里应该是,抵扣到只剩下 0.01;
|
||||
// 积分优惠金额(分)
|
||||
int pointPrice = usePoint * config.getTradeDeductUnitPrice();
|
||||
int pointPrice = usePoint * config.getPointTradeDeductUnitPrice();
|
||||
if (result.getPrice().getPayPrice() <= pointPrice) {
|
||||
// 禁止 0 元购
|
||||
throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL);
|
||||
@ -99,7 +100,7 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator {
|
||||
// pointPrice = result.getPrice().getPayPrice();
|
||||
// // 反推需要扣除的积分
|
||||
// usePoint = NumberUtil.toBigDecimal(pointPrice)
|
||||
// .divide(NumberUtil.toBigDecimal(config.getTradeDeductUnitPrice()), 0, RoundingMode.HALF_UP)
|
||||
// .divide(NumberUtil.toBigDecimal(config.getPointTradeDeductUnitPrice()), 0, RoundingMode.HALF_UP)
|
||||
// .intValue();
|
||||
// }
|
||||
// 记录使用的积分
|
||||
|
@ -2,8 +2,7 @@
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageUserMapper">
|
||||
|
||||
<select id="selectSummaryPageByUserId"
|
||||
resultType="cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO">
|
||||
<sql id="selectSummaryListByUserId">
|
||||
SELECT bu.id, bu.bind_user_time AS brokerageTime,
|
||||
(SELECT SUM(price) FROM trade_brokerage_record r
|
||||
WHERE r.user_id = bu.id AND biz_type = #{bizType} AND r.status = #{status} AND r.deleted = FALSE) AS brokeragePrice,
|
||||
@ -14,12 +13,6 @@
|
||||
FROM trade_brokerage_user AS bu
|
||||
<where>
|
||||
bu.deleted = false
|
||||
<if test="ids != null and ids.size() > 0">
|
||||
and bu.id in
|
||||
<foreach collection="ids" open="(" item="id" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="bindUserIds != null and bindUserIds.size() > 0">
|
||||
and bu.bind_user_id in
|
||||
<foreach collection="bindUserIds" open="(" item="bindUserId" separator="," close=")">
|
||||
@ -41,6 +34,15 @@
|
||||
ORDER BY bu.bind_user_time DESC
|
||||
</otherwise>
|
||||
</choose>
|
||||
</sql>
|
||||
|
||||
<select id="selectSummaryPageByUserId"
|
||||
resultType="cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO">
|
||||
<include refid="selectSummaryListByUserId" />
|
||||
</select>
|
||||
<select id="selectSummaryListByUserId"
|
||||
resultType="cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO">
|
||||
<include refid="selectSummaryListByUserId" />
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
@ -0,0 +1,98 @@
|
||||
package cn.iocoder.yudao.module.trade.service.price.calculator;
|
||||
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||
import cn.iocoder.yudao.module.member.api.config.MemberConfigApi;
|
||||
import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* {@link TradePointGiveCalculator} 的单元测试类
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
public class TradePointGiveCalculatorTest extends BaseMockitoUnitTest {
|
||||
|
||||
@InjectMocks
|
||||
private TradePointGiveCalculator tradePointGiveCalculator;
|
||||
|
||||
@Mock
|
||||
private MemberConfigApi memberConfigApi;
|
||||
|
||||
@Test
|
||||
public void testCalculate() {
|
||||
|
||||
// 准备参数
|
||||
TradePriceCalculateReqBO param = new TradePriceCalculateReqBO()
|
||||
.setUserId(233L)
|
||||
.setItems(asList(
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 全局积分
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 全局积分 + SKU 积分
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(4).setSelected(false), // 全局积分,但是未选中
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(40L).setCount(5).setSelected(false) // 全局积分 + SKU 积分,但是未选中
|
||||
));
|
||||
TradePriceCalculateRespBO result = new TradePriceCalculateRespBO()
|
||||
.setType(TradeOrderTypeEnum.NORMAL.getType())
|
||||
.setPrice(new TradePriceCalculateRespBO.Price())
|
||||
.setPromotions(new ArrayList<>())
|
||||
.setItems(asList(
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true)
|
||||
.setPrice(100).setSpuId(1L).setGivePoint(0),
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true)
|
||||
.setPrice(50).setSpuId(2L).setGivePoint(100),
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(4).setSelected(false)
|
||||
.setPrice(30).setSpuId(3L).setGivePoint(0),
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(40L).setCount(5).setSelected(false)
|
||||
.setPrice(60).setSpuId(1L).setGivePoint(100)
|
||||
));
|
||||
// 保证价格被初始化上
|
||||
TradePriceCalculatorHelper.recountPayPrice(result.getItems());
|
||||
TradePriceCalculatorHelper.recountAllPrice(result);
|
||||
|
||||
// mock 方法(积分配置 信息)
|
||||
MemberConfigRespDTO memberConfig = randomPojo(MemberConfigRespDTO.class,
|
||||
o -> o.setPointTradeDeductEnable(true) // 启用积分折扣
|
||||
.setPointTradeGivePoint(100)); // 1 元赠送多少分
|
||||
when(memberConfigApi.getConfig()).thenReturn(memberConfig);
|
||||
|
||||
// 调用
|
||||
tradePointGiveCalculator.calculate(param, result);
|
||||
// 断言:Price 部分
|
||||
assertEquals(result.getGivePoint(), 2 * 100 + 3 * 50 + 100);
|
||||
// 断言:SKU 1
|
||||
TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0);
|
||||
assertEquals(orderItem01.getSkuId(), 10L);
|
||||
assertEquals(orderItem01.getCount(), 2);
|
||||
assertEquals(orderItem01.getPrice(), 100);
|
||||
assertEquals(orderItem01.getGivePoint(), 2 * 100); // 全局积分
|
||||
// 断言:SKU 2
|
||||
TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1);
|
||||
assertEquals(orderItem02.getSkuId(), 20L);
|
||||
assertEquals(orderItem02.getCount(), 3);
|
||||
assertEquals(orderItem02.getPrice(), 50);
|
||||
assertEquals(orderItem02.getGivePoint(), 3 * 50 + 100); // 全局积分 + SKU 积分
|
||||
// 断言:SKU 3
|
||||
TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2);
|
||||
assertEquals(orderItem03.getSkuId(), 30L);
|
||||
assertEquals(orderItem03.getCount(), 4);
|
||||
assertEquals(orderItem03.getPrice(), 30);
|
||||
assertEquals(orderItem03.getGivePoint(), 0); // 全局积分,但是未选中
|
||||
// 断言:SKU 4
|
||||
TradePriceCalculateRespBO.OrderItem orderItem04 = result.getItems().get(3);
|
||||
assertEquals(orderItem04.getSkuId(), 40L);
|
||||
assertEquals(orderItem04.getCount(), 5);
|
||||
assertEquals(orderItem04.getPrice(), 60);
|
||||
assertEquals(orderItem04.getGivePoint(), 100); // 全局积分 + SKU 积分,但是未选中
|
||||
}
|
||||
}
|
@ -0,0 +1,332 @@
|
||||
package cn.iocoder.yudao.module.trade.service.price.calculator;
|
||||
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||
import cn.iocoder.yudao.module.member.api.config.MemberConfigApi;
|
||||
import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* {@link TradePointUsePriceCalculator } 的单元测试类
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
public class TradePointUsePriceCalculatorTest extends BaseMockitoUnitTest {
|
||||
|
||||
@InjectMocks
|
||||
private TradePointUsePriceCalculator tradePointUsePriceCalculator;
|
||||
|
||||
@Mock
|
||||
private MemberConfigApi memberConfigApi;
|
||||
@Mock
|
||||
private MemberUserApi memberUserApi;
|
||||
|
||||
@Test
|
||||
public void testCalculate_success() {
|
||||
// 准备参数
|
||||
TradePriceCalculateReqBO param = new TradePriceCalculateReqBO()
|
||||
.setUserId(233L).setPointStatus(true) // 是否使用积分
|
||||
.setItems(asList(
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 使用积分
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 使用积分
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(5).setSelected(false) // 未选中,不使用积分
|
||||
));
|
||||
TradePriceCalculateRespBO result = new TradePriceCalculateRespBO()
|
||||
.setType(TradeOrderTypeEnum.NORMAL.getType())
|
||||
.setPrice(new TradePriceCalculateRespBO.Price())
|
||||
.setPromotions(new ArrayList<>())
|
||||
.setItems(asList(
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true)
|
||||
.setPrice(100).setSpuId(1L),
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true)
|
||||
.setPrice(50).setSpuId(2L),
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(5).setSelected(false)
|
||||
.setPrice(30).setSpuId(3L)
|
||||
));
|
||||
// 保证价格被初始化上
|
||||
TradePriceCalculatorHelper.recountPayPrice(result.getItems());
|
||||
TradePriceCalculatorHelper.recountAllPrice(result);
|
||||
|
||||
// mock 方法(积分配置 信息)
|
||||
MemberConfigRespDTO memberConfig = randomPojo(MemberConfigRespDTO.class,
|
||||
o -> o.setPointTradeDeductEnable(true) // 启用积分折扣
|
||||
.setPointTradeDeductUnitPrice(1) // 1 积分抵扣多少金额(单位分)
|
||||
.setPointTradeDeductMaxPrice(100)); // 积分抵扣最大值
|
||||
when(memberConfigApi.getConfig()).thenReturn(memberConfig);
|
||||
// mock 方法(会员 信息)
|
||||
MemberUserRespDTO user = randomPojo(MemberUserRespDTO.class, o -> o.setId(param.getUserId()).setPoint(100));
|
||||
when(memberUserApi.getUser(user.getId())).thenReturn(user);
|
||||
|
||||
// 调用
|
||||
tradePointUsePriceCalculator.calculate(param, result);
|
||||
// 断言:使用了多少积分
|
||||
assertEquals(result.getUsePoint(), 100);
|
||||
// 断言:Price 部分
|
||||
TradePriceCalculateRespBO.Price price = result.getPrice();
|
||||
assertEquals(price.getTotalPrice(), 350);
|
||||
assertEquals(price.getPayPrice(), 250);
|
||||
assertEquals(price.getPointPrice(), 100);
|
||||
// 断言:SKU 1
|
||||
TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0);
|
||||
assertEquals(orderItem01.getSkuId(), 10L);
|
||||
assertEquals(orderItem01.getCount(), 2);
|
||||
assertEquals(orderItem01.getPrice(), 100);
|
||||
assertEquals(orderItem01.getPointPrice(), 57);
|
||||
assertEquals(orderItem01.getPayPrice(), 143);
|
||||
// 断言:SKU 2
|
||||
TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1);
|
||||
assertEquals(orderItem02.getSkuId(), 20L);
|
||||
assertEquals(orderItem02.getCount(), 3);
|
||||
assertEquals(orderItem02.getPrice(), 50);
|
||||
assertEquals(orderItem02.getPointPrice(), 43);
|
||||
assertEquals(orderItem02.getPayPrice(), 107);
|
||||
// 断言:SKU 3
|
||||
TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2);
|
||||
assertEquals(orderItem03.getSkuId(), 30L);
|
||||
assertEquals(orderItem03.getCount(), 5);
|
||||
assertEquals(orderItem03.getPrice(), 30);
|
||||
assertEquals(orderItem03.getPointPrice(), 0);
|
||||
assertEquals(orderItem03.getPayPrice(), 150);
|
||||
// 断言:Promotion 部分
|
||||
assertEquals(result.getPromotions().size(), 1);
|
||||
TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0);
|
||||
assertEquals(promotion01.getId(), user.getId());
|
||||
assertEquals(promotion01.getName(), "积分抵扣");
|
||||
assertEquals(promotion01.getType(), PromotionTypeEnum.POINT.getType());
|
||||
assertEquals(promotion01.getTotalPrice(), 350);
|
||||
assertEquals(promotion01.getDiscountPrice(), 100);
|
||||
assertTrue(promotion01.getMatch());
|
||||
assertEquals(promotion01.getDescription(), "积分抵扣:省 1.00 元");
|
||||
assertEquals(promotion01.getItems().size(), 2);
|
||||
TradePriceCalculateRespBO.PromotionItem promotionItem011 = promotion01.getItems().get(0);
|
||||
assertEquals(promotionItem011.getSkuId(), 10L);
|
||||
assertEquals(promotionItem011.getTotalPrice(), 200);
|
||||
assertEquals(promotionItem011.getDiscountPrice(), 57);
|
||||
TradePriceCalculateRespBO.PromotionItem promotionItem012 = promotion01.getItems().get(1);
|
||||
assertEquals(promotionItem012.getSkuId(), 20L);
|
||||
assertEquals(promotionItem012.getTotalPrice(), 150);
|
||||
assertEquals(promotionItem012.getDiscountPrice(), 43);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当用户积分充足时,抵扣的金额为:配置表的“积分抵扣最大值”
|
||||
*/
|
||||
@Test
|
||||
public void testCalculate_TradeDeductMaxPrice() {
|
||||
// 准备参数
|
||||
TradePriceCalculateReqBO param = new TradePriceCalculateReqBO()
|
||||
.setUserId(233L).setPointStatus(true) // 是否使用积分
|
||||
.setItems(asList(
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 使用积分
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 使用积分
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(5).setSelected(false) // 未选中,不使用积分
|
||||
));
|
||||
TradePriceCalculateRespBO result = new TradePriceCalculateRespBO()
|
||||
.setType(TradeOrderTypeEnum.NORMAL.getType())
|
||||
.setPrice(new TradePriceCalculateRespBO.Price())
|
||||
.setPromotions(new ArrayList<>())
|
||||
.setItems(asList(
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true)
|
||||
.setPrice(100).setSpuId(1L),
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true)
|
||||
.setPrice(50).setSpuId(2L),
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(5).setSelected(false)
|
||||
.setPrice(30).setSpuId(3L)
|
||||
));
|
||||
// 保证价格被初始化上
|
||||
TradePriceCalculatorHelper.recountPayPrice(result.getItems());
|
||||
TradePriceCalculatorHelper.recountAllPrice(result);
|
||||
|
||||
// mock 方法(积分配置 信息)
|
||||
MemberConfigRespDTO memberConfig = randomPojo(MemberConfigRespDTO.class,
|
||||
o -> o.setPointTradeDeductEnable(true) // 启用积分折扣
|
||||
.setPointTradeDeductUnitPrice(1) // 1 积分抵扣多少金额(单位分)
|
||||
.setPointTradeDeductMaxPrice(50)); // 积分抵扣最大值
|
||||
when(memberConfigApi.getConfig()).thenReturn(memberConfig);
|
||||
// mock 方法(会员 信息)
|
||||
MemberUserRespDTO user = randomPojo(MemberUserRespDTO.class, o -> o.setId(param.getUserId()).setPoint(100));
|
||||
when(memberUserApi.getUser(user.getId())).thenReturn(user);
|
||||
|
||||
// 调用
|
||||
tradePointUsePriceCalculator.calculate(param, result);
|
||||
// 断言:使用了多少积分
|
||||
assertEquals(result.getUsePoint(), 50);
|
||||
// 断言:Price 部分
|
||||
TradePriceCalculateRespBO.Price price = result.getPrice();
|
||||
assertEquals(price.getTotalPrice(), 350);
|
||||
assertEquals(price.getPayPrice(), 300);
|
||||
assertEquals(price.getPointPrice(), 50);
|
||||
// 断言:SKU 1
|
||||
TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0);
|
||||
assertEquals(orderItem01.getSkuId(), 10L);
|
||||
assertEquals(orderItem01.getCount(), 2);
|
||||
assertEquals(orderItem01.getPrice(), 100);
|
||||
assertEquals(orderItem01.getPointPrice(), 28);
|
||||
assertEquals(orderItem01.getPayPrice(), 172);
|
||||
// 断言:SKU 2
|
||||
TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1);
|
||||
assertEquals(orderItem02.getSkuId(), 20L);
|
||||
assertEquals(orderItem02.getCount(), 3);
|
||||
assertEquals(orderItem02.getPrice(), 50);
|
||||
assertEquals(orderItem02.getPointPrice(), 22);
|
||||
assertEquals(orderItem02.getPayPrice(), 128);
|
||||
// 断言:SKU 3
|
||||
TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2);
|
||||
assertEquals(orderItem03.getSkuId(), 30L);
|
||||
assertEquals(orderItem03.getCount(), 5);
|
||||
assertEquals(orderItem03.getPrice(), 30);
|
||||
assertEquals(orderItem03.getPointPrice(), 0);
|
||||
assertEquals(orderItem03.getPayPrice(), 150);
|
||||
// 断言:Promotion 部分
|
||||
assertEquals(result.getPromotions().size(), 1);
|
||||
TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0);
|
||||
assertEquals(promotion01.getId(), user.getId());
|
||||
assertEquals(promotion01.getName(), "积分抵扣");
|
||||
assertEquals(promotion01.getType(), PromotionTypeEnum.POINT.getType());
|
||||
assertEquals(promotion01.getTotalPrice(), 350);
|
||||
assertEquals(promotion01.getDiscountPrice(), 50);
|
||||
assertTrue(promotion01.getMatch());
|
||||
assertEquals(promotion01.getDescription(), "积分抵扣:省 0.50 元");
|
||||
assertEquals(promotion01.getItems().size(), 2);
|
||||
TradePriceCalculateRespBO.PromotionItem promotionItem011 = promotion01.getItems().get(0);
|
||||
assertEquals(promotionItem011.getSkuId(), 10L);
|
||||
assertEquals(promotionItem011.getTotalPrice(), 200);
|
||||
assertEquals(promotionItem011.getDiscountPrice(), 28);
|
||||
TradePriceCalculateRespBO.PromotionItem promotionItem012 = promotion01.getItems().get(1);
|
||||
assertEquals(promotionItem012.getSkuId(), 20L);
|
||||
assertEquals(promotionItem012.getTotalPrice(), 150);
|
||||
assertEquals(promotionItem012.getDiscountPrice(), 22);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单不使用积分,不会产生优惠
|
||||
*/
|
||||
@Test
|
||||
public void testCalculate_PointStatusFalse() {
|
||||
// 准备参数
|
||||
TradePriceCalculateReqBO param = new TradePriceCalculateReqBO()
|
||||
.setUserId(233L).setPointStatus(false) // 是否使用积分
|
||||
.setItems(asList(
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 使用积分
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 使用积分
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(5).setSelected(false) // 未选中,不使用积分
|
||||
));
|
||||
TradePriceCalculateRespBO result = new TradePriceCalculateRespBO()
|
||||
.setType(TradeOrderTypeEnum.NORMAL.getType())
|
||||
.setPrice(new TradePriceCalculateRespBO.Price())
|
||||
.setPromotions(new ArrayList<>())
|
||||
.setItems(asList(
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true)
|
||||
.setPrice(100).setSpuId(1L),
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true)
|
||||
.setPrice(50).setSpuId(2L),
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(5).setSelected(false)
|
||||
.setPrice(30).setSpuId(3L)
|
||||
));
|
||||
// 保证价格被初始化上
|
||||
TradePriceCalculatorHelper.recountPayPrice(result.getItems());
|
||||
TradePriceCalculatorHelper.recountAllPrice(result);
|
||||
|
||||
// 调用
|
||||
tradePointUsePriceCalculator.calculate(param, result);
|
||||
// 断言:没有使用积分
|
||||
assertNotUsePoint(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员积分不足,不会产生优惠
|
||||
*/
|
||||
@Test
|
||||
public void testCalculate_UserPointNotEnough() {
|
||||
// 准备参数
|
||||
TradePriceCalculateReqBO param = new TradePriceCalculateReqBO()
|
||||
.setUserId(233L).setPointStatus(true) // 是否使用积分
|
||||
.setItems(asList(
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 使用积分
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 使用积分
|
||||
new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(5).setSelected(false) // 未选中,不使用积分
|
||||
));
|
||||
TradePriceCalculateRespBO result = new TradePriceCalculateRespBO()
|
||||
.setType(TradeOrderTypeEnum.NORMAL.getType())
|
||||
.setPrice(new TradePriceCalculateRespBO.Price())
|
||||
.setPromotions(new ArrayList<>())
|
||||
.setItems(asList(
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true)
|
||||
.setPrice(100).setSpuId(1L),
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true)
|
||||
.setPrice(50).setSpuId(2L),
|
||||
new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(5).setSelected(false)
|
||||
.setPrice(30).setSpuId(3L)
|
||||
));
|
||||
// 保证价格被初始化上
|
||||
TradePriceCalculatorHelper.recountPayPrice(result.getItems());
|
||||
TradePriceCalculatorHelper.recountAllPrice(result);
|
||||
|
||||
// mock 方法(积分配置 信息)
|
||||
MemberConfigRespDTO memberConfig = randomPojo(MemberConfigRespDTO.class,
|
||||
o -> o.setPointTradeDeductEnable(true) // 启用积分折扣
|
||||
.setPointTradeDeductUnitPrice(1) // 1 积分抵扣多少金额(单位分)
|
||||
.setPointTradeDeductMaxPrice(100)); // 积分抵扣最大值
|
||||
when(memberConfigApi.getConfig()).thenReturn(memberConfig);
|
||||
// mock 方法(会员 信息)
|
||||
MemberUserRespDTO user = randomPojo(MemberUserRespDTO.class, o -> o.setId(param.getUserId()).setPoint(0));
|
||||
when(memberUserApi.getUser(user.getId())).thenReturn(user);
|
||||
|
||||
// 调用
|
||||
tradePointUsePriceCalculator.calculate(param, result);
|
||||
|
||||
// 断言:没有使用积分
|
||||
assertNotUsePoint(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言:没有使用积分
|
||||
*/
|
||||
private static void assertNotUsePoint(TradePriceCalculateRespBO result) {
|
||||
// 断言:使用了多少积分
|
||||
assertEquals(result.getUsePoint(), 0);
|
||||
// 断言:Price 部分
|
||||
TradePriceCalculateRespBO.Price price = result.getPrice();
|
||||
assertEquals(price.getTotalPrice(), 350);
|
||||
assertEquals(price.getPayPrice(), 350);
|
||||
assertEquals(price.getPointPrice(), 0);
|
||||
// 断言:SKU 1
|
||||
TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0);
|
||||
assertEquals(orderItem01.getSkuId(), 10L);
|
||||
assertEquals(orderItem01.getCount(), 2);
|
||||
assertEquals(orderItem01.getPrice(), 100);
|
||||
assertEquals(orderItem01.getPointPrice(), 0);
|
||||
assertEquals(orderItem01.getPayPrice(), 200);
|
||||
// 断言:SKU 2
|
||||
TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1);
|
||||
assertEquals(orderItem02.getSkuId(), 20L);
|
||||
assertEquals(orderItem02.getCount(), 3);
|
||||
assertEquals(orderItem02.getPrice(), 50);
|
||||
assertEquals(orderItem02.getPointPrice(), 0);
|
||||
assertEquals(orderItem02.getPayPrice(), 150);
|
||||
// 断言:SKU 3
|
||||
TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2);
|
||||
assertEquals(orderItem03.getSkuId(), 30L);
|
||||
assertEquals(orderItem03.getCount(), 5);
|
||||
assertEquals(orderItem03.getPrice(), 30);
|
||||
assertEquals(orderItem03.getPointPrice(), 0);
|
||||
assertEquals(orderItem03.getPayPrice(), 150);
|
||||
// 断言:Promotion 部分
|
||||
assertEquals(result.getPromotions().size(), 0);
|
||||
}
|
||||
}
|
@ -22,6 +22,11 @@
|
||||
<artifactId>yudao-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-mq</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- 参数校验 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.member.api.config;
|
||||
|
||||
import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO;
|
||||
|
||||
/**
|
||||
* 用户配置 API 接口
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
public interface MemberConfigApi {
|
||||
|
||||
/**
|
||||
* 获得积分配置
|
||||
*
|
||||
* @return 积分配置
|
||||
*/
|
||||
MemberConfigRespDTO getConfig();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.member.api.point.dto;
|
||||
package cn.iocoder.yudao.module.member.api.config.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@ -8,25 +8,25 @@ import lombok.Data;
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class MemberPointConfigRespDTO {
|
||||
public class MemberConfigRespDTO {
|
||||
|
||||
/**
|
||||
* 积分抵扣开关
|
||||
*/
|
||||
private Boolean tradeDeductEnable;
|
||||
private Boolean pointTradeDeductEnable;
|
||||
/**
|
||||
* 积分抵扣,单位:分
|
||||
* <p>
|
||||
* 1 积分抵扣多少分
|
||||
*/
|
||||
private Integer tradeDeductUnitPrice;
|
||||
private Integer pointTradeDeductUnitPrice;
|
||||
/**
|
||||
* 积分抵扣最大值
|
||||
*/
|
||||
private Integer tradeDeductMaxPrice;
|
||||
private Integer pointTradeDeductMaxPrice;
|
||||
/**
|
||||
* 1 元赠送多少分
|
||||
*/
|
||||
private Integer tradeGivePoint;
|
||||
private Integer pointTradeGivePoint;
|
||||
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.module.member.api.point;
|
||||
|
||||
import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
@ -12,14 +11,6 @@ import javax.validation.constraints.Min;
|
||||
*/
|
||||
public interface MemberPointApi {
|
||||
|
||||
// TODO @疯狂:这个我们要不要搞成通用的会员配置?MemberConfig?
|
||||
/**
|
||||
* 获得积分配置
|
||||
*
|
||||
* @return 积分配置
|
||||
*/
|
||||
MemberPointConfigRespDTO getConfig();
|
||||
|
||||
/**
|
||||
* 增加用户积分
|
||||
*
|
||||
|
@ -38,6 +38,7 @@ public interface ErrorCodeConstants {
|
||||
//========== 签到配置 1-004-009-000 ==========
|
||||
ErrorCode SIGN_IN_CONFIG_NOT_EXISTS = new ErrorCode(1_004_009_000, "签到天数规则不存在");
|
||||
ErrorCode SIGN_IN_CONFIG_EXISTS = new ErrorCode(1_004_009_001, "签到天数规则已存在");
|
||||
ErrorCode SIGN_IN_CONFIG_AWARD_EMPTY = new ErrorCode(1_004_009_002, "签到奖励积分和经验不能同时为空");
|
||||
|
||||
//========== 签到配置 1-004-010-000 ==========
|
||||
ErrorCode SIGN_IN_RECORD_TODAY_EXISTS = new ErrorCode(1_004_010_000,"今日已签到,请勿重复签到");
|
||||
|
@ -17,6 +17,7 @@ import java.util.Objects;
|
||||
public enum MemberPointBizTypeEnum implements IntArrayValuable {
|
||||
|
||||
SIGN(1, "签到", "签到获得 {} 积分", true),
|
||||
ADMIN(2, "管理员修改", "管理员修改 {} 积分", true),
|
||||
ORDER_GIVE(10, "订单奖励", "下单获得 {} 积分", true), // 支付订单时,赠送积分
|
||||
ORDER_CANCEL(11, "订单取消", "订单取消,退还 {} 积分", true), // 取消订单时,退回积分
|
||||
ORDER_USE(12, "订单使用", "下单使用 {} 积分", false), // 下单时,扣减积分
|
||||
|
@ -0,0 +1,29 @@
|
||||
package cn.iocoder.yudao.module.member.mq.message.user;
|
||||
|
||||
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 新人券发放消息
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RegisterCouponSendMessage extends AbstractStreamMessage {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
@Override
|
||||
public String getStreamKey() {
|
||||
return "member.register-coupon.send";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package cn.iocoder.yudao.module.member.api.config;
|
||||
|
||||
import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.member.convert.config.MemberConfigConvert;
|
||||
import cn.iocoder.yudao.module.member.service.config.MemberConfigService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 用户配置 API 实现类
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class MemberConfigApiImpl implements MemberConfigApi {
|
||||
|
||||
@Resource
|
||||
private MemberConfigService memberConfigService;
|
||||
|
||||
@Override
|
||||
public MemberConfigRespDTO getConfig() {
|
||||
return MemberConfigConvert.INSTANCE.convert01(memberConfigService.getConfig());
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,7 @@
|
||||
package cn.iocoder.yudao.module.member.api.point;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.member.convert.point.MemberPointConfigConvert;
|
||||
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.member.service.point.MemberPointConfigService;
|
||||
import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -25,13 +22,6 @@ public class MemberPointApiImpl implements MemberPointApi {
|
||||
|
||||
@Resource
|
||||
private MemberPointRecordService memberPointRecordService;
|
||||
@Resource
|
||||
private MemberPointConfigService memberPointConfigService;
|
||||
|
||||
@Override
|
||||
public MemberPointConfigRespDTO getConfig() {
|
||||
return MemberPointConfigConvert.INSTANCE.convert01(memberPointConfigService.getPointConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPoint(Long userId, Integer point, Integer bizType, String bizId) {
|
||||
|
@ -0,0 +1,45 @@
|
||||
package cn.iocoder.yudao.module.member.controller.admin.config;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigRespVO;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigSaveReqVO;
|
||||
import cn.iocoder.yudao.module.member.convert.config.MemberConfigConvert;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.config.MemberConfigDO;
|
||||
import cn.iocoder.yudao.module.member.service.config.MemberConfigService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 会员设置")
|
||||
@RestController
|
||||
@RequestMapping("/member/config")
|
||||
@Validated
|
||||
public class MemberConfigController {
|
||||
|
||||
@Resource
|
||||
private MemberConfigService memberConfigService;
|
||||
|
||||
@PutMapping("/save")
|
||||
@Operation(summary = "保存会员配置")
|
||||
@PreAuthorize("@ss.hasPermission('member:config:save')")
|
||||
public CommonResult<Boolean> saveConfig(@Valid @RequestBody MemberConfigSaveReqVO saveReqVO) {
|
||||
memberConfigService.saveConfig(saveReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得会员配置")
|
||||
@PreAuthorize("@ss.hasPermission('member:config:query')")
|
||||
public CommonResult<MemberConfigRespVO> getConfig() {
|
||||
MemberConfigDO config = memberConfigService.getConfig();
|
||||
return success(MemberConfigConvert.INSTANCE.convert(config));
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.member.controller.admin.point.vo.config;
|
||||
package cn.iocoder.yudao.module.member.controller.admin.config.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
@ -6,26 +6,26 @@ import lombok.Data;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 会员积分配置 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 会员配置 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||
*/
|
||||
@Data
|
||||
public class MemberPointConfigBaseVO {
|
||||
public class MemberConfigBaseVO {
|
||||
|
||||
@Schema(description = "积分抵扣开关", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "积分抵扣开发不能为空")
|
||||
private Boolean tradeDeductEnable;
|
||||
private Boolean pointTradeDeductEnable;
|
||||
|
||||
@Schema(description = "积分抵扣,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "13506")
|
||||
@NotNull(message = "积分抵扣不能为空")
|
||||
private Integer tradeDeductUnitPrice;
|
||||
private Integer pointTradeDeductUnitPrice;
|
||||
|
||||
@Schema(description = "积分抵扣最大值", requiredMode = Schema.RequiredMode.REQUIRED, example = "32428")
|
||||
@NotNull(message = "积分抵扣最大值不能为空")
|
||||
private Integer tradeDeductMaxPrice;
|
||||
private Integer pointTradeDeductMaxPrice;
|
||||
|
||||
@Schema(description = "1 元赠送多少分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
@NotNull(message = "1 元赠送积分不能为空")
|
||||
private Integer tradeGivePoint;
|
||||
private Integer pointTradeGivePoint;
|
||||
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
package cn.iocoder.yudao.module.member.controller.admin.point.vo.config;
|
||||
package cn.iocoder.yudao.module.member.controller.admin.config.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 会员积分配置 Response VO")
|
||||
@Schema(description = "管理后台 - 会员配置 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class MemberPointConfigRespVO extends MemberPointConfigBaseVO {
|
||||
public class MemberConfigRespVO extends MemberConfigBaseVO {
|
||||
|
||||
@Schema(description = "自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
@ -0,0 +1,13 @@
|
||||
package cn.iocoder.yudao.module.member.controller.admin.config.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 会员配置保存 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class MemberConfigSaveReqVO extends MemberConfigBaseVO {
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package cn.iocoder.yudao.module.member.controller.admin.point;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigRespVO;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigSaveReqVO;
|
||||
import cn.iocoder.yudao.module.member.convert.point.MemberPointConfigConvert;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointConfigDO;
|
||||
import cn.iocoder.yudao.module.member.service.point.MemberPointConfigService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 会员积分设置")
|
||||
@RestController
|
||||
@RequestMapping("/member/point/config")
|
||||
@Validated
|
||||
public class MemberPointConfigController {
|
||||
|
||||
@Resource
|
||||
private MemberPointConfigService memberPointConfigService;
|
||||
|
||||
@PutMapping("/save")
|
||||
@Operation(summary = "保存会员积分配置")
|
||||
@PreAuthorize("@ss.hasPermission('point:config:save')")
|
||||
public CommonResult<Boolean> savePointConfig(@Valid @RequestBody MemberPointConfigSaveReqVO saveReqVO) {
|
||||
memberPointConfigService.savePointConfig(saveReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得会员积分配置")
|
||||
@PreAuthorize("@ss.hasPermission('point:config:query')")
|
||||
public CommonResult<MemberPointConfigRespVO> getPointConfig() {
|
||||
MemberPointConfigDO config = memberPointConfigService.getPointConfig();
|
||||
return success(MemberPointConfigConvert.INSTANCE.convert(config));
|
||||
}
|
||||
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package cn.iocoder.yudao.module.member.controller.admin.point.vo.config;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 会员积分配置保存 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class MemberPointConfigSaveReqVO extends MemberPointConfigBaseVO {
|
||||
}
|
@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.PositiveOrZero;
|
||||
|
||||
/**
|
||||
* 签到规则 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
@ -20,8 +21,14 @@ public class MemberSignInConfigBaseVO {
|
||||
|
||||
@Schema(description = "奖励积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
@NotNull(message = "奖励积分不能为空")
|
||||
@PositiveOrZero(message = "奖励积分不能小于 0")
|
||||
private Integer point;
|
||||
|
||||
@Schema(description = "奖励经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
@NotNull(message = "奖励经验不能为空")
|
||||
@PositiveOrZero(message = "奖励经验不能小于 0")
|
||||
private Integer experience;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "状态不能为空")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
|
@ -21,7 +21,7 @@ public class MemberSignInRecordRespVO {
|
||||
@Schema(description = "第几天签到", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer day;
|
||||
|
||||
@Schema(description = "签到的分数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
@Schema(description = "签到的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer point;
|
||||
|
||||
@Schema(description = "签到时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
|
@ -3,17 +3,16 @@ package cn.iocoder.yudao.module.member.controller.admin.user;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserRespVO;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateLevelReqVO;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.user.vo.*;
|
||||
import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
|
||||
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.member.service.group.MemberGroupService;
|
||||
import cn.iocoder.yudao.module.member.service.level.MemberLevelService;
|
||||
import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService;
|
||||
import cn.iocoder.yudao.module.member.service.tag.MemberTagService;
|
||||
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@ -33,6 +32,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - 会员用户")
|
||||
@RestController
|
||||
@ -48,6 +48,8 @@ public class MemberUserController {
|
||||
private MemberLevelService memberLevelService;
|
||||
@Resource
|
||||
private MemberGroupService memberGroupService;
|
||||
@Resource
|
||||
private MemberPointRecordService memberPointRecordService;
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新会员用户")
|
||||
@ -65,6 +67,23 @@ public class MemberUserController {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-point")
|
||||
@Operation(summary = "更新会员用户积分")
|
||||
@PreAuthorize("@ss.hasPermission('member:user:update-point')")
|
||||
public CommonResult<Boolean> updateUserPoint(@Valid @RequestBody MemberUserUpdatePointReqVO updateReqVO) {
|
||||
memberPointRecordService.createPointRecord(updateReqVO.getId(), updateReqVO.getPoint(),
|
||||
MemberPointBizTypeEnum.ADMIN, String.valueOf(getLoginUserId()));
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-balance")
|
||||
@Operation(summary = "更新会员用户余额")
|
||||
@PreAuthorize("@ss.hasPermission('member:user:update-balance')")
|
||||
public CommonResult<Boolean> updateUserBalance(@Valid @RequestBody Long id) {
|
||||
// todo @jason:增加一个【修改余额】
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得会员用户")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
|
@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.member.controller.admin.user.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
@ -10,9 +9,8 @@ import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 会员用户 修改等级 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class MemberUserUpdateLevelReqVO extends MemberUserBaseVO {
|
||||
public class MemberUserUpdateLevelReqVO {
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23788")
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
|
@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.member.controller.admin.user.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 会员用户 修改积分 Request VO")
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class MemberUserUpdatePointReqVO {
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23788")
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "变动积分,正数为增加,负数为减少", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
@NotNull(message = "变动积分不能为空")
|
||||
private Integer point;
|
||||
|
||||
}
|
@ -1,13 +1,10 @@
|
||||
package cn.iocoder.yudao.module.member.controller.app.signin;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO;
|
||||
import cn.iocoder.yudao.module.member.service.signin.MemberSignInRecordService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@ -29,17 +26,8 @@ public class AppMemberSignInController {
|
||||
// TODO @xiaqing:合并到 AppMemberSignInRecordController 的 getSignInRecordSummary 里哈。
|
||||
@Operation(summary = "个人签到信息")
|
||||
@GetMapping("/get-summary")
|
||||
public CommonResult getUserSummary(){
|
||||
public CommonResult getUserSummary() {
|
||||
return success(signInRecordService.getSignInRecordSummary(getLoginUserId()));
|
||||
}
|
||||
|
||||
// TODO @xiaqing:泛型:
|
||||
// TODO @xiaqing:合并到 AppMemberSignInRecordController 的 createSignInRecord 里哈。
|
||||
@Operation(summary = "会员签到")
|
||||
@PostMapping("/create")
|
||||
public CommonResult create(){
|
||||
MemberSignInRecordDO recordDO = signInRecordService.createSignRecord(getLoginUserId());
|
||||
return success(MemberSignInRecordConvert.INSTANCE.coverRecordToAppRecordVo(recordDO));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
@ -50,16 +49,12 @@ public class AppMemberSignInRecordController {
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
// TODO 芋艿:临时 mock => UserSignController.info
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "签到")
|
||||
@PreAuthenticated
|
||||
public CommonResult<AppMemberSignInRecordRespVO> createSignInRecord() {
|
||||
AppMemberSignInRecordRespVO respVO = new AppMemberSignInRecordRespVO()
|
||||
.setPoint(10)
|
||||
.setDay(10)
|
||||
.setCreateTime(LocalDateTime.now());
|
||||
return success(respVO);
|
||||
MemberSignInRecordDO recordDO = signInRecordService.createSignRecord(getLoginUserId());
|
||||
return success(MemberSignInRecordConvert.INSTANCE.coverRecordToAppRecordVo(recordDO));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
|
@ -12,9 +12,12 @@ public class AppMemberSignInRecordRespVO {
|
||||
@Schema(description = "第几天签到", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer day;
|
||||
|
||||
@Schema(description = "签到的分数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
@Schema(description = "签到的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer point;
|
||||
|
||||
@Schema(description = "签到的经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer experience;
|
||||
|
||||
@Schema(description = "签到时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
|
@ -15,6 +15,9 @@ public class AppMemberSignInRecordRespVO {
|
||||
@Schema(description = "签到的分数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer point;
|
||||
|
||||
@Schema(description = "签到的经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer experience;
|
||||
|
||||
@Schema(description = "签到时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
|
@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.member.convert.config;
|
||||
|
||||
import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigRespVO;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigSaveReqVO;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.config.MemberConfigDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* 会员配置 Convert
|
||||
*
|
||||
* @author QingX
|
||||
*/
|
||||
@Mapper
|
||||
public interface MemberConfigConvert {
|
||||
|
||||
MemberConfigConvert INSTANCE = Mappers.getMapper(MemberConfigConvert.class);
|
||||
|
||||
MemberConfigRespVO convert(MemberConfigDO bean);
|
||||
|
||||
MemberConfigDO convert(MemberConfigSaveReqVO bean);
|
||||
|
||||
MemberConfigRespDTO convert01(MemberConfigDO config);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package cn.iocoder.yudao.module.member.convert.point;
|
||||
|
||||
import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigRespVO;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigSaveReqVO;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointConfigDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* 会员积分配置 Convert
|
||||
*
|
||||
* @author QingX
|
||||
*/
|
||||
@Mapper
|
||||
public interface MemberPointConfigConvert {
|
||||
|
||||
MemberPointConfigConvert INSTANCE = Mappers.getMapper(MemberPointConfigConvert.class);
|
||||
|
||||
MemberPointConfigRespVO convert(MemberPointConfigDO bean);
|
||||
|
||||
MemberPointConfigDO convert(MemberPointConfigSaveReqVO bean);
|
||||
|
||||
MemberPointConfigRespDTO convert01(MemberPointConfigDO pointConfig);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.member.dal.dataobject.point;
|
||||
package cn.iocoder.yudao.module.member.dal.dataobject.config;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
@ -7,19 +7,19 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 会员积分配置 DO
|
||||
* 会员配置 DO
|
||||
*
|
||||
* @author QingX
|
||||
*/
|
||||
@TableName(value = "member_point_config", autoResultMap = true)
|
||||
@KeySequence("member_point_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@TableName(value = "member_config", autoResultMap = true)
|
||||
@KeySequence("member_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MemberPointConfigDO extends BaseDO {
|
||||
public class MemberConfigDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 自增主键
|
||||
@ -29,20 +29,20 @@ public class MemberPointConfigDO extends BaseDO {
|
||||
/**
|
||||
* 积分抵扣开关
|
||||
*/
|
||||
private Boolean tradeDeductEnable;
|
||||
private Boolean pointTradeDeductEnable;
|
||||
/**
|
||||
* 积分抵扣,单位:分
|
||||
*
|
||||
* 1 积分抵扣多少分
|
||||
*/
|
||||
private Integer tradeDeductUnitPrice;
|
||||
private Integer pointTradeDeductUnitPrice;
|
||||
/**
|
||||
* 积分抵扣最大值
|
||||
*/
|
||||
private Integer tradeDeductMaxPrice;
|
||||
private Integer pointTradeDeductMaxPrice;
|
||||
/**
|
||||
* 1 元赠送多少分
|
||||
*/
|
||||
private Integer tradeGivePoint;
|
||||
private Integer pointTradeGivePoint;
|
||||
|
||||
}
|
@ -35,6 +35,10 @@ public class MemberSignInConfigDO extends BaseDO {
|
||||
* 奖励积分
|
||||
*/
|
||||
private Integer point;
|
||||
/**
|
||||
* 奖励经验
|
||||
*/
|
||||
private Integer experience;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
|
@ -35,10 +35,12 @@ public class MemberSignInRecordDO extends BaseDO {
|
||||
*/
|
||||
private Integer day;
|
||||
/**
|
||||
* 签到的分数
|
||||
* 签到的积分
|
||||
*/
|
||||
private Integer point;
|
||||
|
||||
// TODO 疯狂:签到的经验
|
||||
/**
|
||||
* 签到的经验
|
||||
*/
|
||||
private Integer experience;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
package cn.iocoder.yudao.module.member.dal.mysql.config;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.config.MemberConfigDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 积分设置 Mapper
|
||||
*
|
||||
* @author QingX
|
||||
*/
|
||||
@Mapper
|
||||
public interface MemberConfigMapper extends BaseMapperX<MemberConfigDO> {
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package cn.iocoder.yudao.module.member.dal.mysql.point;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointConfigDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 积分设置 Mapper
|
||||
*
|
||||
* @author QingX
|
||||
*/
|
||||
@Mapper
|
||||
public interface MemberPointConfigMapper extends BaseMapperX<MemberPointConfigDO> {
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.member.mq.producer.user;
|
||||
|
||||
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
|
||||
import cn.iocoder.yudao.module.member.mq.message.user.RegisterCouponSendMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 新人券发放 Producer
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RegisterCouponProducer {
|
||||
|
||||
@Resource
|
||||
private RedisMQTemplate redisMQTemplate;
|
||||
|
||||
/**
|
||||
* 发送 {@link RegisterCouponSendMessage} 消息
|
||||
*
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
public void sendMailSendMessage(Long userId) {
|
||||
redisMQTemplate.send(new RegisterCouponSendMessage().setUserId(userId));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package cn.iocoder.yudao.module.member.service.config;
|
||||
|
||||
import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigSaveReqVO;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.config.MemberConfigDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* 会员配置 Service 接口
|
||||
*
|
||||
* @author QingX
|
||||
*/
|
||||
public interface MemberConfigService {
|
||||
|
||||
/**
|
||||
* 保存会员配置
|
||||
*
|
||||
* @param saveReqVO 更新信息
|
||||
*/
|
||||
void saveConfig(@Valid MemberConfigSaveReqVO saveReqVO);
|
||||
|
||||
/**
|
||||
* 获得会员配置
|
||||
*
|
||||
* @return 积分配置
|
||||
*/
|
||||
MemberConfigDO getConfig();
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package cn.iocoder.yudao.module.member.service.config;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigSaveReqVO;
|
||||
import cn.iocoder.yudao.module.member.convert.config.MemberConfigConvert;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.config.MemberConfigDO;
|
||||
import cn.iocoder.yudao.module.member.dal.mysql.config.MemberConfigMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 会员配置 Service 实现类
|
||||
*
|
||||
* @author QingX
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class MemberConfigServiceImpl implements MemberConfigService {
|
||||
|
||||
@Resource
|
||||
private MemberConfigMapper memberConfigMapper;
|
||||
|
||||
@Override
|
||||
public void saveConfig(MemberConfigSaveReqVO saveReqVO) {
|
||||
// 存在,则进行更新
|
||||
MemberConfigDO dbConfig = getConfig();
|
||||
if (dbConfig != null) {
|
||||
memberConfigMapper.updateById(MemberConfigConvert.INSTANCE.convert(saveReqVO).setId(dbConfig.getId()));
|
||||
return;
|
||||
}
|
||||
// 不存在,则进行插入
|
||||
memberConfigMapper.insert(MemberConfigConvert.INSTANCE.convert(saveReqVO));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberConfigDO getConfig() {
|
||||
List<MemberConfigDO> list = memberConfigMapper.selectList();
|
||||
return CollectionUtils.getFirst(list);
|
||||
}
|
||||
|
||||
}
|
@ -239,7 +239,8 @@ public class MemberLevelServiceImpl implements MemberLevelService {
|
||||
|
||||
// 1. 创建经验记录
|
||||
MemberUserDO user = memberUserService.getUser(userId);
|
||||
int userExperience = NumberUtil.max(user.getExperience() + experience, 0); // 防止扣出负数
|
||||
Integer userExperience = ObjUtil.defaultIfNull(user.getExperience(), 0);
|
||||
userExperience = NumberUtil.max(userExperience + experience, 0); // 防止扣出负数
|
||||
MemberLevelRecordDO levelRecord = new MemberLevelRecordDO()
|
||||
.setUserId(user.getId())
|
||||
.setExperience(experience)
|
||||
|
@ -1,29 +0,0 @@
|
||||
package cn.iocoder.yudao.module.member.service.point;
|
||||
|
||||
import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigSaveReqVO;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointConfigDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* 会员积分配置 Service 接口
|
||||
*
|
||||
* @author QingX
|
||||
*/
|
||||
public interface MemberPointConfigService {
|
||||
|
||||
/**
|
||||
* 保存会员积分配置
|
||||
*
|
||||
* @param saveReqVO 更新信息
|
||||
*/
|
||||
void savePointConfig(@Valid MemberPointConfigSaveReqVO saveReqVO);
|
||||
|
||||
/**
|
||||
* 获得会员积分配置
|
||||
*
|
||||
* @return 积分配置
|
||||
*/
|
||||
MemberPointConfigDO getPointConfig();
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package cn.iocoder.yudao.module.member.service.point;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigSaveReqVO;
|
||||
import cn.iocoder.yudao.module.member.convert.point.MemberPointConfigConvert;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointConfigDO;
|
||||
import cn.iocoder.yudao.module.member.dal.mysql.point.MemberPointConfigMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 会员积分配置 Service 实现类
|
||||
*
|
||||
* @author QingX
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class MemberPointConfigServiceImpl implements MemberPointConfigService {
|
||||
|
||||
@Resource
|
||||
private MemberPointConfigMapper memberPointConfigMapper;
|
||||
|
||||
@Override
|
||||
public void savePointConfig(MemberPointConfigSaveReqVO saveReqVO) {
|
||||
// 存在,则进行更新
|
||||
MemberPointConfigDO dbConfig = getPointConfig();
|
||||
if (dbConfig != null) {
|
||||
memberPointConfigMapper.updateById(MemberPointConfigConvert.INSTANCE.convert(saveReqVO).setId(dbConfig.getId()));
|
||||
return;
|
||||
}
|
||||
// 不存在,则进行插入
|
||||
memberPointConfigMapper.insert(MemberPointConfigConvert.INSTANCE.convert(saveReqVO));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberPointConfigDO getPointConfig() {
|
||||
List<MemberPointConfigDO> list = memberPointConfigMapper.selectList();
|
||||
return CollectionUtils.getFirst(list);
|
||||
}
|
||||
|
||||
}
|
@ -66,6 +66,9 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void createPointRecord(Long userId, Integer point, MemberPointBizTypeEnum bizType, String bizId) {
|
||||
if (point == 0) {
|
||||
return;
|
||||
}
|
||||
// 1. 校验用户积分余额
|
||||
MemberUserDO user = memberUserService.getUser(userId);
|
||||
Integer userPoint = ObjectUtil.defaultIfNull(user.getPoint(), 0);
|
||||
|
@ -11,10 +11,10 @@ import org.springframework.validation.annotation.Validated;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.SIGN_IN_CONFIG_EXISTS;
|
||||
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.SIGN_IN_CONFIG_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 签到规则 Service 实现类
|
||||
@ -30,6 +30,8 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
|
||||
|
||||
@Override
|
||||
public Long createSignInConfig(MemberSignInConfigCreateReqVO createReqVO) {
|
||||
// 校验奖励积分、奖励经验
|
||||
validatePointAndExperience(createReqVO.getPoint(), createReqVO.getExperience());
|
||||
// 判断是否重复插入签到天数
|
||||
validateSignInConfigDayDuplicate(createReqVO.getDay(), null);
|
||||
|
||||
@ -42,6 +44,8 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
|
||||
|
||||
@Override
|
||||
public void updateSignInConfig(MemberSignInConfigUpdateReqVO updateReqVO) {
|
||||
// 校验奖励积分、奖励经验
|
||||
validatePointAndExperience(updateReqVO.getPoint(), updateReqVO.getExperience());
|
||||
// 校验存在
|
||||
validateSignInConfigExists(updateReqVO.getId());
|
||||
// 判断是否重复插入签到天数
|
||||
@ -70,7 +74,7 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
|
||||
* 校验 day 是否重复
|
||||
*
|
||||
* @param day 天
|
||||
* @param id 编号,只有更新的时候会传递
|
||||
* @param id 编号,只有更新的时候会传递
|
||||
*/
|
||||
private void validateSignInConfigDayDuplicate(Integer day, Long id) {
|
||||
MemberSignInConfigDO config = memberSignInConfigMapper.selectByDay(day);
|
||||
@ -84,13 +88,20 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
|
||||
}
|
||||
}
|
||||
|
||||
private void validatePointAndExperience(Integer point, Integer experience) {
|
||||
// 奖励积分、经验 至少要配置一个,否则没有意义
|
||||
if (Objects.equals(point, 0) && Objects.equals(experience, 0)) {
|
||||
throw exception(SIGN_IN_CONFIG_AWARD_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberSignInConfigDO getSignInConfig(Long id) {
|
||||
return memberSignInConfigMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List <MemberSignInConfigDO> getSignInConfigList() {
|
||||
public List<MemberSignInConfigDO> getSignInConfigList() {
|
||||
List<MemberSignInConfigDO> list = memberSignInConfigMapper.selectList();
|
||||
list.sort(Comparator.comparing(MemberSignInConfigDO::getDay));
|
||||
return list;
|
||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.member.service.signin;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
@ -13,8 +14,13 @@ import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO
|
||||
import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInConfigMapper;
|
||||
import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInRecordMapper;
|
||||
import cn.iocoder.yudao.module.member.enums.ErrorCodeConstants;
|
||||
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.member.service.level.MemberLevelService;
|
||||
import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@ -40,20 +46,24 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService
|
||||
private MemberSignInRecordMapper signInRecordMapper;
|
||||
@Resource
|
||||
private MemberSignInConfigMapper signInConfigMapper;
|
||||
@Resource
|
||||
private MemberPointRecordService pointRecordService;
|
||||
@Resource
|
||||
private MemberLevelService memberLevelService;
|
||||
|
||||
@Resource
|
||||
private MemberUserApi memberUserApi;
|
||||
|
||||
@Override
|
||||
public AppMemberSignInSummaryRespVO getSignInRecordSummary(Long userId) {
|
||||
AppMemberSignInSummaryRespVO vo = new AppMemberSignInSummaryRespVO();
|
||||
AppMemberSignInSummaryRespVO vo = new AppMemberSignInSummaryRespVO();
|
||||
vo.setTotalDay(0);
|
||||
vo.setContinuousDay(0);
|
||||
vo.setTodaySignIn(false);
|
||||
//获取用户签到的记录,按照天数倒序获取
|
||||
List <MemberSignInRecordDO> signInRecordDOList = signInRecordMapper.selectListByUserId(userId);
|
||||
List<MemberSignInRecordDO> signInRecordDOList = signInRecordMapper.selectListByUserId(userId);
|
||||
// TODO @xiaqing:if 空的时候,直接 return;这样括号少,逻辑更简洁;
|
||||
if(!CollectionUtils.isEmpty(signInRecordDOList)){
|
||||
if (!CollectionUtils.isEmpty(signInRecordDOList)) {
|
||||
//设置总签到天数
|
||||
vo.setTotalDay(signInRecordDOList.size()); // TODO @xiaqing:是不是不用读取 signInRecordDOList 所有的,而是 count下,然后另外再读取一条最后一条;
|
||||
//判断当天是否有签到复用校验方法
|
||||
@ -61,11 +71,11 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService
|
||||
try {
|
||||
validSignDay(signInRecordDOList.get(0));
|
||||
vo.setTodaySignIn(false);
|
||||
}catch (Exception e){
|
||||
} catch (Exception e) {
|
||||
vo.setTodaySignIn(true);
|
||||
}
|
||||
//如果当天签到了则说明连续签到天数有意义,否则直接用默认值0
|
||||
if(vo.getTodaySignIn()){
|
||||
if (vo.getTodaySignIn()) {
|
||||
//下方计算连续签到从2天开始,此处直接设置一天连续签到
|
||||
vo.setContinuousDay(1);
|
||||
//判断连续签到天数
|
||||
@ -73,10 +83,10 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService
|
||||
for (int i = 1; i < signInRecordDOList.size(); i++) {
|
||||
//前一天减1等于当前天数则说明连续,继续循环
|
||||
LocalDate cur = signInRecordDOList.get(i).getCreateTime().toLocalDate();
|
||||
LocalDate pre = signInRecordDOList.get(i-1).getCreateTime().toLocalDate();
|
||||
if(1==daysBetween(cur,pre)){
|
||||
vo.setContinuousDay(i+1);
|
||||
}else{
|
||||
LocalDate pre = signInRecordDOList.get(i - 1).getCreateTime().toLocalDate();
|
||||
if (1 == daysBetween(cur, pre)) {
|
||||
vo.setContinuousDay(i + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -87,16 +97,16 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService
|
||||
return vo;
|
||||
}
|
||||
|
||||
private long daysBetween(LocalDate date1,LocalDate date2){
|
||||
private long daysBetween(LocalDate date1, LocalDate date2) {
|
||||
return ChronoUnit.DAYS.between(date1, date2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult <MemberSignInRecordDO> getSignInRecordPage(MemberSignInRecordPageReqVO pageReqVO) {
|
||||
public PageResult<MemberSignInRecordDO> getSignInRecordPage(MemberSignInRecordPageReqVO pageReqVO) {
|
||||
// 根据用户昵称查询出用户ids
|
||||
Set <Long> userIds = null;
|
||||
Set<Long> userIds = null;
|
||||
if (StringUtils.isNotBlank(pageReqVO.getNickname())) {
|
||||
List <MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageReqVO.getNickname());
|
||||
List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageReqVO.getNickname());
|
||||
// 如果查询用户结果为空直接返回无需继续查询
|
||||
if (CollectionUtils.isEmpty(users)) {
|
||||
return PageResult.empty();
|
||||
@ -113,50 +123,63 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public MemberSignInRecordDO createSignRecord(Long userId) {
|
||||
// 获取当前用户签到的最大天数
|
||||
// TODO @xiaqing:db 操作,dou封装到 mapper 中;
|
||||
// TODO @xiaqing:maxSignDay,是不是变量叫 lastRecord 会更容易理解哈;
|
||||
MemberSignInRecordDO maxSignDay = signInRecordMapper.selectOne(new LambdaQueryWrapperX <MemberSignInRecordDO>()
|
||||
MemberSignInRecordDO maxSignDay = signInRecordMapper.selectOne(new LambdaQueryWrapperX<MemberSignInRecordDO>()
|
||||
.eq(MemberSignInRecordDO::getUserId, userId)
|
||||
.orderByDesc(MemberSignInRecordDO::getDay)
|
||||
.last("limit 1"));
|
||||
// 判断是否重复签到
|
||||
validSignDay(maxSignDay);
|
||||
|
||||
// TODO @xiaqing:可以使用 // 进行注释
|
||||
/**1.查询出当前签到的天数**/
|
||||
// 1. 查询出当前签到的天数
|
||||
MemberSignInRecordDO sign = new MemberSignInRecordDO().setUserId(userId); // TODO @xiaqing:应该使用 record 变量,会更合适
|
||||
sign.setDay(1); // 设置签到初始化天数
|
||||
sign.setPoint(0); // 设置签到分数默认为 0
|
||||
sign.setPoint(0); // 设置签到积分默认为 0
|
||||
sign.setExperience(0); // 设置签到经验默认为 0
|
||||
// 如果不为空则修改当前签到对应的天数
|
||||
// TODO @xiaqing:应该是要判断连续哈,就是昨天;
|
||||
if (maxSignDay != null) {
|
||||
sign.setDay(maxSignDay.getDay() + 1);
|
||||
}
|
||||
/**2.获取签到对应的分数**/
|
||||
// 2. 获取签到对应的积分数
|
||||
// 获取所有的签到规则,按照天数排序,只获取启用的 TODO @xiaqing:不要使用 signInConfigMapper 直接查询,而是要通过 SigninConfigService;
|
||||
List <MemberSignInConfigDO> configDOList = signInConfigMapper.selectList(new LambdaQueryWrapperX <MemberSignInConfigDO>()
|
||||
List<MemberSignInConfigDO> configDOList = signInConfigMapper.selectList(new LambdaQueryWrapperX<MemberSignInConfigDO>()
|
||||
.eq(MemberSignInConfigDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
|
||||
.orderByAsc(MemberSignInConfigDO::getDay));
|
||||
// 如果签到的天数大于最大启用的规则天数,直接给最大签到的分数
|
||||
// 如果签到的天数大于最大启用的规则天数,直接给最大签到的积分数
|
||||
// TODO @xiaqing:超过最大配置的天数,应该直接重置到第一天哈;
|
||||
MemberSignInConfigDO lastConfig = configDOList.get(configDOList.size() - 1);
|
||||
if (sign.getDay() > lastConfig.getDay()) {
|
||||
sign.setPoint(lastConfig.getPoint());
|
||||
sign.setExperience(lastConfig.getExperience());
|
||||
} else {
|
||||
configDOList.forEach(el -> {
|
||||
// 循环匹配对应天数,设置对应分数
|
||||
// 循环匹配对应天数,设置对应积分数
|
||||
// TODO @xiaqing:使用 equals;另外,这种不应该去遍历比较,从可读性来说,应该 CollUtil.findOne()
|
||||
if (el.getDay() == sign.getDay()) {
|
||||
sign.setPoint(el.getPoint());
|
||||
sign.setExperience(el.getExperience());
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// 3. 插入当前签到获取的分数
|
||||
// 3. 插入签到记录
|
||||
signInRecordMapper.insert(sign);
|
||||
|
||||
// 4. 增加积分
|
||||
if (!ObjectUtils.equalsAny(sign.getPoint(), null, 0)) {
|
||||
pointRecordService.createPointRecord(userId, sign.getPoint(), MemberPointBizTypeEnum.SIGN, String.valueOf(sign.getId()));
|
||||
}
|
||||
// 5. 增加经验
|
||||
if (!ObjectUtils.equalsAny(sign.getPoint(), null, 0)) {
|
||||
memberLevelService.addExperience(userId, sign.getExperience(), MemberExperienceBizTypeEnum.SIGN_IN, String.valueOf(sign.getId()));
|
||||
}
|
||||
|
||||
return sign;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
|
||||
import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
|
||||
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
|
||||
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
|
||||
import cn.iocoder.yudao.module.member.mq.producer.user.RegisterCouponProducer;
|
||||
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
|
||||
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
|
||||
@ -58,6 +59,9 @@ public class MemberUserServiceImpl implements MemberUserService {
|
||||
@Resource
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Resource
|
||||
private RegisterCouponProducer registerCouponProducer;
|
||||
|
||||
@Override
|
||||
public MemberUserDO getUserByMobile(String mobile) {
|
||||
return memberUserMapper.selectByMobile(mobile);
|
||||
@ -89,6 +93,9 @@ public class MemberUserServiceImpl implements MemberUserService {
|
||||
user.setPassword(encodePassword(password)); // 加密密码
|
||||
user.setRegisterIp(registerIp);
|
||||
memberUserMapper.insert(user);
|
||||
|
||||
// 发送 MQ 消息,发放新人券
|
||||
registerCouponProducer.sendMailSendMessage(user.getId());
|
||||
return user;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.module.pay.controller.admin.wallet;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.PayWalletRespVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.PayWalletUserReqVO;
|
||||
import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletConvert;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
|
||||
import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 用户钱包")
|
||||
@RestController
|
||||
@RequestMapping("/pay/wallet")
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class PayWalletController {
|
||||
|
||||
@Resource
|
||||
private PayWalletService payWalletService;
|
||||
|
||||
@GetMapping("/user-wallet")
|
||||
@PreAuthorize("@ss.hasPermission('pay:wallet:query')")
|
||||
@Operation(summary = "获得用户钱包明细")
|
||||
public CommonResult<PayWalletRespVO> getByUser(PayWalletUserReqVO reqVO) {
|
||||
PayWalletDO wallet = payWalletService.getWalletByUserIdAndType(reqVO.getUserId(), reqVO.getUserType());
|
||||
return success(PayWalletConvert.INSTANCE.convert02(wallet));
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 用户钱包 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||
*/
|
||||
@Data
|
||||
public class PayWalletBaseVO {
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20020")
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "用户类型不能为空")
|
||||
private Byte userType;
|
||||
|
||||
@Schema(description = "余额,单位分", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "余额,单位分不能为空")
|
||||
private Integer balance;
|
||||
|
||||
@Schema(description = "累计支出,单位分", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "累计支出,单位分不能为空")
|
||||
private Integer totalExpense;
|
||||
|
||||
@Schema(description = "累计充值,单位分", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "累计充值,单位分不能为空")
|
||||
private Integer totalRecharge;
|
||||
|
||||
@Schema(description = "冻结金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "20737")
|
||||
@NotNull(message = "冻结金额,单位分不能为空")
|
||||
private Integer freezePrice;
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 用户钱包 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class PayWalletRespVO extends PayWalletBaseVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29528")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 用户钱包明细 Request VO")
|
||||
@Data
|
||||
public class PayWalletUserReqVO {
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "用户类型不能为空")
|
||||
@InEnum(value = UserTypeEnum.class, message = "用户类型必须是 {value}")
|
||||
private Integer userType;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.pay.convert.wallet;
|
||||
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.PayWalletRespVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.wallet.AppPayWalletRespVO;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
|
||||
import org.mapstruct.Mapper;
|
||||
@ -11,4 +12,6 @@ public interface PayWalletConvert {
|
||||
PayWalletConvert INSTANCE = Mappers.getMapper(PayWalletConvert.class);
|
||||
|
||||
AppPayWalletRespVO convert(PayWalletDO bean);
|
||||
|
||||
PayWalletRespVO convert02(PayWalletDO wallet);
|
||||
}
|
||||
|
@ -13,10 +13,10 @@ public interface PayWalletService {
|
||||
|
||||
/**
|
||||
* 获取钱包信息
|
||||
*
|
||||
* <p>
|
||||
* 如果不存在,则创建钱包。由于用户注册时候不会创建钱包
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param userId 用户编号
|
||||
* @param userType 用户类型
|
||||
*/
|
||||
PayWalletDO getOrCreateWallet(Long userId, Integer userType);
|
||||
@ -31,10 +31,10 @@ public interface PayWalletService {
|
||||
/**
|
||||
* 钱包订单支付
|
||||
*
|
||||
* @param userId 用户 id
|
||||
* @param userType 用户类型
|
||||
* @param userId 用户 id
|
||||
* @param userType 用户类型
|
||||
* @param outTradeNo 外部订单号
|
||||
* @param price 金额
|
||||
* @param price 金额
|
||||
*/
|
||||
PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price);
|
||||
|
||||
@ -43,17 +43,17 @@ public interface PayWalletService {
|
||||
*
|
||||
* @param outRefundNo 外部退款号
|
||||
* @param refundPrice 退款金额
|
||||
* @param reason 退款原因
|
||||
* @param reason 退款原因
|
||||
*/
|
||||
PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason);
|
||||
|
||||
/**
|
||||
* 扣减钱包余额
|
||||
*
|
||||
* @param walletId 钱包 id
|
||||
* @param bizId 业务关联 id
|
||||
* @param bizType 业务关联分类
|
||||
* @param price 扣减金额
|
||||
* @param walletId 钱包 id
|
||||
* @param bizId 业务关联 id
|
||||
* @param bizType 业务关联分类
|
||||
* @param price 扣减金额
|
||||
* @return 钱包流水
|
||||
*/
|
||||
PayWalletTransactionDO reduceWalletBalance(Long walletId, Long bizId,
|
||||
@ -63,9 +63,9 @@ public interface PayWalletService {
|
||||
* 增加钱包余额
|
||||
*
|
||||
* @param walletId 钱包 id
|
||||
* @param bizId 业务关联 id
|
||||
* @param bizType 业务关联分类
|
||||
* @param price 增加金额
|
||||
* @param bizId 业务关联 id
|
||||
* @param bizType 业务关联分类
|
||||
* @param price 增加金额
|
||||
* @return 钱包流水
|
||||
*/
|
||||
PayWalletTransactionDO addWalletBalance(Long walletId, String bizId,
|
||||
@ -74,15 +74,25 @@ public interface PayWalletService {
|
||||
/**
|
||||
* 冻结钱包部分余额
|
||||
*
|
||||
* @param id 钱包编号
|
||||
* @param id 钱包编号
|
||||
* @param price 冻结金额
|
||||
*/
|
||||
void freezePrice(Long id, Integer price);
|
||||
|
||||
/**
|
||||
* 解冻钱包余额
|
||||
* @param id 钱包编号
|
||||
*
|
||||
* @param id 钱包编号
|
||||
* @param price 解冻金额
|
||||
*/
|
||||
void unFreezePrice(Long id, Integer price);
|
||||
|
||||
/**
|
||||
* 获得用户的钱包明细
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param userType 用户类型
|
||||
* @return 用户的钱包明细
|
||||
*/
|
||||
PayWalletDO getWalletByUserIdAndType(Long userId, Integer userType);
|
||||
}
|
||||
|
@ -195,4 +195,9 @@ public class PayWalletServiceImpl implements PayWalletService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayWalletDO getWalletByUserIdAndType(Long userId, Integer userType) {
|
||||
return walletMapper.selectByUserIdAndType(userId, userType);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user