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