Compare commits
135 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5b1c38f71 | ||
|
|
e1f834313a | ||
|
|
dedcc0a556 | ||
|
|
33fcce1cc9 | ||
|
|
85c8c5d021 | ||
|
|
2ab2c4ff5d | ||
|
|
feff49c79b | ||
|
|
c813ed0062 | ||
|
|
f658d43a5a | ||
|
|
fe0b9c37a4 | ||
|
|
28cc0617c3 | ||
|
|
f2cb6b56ea | ||
|
|
81b7da07f4 | ||
|
|
db3f775c50 | ||
|
|
93a45319ac | ||
|
|
7627614284 | ||
|
|
ca5887028a | ||
|
|
1a3736fd29 | ||
|
|
09d00260f6 | ||
|
|
2e019ef933 | ||
|
|
6acc99c7cf | ||
|
|
b57e7813d6 | ||
|
|
09e6f4a1a1 | ||
|
|
872bb220dc | ||
|
|
2498e57600 | ||
|
|
cfbb673387 | ||
|
|
05db6501f7 | ||
|
|
a5aa090f4a | ||
|
|
09aae17a02 | ||
|
|
7f5739f89b | ||
|
|
131d4eb156 | ||
|
|
ffa0b0db30 | ||
|
|
7bd0084802 | ||
|
|
d88762f3ab | ||
|
|
ebdbed6d08 | ||
|
|
efdf505e63 | ||
|
|
98f25179d3 | ||
|
|
9a0c7dd73d | ||
|
|
0cf464e549 | ||
|
|
2e6ddeafdd | ||
|
|
633b94c375 | ||
|
|
6441018d95 | ||
|
|
e706431df5 | ||
|
|
db1a3566ae | ||
|
|
9225b4ff10 | ||
|
|
586a507bb1 | ||
|
|
034f29c734 | ||
|
|
478dd1d201 | ||
|
|
554aed024c | ||
|
|
b2e0fe1de4 | ||
|
|
b69a558df0 | ||
|
|
2f180a73ed | ||
|
|
82f3223a03 | ||
|
|
cfe48d539b | ||
|
|
8ef00ae285 | ||
|
|
ed032653ee | ||
|
|
9108a1585c | ||
|
|
d4855b702b | ||
|
|
40822ca05b | ||
|
|
4dac80f084 | ||
|
|
8609216ef5 | ||
|
|
9678c7f506 | ||
|
|
63cdebdf1f | ||
|
|
e89be8eb8c | ||
|
|
3559971a8d | ||
|
|
dc1d1a7e7e | ||
|
|
10ecce1e0d | ||
|
|
2520c27f77 | ||
|
|
63d684c972 | ||
|
|
35739b64a3 | ||
|
|
ddcda57a08 | ||
|
|
16ae69ed06 | ||
|
|
fd067d8abf | ||
|
|
42b3c72977 | ||
|
|
e34b4172b8 | ||
|
|
30d6ab64f8 | ||
|
|
2e8c40bcf3 | ||
|
|
f2385c3ace | ||
|
|
a45355b125 | ||
|
|
b3bb771066 | ||
|
|
068c6b986e | ||
|
|
18e2c89891 | ||
|
|
7b485753a6 | ||
|
|
8556d27173 | ||
|
|
d677aabbf4 | ||
|
|
aaa0748409 | ||
|
|
57ee156798 | ||
|
|
5ae4d8b4fa | ||
|
|
681327274c | ||
|
|
6ab2888fd0 | ||
|
|
80a0e0e8c7 | ||
|
|
80773e2d58 | ||
|
|
065bcc8a55 | ||
|
|
9398413999 | ||
|
|
cf623f6756 | ||
|
|
1b316baac6 | ||
|
|
4fc1d0e346 | ||
|
|
159fe37120 | ||
|
|
6f9486f065 | ||
|
|
94da71336a | ||
|
|
8c5ce396b2 | ||
|
|
0063820fdf | ||
|
|
fe80edebbd | ||
|
|
6b59c1e643 | ||
|
|
1b52381c71 | ||
|
|
763519876e | ||
|
|
cede181bc0 | ||
|
|
cb776eb4c0 | ||
|
|
8ed4f6eb3c | ||
|
|
9cf97f3203 | ||
|
|
2a984b8c56 | ||
|
|
22ecf48168 | ||
|
|
89422b2736 | ||
|
|
bcd4bf4ff1 | ||
|
|
a263bc6301 | ||
|
|
27ae773e20 | ||
|
|
085b61c2ab | ||
|
|
c7682680ee | ||
|
|
a301432a87 | ||
|
|
526de18a42 | ||
|
|
c940bf6cb2 | ||
|
|
a7643a6b93 | ||
|
|
24f6b9e80f | ||
|
|
d349616957 | ||
|
|
f7c9ba820d | ||
|
|
f99f59963a | ||
|
|
caaf9c74f3 | ||
|
|
076f47f5c4 | ||
|
|
f0e4e4c2bc | ||
|
|
c87fe45dfa | ||
|
|
49fd03df7f | ||
|
|
6deed61311 | ||
|
|
6311767320 | ||
|
|
2463d1b5bb | ||
|
|
2d052ffb1a |
30
.cursor/rules/01-project-overview.mdc
Normal file
30
.cursor/rules/01-project-overview.mdc
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# Lilishop Project Overview
|
||||
|
||||
This is a comprehensive B2B2C e-commerce system built with Spring Boot (backend) and Vue/uniapp (frontend). The project supports multi-tenant merchant access and distributed deployment.
|
||||
|
||||
## Key Project Components
|
||||
|
||||
### Backend APIs
|
||||
- [buyer-api/](mdc:buyer-api) - Buyer-facing APIs for shopping functionality
|
||||
- [seller-api/](mdc:seller-api) - Merchant-facing APIs for store management
|
||||
- [manager-api/](mdc:manager-api) - Platform admin APIs
|
||||
- [common-api/](mdc:common-api) - Shared API components
|
||||
- [im-api/](mdc:im-api) - Instant messaging APIs
|
||||
|
||||
### Core Components
|
||||
- [framework/](mdc:framework) - Core framework and shared utilities
|
||||
- [consumer/](mdc:consumer) - Message queue consumers
|
||||
- [config/](mdc:config) - System configuration files
|
||||
|
||||
### Documentation
|
||||
- [docs/](mdc:docs) - Project documentation
|
||||
- [README.md](mdc:README.md) - Project overview and setup instructions
|
||||
|
||||
### Build & Deployment
|
||||
- [pom.xml](mdc:pom.xml) - Maven project configuration
|
||||
- [deploy-api.yml](mdc:deploy-api.yml) - Deployment configuration
|
||||
38
.cursor/rules/02-technical-architecture.mdc
Normal file
38
.cursor/rules/02-technical-architecture.mdc
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# Technical Architecture
|
||||
|
||||
## Backend Stack
|
||||
- Spring Boot - Core framework
|
||||
- Spring MVC - Web framework
|
||||
- Mybatis-Plus - ORM framework
|
||||
- Spring Security - Security framework
|
||||
- JWT - Authentication
|
||||
- RocketMQ - Message queue
|
||||
- Redis & MongoDB - Caching
|
||||
- Elasticsearch - Search engine
|
||||
- MySQL - Primary database
|
||||
- Sharding - Database sharding
|
||||
- XXL-Job - Distributed scheduling
|
||||
|
||||
## Frontend Stack
|
||||
### Admin & Seller Portals ([admin/](mdc:admin))
|
||||
- Vue.js - Frontend framework
|
||||
- iView - UI components
|
||||
- Vuex - State management
|
||||
- Vue Router - Routing
|
||||
- Axios - HTTP client
|
||||
|
||||
### Mobile Applications
|
||||
- Uni-app - Cross-platform framework
|
||||
- uViewui - UI components
|
||||
- SCSS - Styling
|
||||
|
||||
## Infrastructure
|
||||
- Nginx - Load balancing & reverse proxy
|
||||
- Aliyun OSS - Object storage
|
||||
- Docker - Containerization
|
||||
- Docker Compose - Container orchestration
|
||||
43
.cursor/rules/03-development-guidelines.mdc
Normal file
43
.cursor/rules/03-development-guidelines.mdc
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# Development Guidelines
|
||||
|
||||
## Project Setup
|
||||
1. Ensure you have the following prerequisites:
|
||||
- JDK 1.8+
|
||||
- Maven 3.x
|
||||
- MySQL 5.7+
|
||||
- Redis
|
||||
- RocketMQ
|
||||
- Elasticsearch
|
||||
- Node.js 12+
|
||||
|
||||
## Database Setup
|
||||
- Initial database scripts can be found in [DB/](mdc:DB)
|
||||
- For Docker deployment, refer to docker-compose configuration
|
||||
|
||||
## API Development Guidelines
|
||||
1. All new APIs should be placed in appropriate modules:
|
||||
- Customer-facing APIs in [buyer-api/](mdc:buyer-api)
|
||||
- Merchant APIs in [seller-api/](mdc:seller-api)
|
||||
- Admin APIs in [manager-api/](mdc:manager-api)
|
||||
- Shared components in [common-api/](mdc:common-api)
|
||||
|
||||
2. Follow RESTful API conventions:
|
||||
- Use appropriate HTTP methods (GET, POST, PUT, DELETE)
|
||||
- Use consistent URL patterns
|
||||
- Implement proper error handling
|
||||
|
||||
## Security Guidelines
|
||||
1. All sensitive operations must be authenticated
|
||||
2. Use Spring Security for access control
|
||||
3. Store sensitive configuration in environment variables
|
||||
4. Never commit sensitive credentials to version control
|
||||
|
||||
## Testing
|
||||
1. Write unit tests for critical business logic
|
||||
2. Ensure API endpoints are properly documented
|
||||
3. Test both success and error scenarios
|
||||
37
.cursor/rules/04-deployment-guide.mdc
Normal file
37
.cursor/rules/04-deployment-guide.mdc
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# Deployment Guide
|
||||
|
||||
## Local Development Setup
|
||||
1. Clone the repository
|
||||
2. Import as Maven project
|
||||
3. Configure environment variables in [config/](mdc:config)
|
||||
4. Start required services (MySQL, Redis, RocketMQ, Elasticsearch)
|
||||
5. Run individual API modules
|
||||
|
||||
## Docker Deployment
|
||||
- Use [deploy-api.yml](mdc:deploy-api.yml) for container configuration
|
||||
- Execute [docker-image.sh](mdc:docker-image.sh) to build images
|
||||
|
||||
## Production Deployment
|
||||
1. Configure load balancer (Nginx recommended)
|
||||
2. Set up database replication/clustering
|
||||
3. Configure message queue clusters
|
||||
4. Set up monitoring and logging
|
||||
5. Configure CDN for static assets
|
||||
|
||||
## Configuration Files
|
||||
- Database: [DB/](mdc:DB)
|
||||
- API deployment: [deploy-api.yml](mdc:deploy-api.yml)
|
||||
- Docker scripts: [docker-image.sh](mdc:docker-image.sh)
|
||||
|
||||
## Deployment Checklist
|
||||
1. Database migration and backup
|
||||
2. Environment variable configuration
|
||||
3. Service dependencies verification
|
||||
4. SSL certificate setup
|
||||
5. Monitoring and alerting setup
|
||||
6. Backup and recovery procedures
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
/**
|
||||
交易唤醒表,增加交易流水详情
|
||||
*/
|
||||
ALTER TABLE li_order_item ADD `is_refund` varchar(255) DEFAULT NULL COMMENT '是否退款';
|
||||
|
||||
/**
|
||||
交易表增加订单状态字段
|
||||
*/
|
||||
ALTER TABLE li_order_item ADD `refund_price` decimal(10,2) DEFAULT NULL COMMENT '退款金额';
|
||||
@@ -1,20 +0,0 @@
|
||||
|
||||
/**
|
||||
文件表增加拥有者名称
|
||||
*/
|
||||
ALTER TABLE li_file ADD `owner_name` varchar(255) DEFAULT NULL COMMENT '拥有者名称';
|
||||
|
||||
/**
|
||||
初始化文件拥有者名称
|
||||
*/
|
||||
UPDATE li_file f JOIN li_store s ON f.owner_id = s.id
|
||||
SET f.owner_name = s.store_name
|
||||
WHERE user_enums = 'STORE';
|
||||
|
||||
UPDATE li_file f JOIN li_admin_user a ON f.owner_id = a.id
|
||||
SET f.owner_name = a.nick_name
|
||||
WHERE user_enums = 'MANAGER';
|
||||
|
||||
UPDATE li_file f JOIN li_member m ON f.owner_id = m.id
|
||||
SET f.owner_name = m.nick_name
|
||||
WHERE user_enums = 'MEMBER';
|
||||
14
DB/index.sql
Normal file
14
DB/index.sql
Normal file
@@ -0,0 +1,14 @@
|
||||
-- 针对WHERE条件、排序和分组的组合索引
|
||||
CREATE INDEX idx_order_delete_flag_create_time_id_sn ON li_order (delete_flag, create_time DESC, id DESC, sn);
|
||||
|
||||
-- 针对WHERE条件和连接条件的组合索引
|
||||
CREATE INDEX idx_order_status_delete_flag_sn ON li_order (order_status, delete_flag, sn);
|
||||
|
||||
-- 针对连接条件的索引
|
||||
CREATE INDEX idx_order_item_order_sn ON li_order_item (order_sn);
|
||||
|
||||
-- 针对过滤条件、排序字段的组合索引
|
||||
CREATE INDEX idx_li_member_disabled_create_time ON li_member (disabled, create_time DESC);
|
||||
|
||||
-- 针对过滤条件、排序字段的组合索引
|
||||
CREATE INDEX idx_li_goods_delete_flag_create_time ON li_goods (delete_flag, create_time DESC);
|
||||
@@ -68,8 +68,6 @@ CREATE TABLE `li_order_package_item` (
|
||||
*/
|
||||
ALTER TABLE li_order_item ADD `deliver_number` int DEFAULT NULL COMMENT '发货数量';
|
||||
|
||||
ALTER TABLE li_goods_sku ADD `alert_quantity` int DEFAULT NULL COMMENT '预警库存';
|
||||
|
||||
/*
|
||||
sku增加预警库存
|
||||
*/
|
||||
@@ -105,7 +103,7 @@ WHERE
|
||||
sf.flow_type = 'REFUND'
|
||||
AND sf.store_id=b.store_id
|
||||
AND sf.create_time BETWEEN b.start_time
|
||||
AND b.end_time),0)
|
||||
AND b.end_time),0);
|
||||
|
||||
UPDATE li_bill b
|
||||
SET b.kanjia_refund_settlement_price =IFNULL((
|
||||
@@ -119,3 +117,57 @@ SET b.kanjia_refund_settlement_price =IFNULL((
|
||||
AND sf.create_time BETWEEN b.start_time
|
||||
AND b.end_time),0);
|
||||
|
||||
/**
|
||||
文件表增加拥有者名称
|
||||
*/
|
||||
ALTER TABLE li_file ADD `owner_name` varchar(255) DEFAULT NULL COMMENT '拥有者名称';
|
||||
|
||||
/**
|
||||
初始化文件拥有者名称
|
||||
*/
|
||||
UPDATE li_file f JOIN li_store s ON f.owner_id = s.id
|
||||
SET f.owner_name = s.store_name
|
||||
WHERE user_enums = 'STORE';
|
||||
|
||||
UPDATE li_file f JOIN li_admin_user a ON f.owner_id = a.id
|
||||
SET f.owner_name = a.nick_name
|
||||
WHERE user_enums = 'MANAGER';
|
||||
|
||||
UPDATE li_file f JOIN li_member m ON f.owner_id = m.id
|
||||
SET f.owner_name = m.nick_name
|
||||
WHERE user_enums = 'MEMBER';
|
||||
|
||||
ALTER TABLE `li_order`
|
||||
ADD COLUMN `seller_remark` varchar(255) NULL COMMENT '商家订单备注' AFTER `remark`;
|
||||
|
||||
|
||||
ALTER TABLE `li_distribution_cash`
|
||||
ADD COLUMN `name` varchar(255) NULL COMMENT '会员姓名';
|
||||
ALTER TABLE `li_distribution_cash`
|
||||
ADD COLUMN `id_number` varchar(255) NULL COMMENT '身份证号' ;
|
||||
ALTER TABLE `li_distribution_cash`
|
||||
ADD COLUMN `settlement_bank_account_name` varchar(255) NULL COMMENT '结算银行开户行名称' ;
|
||||
ALTER TABLE `li_distribution_cash`
|
||||
ADD COLUMN `settlement_bank_account_num` varchar(255) NULL COMMENT '结算银行开户账号' ;
|
||||
ALTER TABLE `li_distribution_cash`
|
||||
ADD COLUMN `settlement_bank_branch_name` varchar(255) NULL COMMENT '结算银行开户支行名称' ;
|
||||
|
||||
ALTER TABLE `li_distribution` ADD `distribution_order_price` decimal(10,2) DEFAULT NULL COMMENT '分销订单金额';
|
||||
|
||||
ALTER TABLE `li_distribution_order` ADD `refund_num` int DEFAULT NULL COMMENT '退款商品数量';
|
||||
|
||||
ALTER TABLE `li_store_flow` ADD `bill_time` datetime(6) DEFAULT NULL COMMENT '结算时间';
|
||||
ALTER TABLE `li_store_flow` ADD `full_refund` bit(1) DEFAULT NULL COMMENT '是否全部退款';
|
||||
ALTER TABLE `li_store_flow` ADD `profit_sharing_status` varchar(255) NULL COMMENT '分账状态';
|
||||
ALTER TABLE `li_store_flow` ADD `profit_sharing` varchar(255) NULL COMMENT '分账详情';
|
||||
|
||||
|
||||
|
||||
INSERT INTO `lilishop`.`li_setting` (`id`, `create_by`, `create_time`, `delete_flag`, `update_by`, `update_time`, `setting_value`) VALUES ('CONNECT_SETTING', 'admin', '2024-07-07 13:55:38.686000', b'0', NULL, NULL, '{\"callbackUrl\":\"https://buyer-api.pickmall.cn\",\"pc\":\"https://pc-b2b2c.pickmall.cn\",\"wap\":\"https://m-b2b2c.pickmall.cn\"}');
|
||||
UPDATE `lilishop`.`li_setting` SET `create_by` = 'admin', `create_time` = '2021-01-23 02:18:03.299000', `delete_flag` = b'0', `update_by` = 'admin', `update_time` = '2024-07-07 13:53:44.732000', `setting_value` = '{\"accessKeyId\":\"test\",\"tencentSdkAppId\":\"null\",\"registerTemplateCode\":\"SMS_205755298\",\"huaweiSender\":\"null\",\"signName\":\"lili\",\"tencentSecretId\":\"null\",\"huaweiAppKey\":\"null\",\"isTestModel\":\"true\",\"tencentSecretKey\":\"null\",\"type\":\"ALI\",\"accessSecret\":\"test\",\"tencentSignName\":\"null\",\"huaweiSignature\":\"null\",\"payPasswordTemplateCode\":\"SMS_205755301\",\"walletPasswordTemplateCode\":\"SMS_205755297\",\"findPasswordTemplateCode\":\"SMS_205755301\",\"huaweiAppSecret\":\"null\",\"loginTemplateCode\":\"SMS_205755300\"}' WHERE `id` = 'SMS_SETTING';
|
||||
|
||||
|
||||
|
||||
ALTER TABLE li_store_logistics ADD `partner_name` varchar(255) DEFAULT NULL COMMENT '电子面单客户账户名称';
|
||||
|
||||
|
||||
285
README.md
285
README.md
@@ -1,204 +1,167 @@
|
||||
## Lilishop 商城系统
|
||||
# Lilishop B2B2C 商城系统
|
||||
|
||||
[](https://github.com/hongyehuicheng/lilishop)
|
||||
[](https://gitee.com/beijing_hongye_huicheng/lilishop)
|
||||
[](https://www.gnu.org/licenses/agpl-3.0.html)
|
||||
[](https://spring.io/projects/spring-boot)
|
||||
[](https://vuejs.org/)
|
||||
[](https://uniapp.dcloud.io/)
|
||||
|
||||
---
|
||||
|
||||
### 1. 项目简介
|
||||
|
||||
**Lilishop** 是一款功能完善的B2B2C多商户商城系统,采用前后端分离架构,全端代码开源。后端基于 **SpringBoot** 构建,具备高内聚、低耦合的特性,支持分布式部署。前端覆盖PC、H5、小程序和APP,基于 **Vue** 和 **uni-app** 开发。
|
||||
|
||||
- **官方网站**: <https://pickmall.cn>
|
||||
- **官方文档**: <https://docs.pickmall.cn>
|
||||
- **Gitee 仓库**: <https://gitee.com/beijing_hongye_huicheng/lilishop>
|
||||
- **GitHub 仓库**: <https://github.com/lilishop/lilishop>
|
||||
|
||||
|
||||
### 商城介绍
|
||||
**官网**:https://pickmall.cn
|
||||
---
|
||||
|
||||
Lilishop商城系统支持商家入驻,后端基于SpringBoot 研发,前端使用 Vue、uniapp开发, **系统全端全部代码开源**
|
||||
### 2. 核心特性
|
||||
|
||||
前后端分离,支持分布式部署,支持Docker,各个API独立,并且有独立的消费者。
|
||||
- **全端覆盖**: 一套代码库支持PC、H5、小程序、APP,降低开发和维护成本。
|
||||
- **商家入驻**: 支持多商家入驻,构建平台化电商生态。
|
||||
- **分布式架构**: 后端API服务化,支持独立部署和弹性伸缩。
|
||||
- **前后端分离**: 清晰的职责划分,便于团队协作和独立开发。
|
||||
- **容器化支持**: 提供Docker镜像和docker-compose配置,实现一键部署。
|
||||
- **功能完善**: 涵盖会员、订单、商品、促销、店铺、运营、统计等完整电商业务模块。
|
||||
|
||||
### 商城 API/消费者 聚合版
|
||||
api不需要单独部署,只需启动一个jar包就可以正常运转 如有需要,可以点击跳转
|
||||
https://gitee.com/beijing_hongye_huicheng/lilishop-simplify
|
||||
---
|
||||
|
||||
### 开发/使用/常见问题 帮助文档
|
||||
### 3. 在线演示
|
||||
|
||||
https://docs.pickmall.cn
|
||||
**注意**: 演示站手机验证码统一为 `111111`。演示环境部署于 `master` 分支。
|
||||
|
||||
- **平台管理端**: <https://admin-b2b2c.pickmall.cn>
|
||||
- 账号: `admin`
|
||||
- 密码: `123456`
|
||||
- **店铺管理端**: <https://store-b2b2c.pickmall.cn>
|
||||
- 账号: `13011111111`
|
||||
- 密码: `111111`
|
||||
- **商城PC端**: <https://pc-b2b2c.pickmall.cn>
|
||||
- **移动端 (H5/小程序/APP)**:
|
||||

|
||||
|
||||
#### 欢迎交流需求,交流业务,交流技术(基础问题自行解决,其他问题先看文档后提问)
|
||||
---
|
||||
|
||||
#### 不用削尖脑袋往老群里加,老群活跃度较低,很多潜水党,新群相对而言活跃一些 :tw-1f606: :tw-1f606: :tw-1f606: :tw-1f606: :tw-1f606: :tw-1f606:
|
||||
### 4. 快速开始
|
||||
|
||||
#### 开发新手或者不熟悉的同学在群内提问或新开Issue提问前,请先阅读[【提问的智慧】](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md),并确保已查阅过 [【在线文档】](https://docs.pickmall.cn/) ,避免浪费大家的宝贵时间;
|
||||
#### 环境准备与部署
|
||||
详细的本地部署指南,请参考官方文档:
|
||||
[**部署文档 -> 环境准备**](https://docs.pickmall.cn/deply/deply.html)
|
||||
|
||||
##### 交流 qq 1群 961316482 (1群扩建至2000人,还有300坑)
|
||||
##### 交流 qq 2群 875294241(已满)
|
||||
##### 交流 qq 3群 263785057(已满)
|
||||
##### 交流 qq 4群 674617534 (已满)
|
||||
##### 交流 qq 5群 594675235 (已满)
|
||||
##### 交流 qq 6群 917026848
|
||||
#### 数据库初始化
|
||||
- **推荐方式**: 使用项目提供的 `docker-compose` 配置,可自动完成数据库(MySQL, Redis, Elasticsearch等)的部署与初始化。
|
||||
- **手动方式**: 如果您选择手动部署,SQL脚本位于以下地址。请确保获取与您代码版本一致的SQL文件。
|
||||
[**数据库脚本 (Gitee)**](https://gitee.com/beijing_hongye_huicheng/docker/tree/master/init/mysql)
|
||||
|
||||
##### 体验 公众号/小程序/APP 体验,扫描二维码
|
||||
---
|
||||
|
||||

|
||||
### 5. 技术架构
|
||||
|
||||
[](https://gitee.com/beijing_hongye_huicheng/lilishop/stargazers)
|
||||

|
||||
#### 5.1 架构图
|
||||

|
||||
|
||||
#### 5.2 后端技术栈
|
||||
|
||||
#### PS: **演示站点所有环境均部署master分支。如果有演示站点问题,可以反馈,如果演示站点没问题本地运行有问题,需自行处理**
|
||||
| 技术 | 选型 | 备注/用途 |
|
||||
| :-------------- | :-------------- | :--------- |
|
||||
| 核心框架 | Spring Boot | 简化应用开发 |
|
||||
| ORM框架 | Mybatis-Plus | 数据持久化 |
|
||||
| 数据库 | MySQL | 关系型数据存储 |
|
||||
| 消息队列 | RocketMQ | 异步任务与解耦 |
|
||||
| 缓存 | Redis, MongoDB | 数据缓存与存储 |
|
||||
| 搜索引擎 | Elasticsearch | 商品搜索 |
|
||||
| 安全框架 | Spring Security | 认证与授权 |
|
||||
| 分库分表 | ShardingSphere | 数据水平扩展 |
|
||||
| 定时任务 | XXL-Job | 分布式任务调度 |
|
||||
| 认证方案 | JWT | Token |
|
||||
|
||||
#### 5.3 前端技术栈
|
||||
|
||||
### 项目地址
|
||||
**管理端 (平台/商家)**
|
||||
|
||||
gitee : https://gitee.com/beijing_hongye_huicheng
|
||||
|
||||
github 镜像: https://github.com/lilishop?tab=repositories
|
||||
|
||||
商城UI 项目下3个文件夹
|
||||
buyer:买家PC端,seller:商家端,manager:后台管理端
|
||||
|
||||
|
||||
### 演示地址
|
||||
PS:手机验证码为 ‘111111’
|
||||
|
||||
**平台管理端**:https://admin-b2b2c.pickmall.cn 账号:admin/123456
|
||||
|
||||
**店铺管理端**:https://store-b2b2c.pickmall.cn 账号:13011111111/111111
|
||||
|
||||
**商城PC页面**:https://pc-b2b2c.pickmall.cn
|
||||
|
||||
**商城 小程序/公众号/APP**:扫描二维码
|
||||
|
||||

|
||||
|
||||
### 快速本地部署
|
||||
|
||||
[点击跳转](https://docs.pickmall.cn/deploy/%E8%BF%90%E8%A1%8C%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87.html)
|
||||
|
||||
**商城数据库**
|
||||
使用docker-compose部署数据库,自动初始化数据库,不需要手动下载等操作
|
||||
|
||||
如果手动部署,才需要获取sql [点击跳转](https://gitee.com/beijing_hongye_huicheng/docker/tree/master/init/mysql) (PS:这里有与tag版本一致的sql,如果是历史版本,则docker项目也切换至历史版本获取sql即可,历史版本升级则根据java相聚的根目录DB目录下的升级sql,按需执行)。
|
||||
| 技术 | 选型 | 备注/用途 |
|
||||
| :--------- | :--------- | :--------- |
|
||||
| JS框架 | Vue.js | 核心框架 |
|
||||
| UI库 | iView | 界面组件 |
|
||||
| 状态管理 | Vuex | 全局状态管理 |
|
||||
| 路由 | Vue Router | 页面路由 |
|
||||
| HTTP客户端 | axios | API请求 |
|
||||
|
||||
**移动端 (H5/小程序/APP)**
|
||||
|
||||
| 技术 | 选型 | 备注/用途 |
|
||||
| :-------- | :------ | :------------- |
|
||||
| 核心框架 | uni-app | 跨平台开发框架 |
|
||||
| UI库 | uViewUI | 丰富的组件库 |
|
||||
| CSS预处理 | SCSS | 样式开发 |
|
||||
|
||||
### 功能列表
|
||||
|
||||
### 6. 功能清单
|
||||
|
||||
#### 6.1 平台管理端
|
||||
|
||||
#### 平台管理端功能
|
||||
| 模块 | 主要功能 |
|
||||
| :--- | :--------------------------------------------------------------------- |
|
||||
| 首页 | 数据看板、待办事项 |
|
||||
| 会员 | 会员管理、会员评价、积分管理、资金流水、充值管理 |
|
||||
| 订单 | 商品订单、虚拟订单、售后处理、订单投诉、收款与退款流水 |
|
||||
| 商品 | 商品管理、商品审核、分类、品牌、规格、计量单位管理 |
|
||||
| 促销 | 优惠券、秒杀、砍价、拼团、积分商品等营销活动 |
|
||||
| 店铺 | 店铺管理、入驻审核、结算管理、店铺对账 |
|
||||
| 运营 | 页面装修、分销管理、文章管理、意见反馈、站内信、短信配置 |
|
||||
| 统计 | 会员、订单、流量、商品销量等多维度统计 |
|
||||
| 设置 | 权限、角色、部门、管理员、系统参数、OSS、支付、物流、敏感词等基础配置 |
|
||||
|
||||
#### 6.2 商家端
|
||||
|
||||
| 模块 <img width=80/> | 功能 |
|
||||
|--------------------|-----------------------------------------------------------------|
|
||||
| 首页 | 平台基础信息统计、待办事项 |
|
||||
| 会员 | 会员列表、评价列表、积分历史、会员资金、会员充值 |
|
||||
| 订单 | 商品订单、虚拟订单、订单售后、订单投诉、售后原因维护、收款流水、退款流水 |
|
||||
| 商品 | 商品列表、商品审核、商品分类、商品品牌、商品规格、商品计量单位 |
|
||||
| 促销 | 优惠券、券活动(每日&每月&每周&邀新 赠券)、秒杀活动、砍价活动、拼团活动、积分商品 |
|
||||
| 店铺 | 店铺管理、店铺审核、店铺结算、店铺对账 |
|
||||
| 运营 | 楼层装修、分销商管理、文章管理、意见反馈、站内信、短信、搜索热词管理 |
|
||||
| 统计 | 会员统计、订单统计、流量统计、商品销量统计 |
|
||||
| 设置 | 菜单管理、角色管理、部门管理、管理员管理、系统设置、行政地区管理、OSS管理、联合登陆、支付、物流公司、敏感词、验证码资源 |
|
||||
| 模块 | 主要功能 |
|
||||
| :--- | :----------------------------------------------------------- |
|
||||
| 首页 | 店铺看板、待办事项、公告 |
|
||||
| 商品 | 商品发布、商品管理、运费模板、店铺内分类 |
|
||||
| 订单 | 订单处理、评价管理、投诉处理、退款/退货申请 |
|
||||
| 财务 | 店铺对账、结算管理、发票管理 |
|
||||
| 促销 | 优惠券、满减、秒杀、拼团、分销商品管理 |
|
||||
| 统计 | 订单统计、流量分析、商品销量排行 |
|
||||
| 设置 | 物流配送、自提点、店铺信息、PC/移动端装修、店员与权限管理 |
|
||||
|
||||
---
|
||||
|
||||
### 7. 界面展示
|
||||
|
||||
#### 卖家功能
|
||||
|
||||
|
||||
| 模块 <img width=80/> | 功能 |
|
||||
|----|-------------------------------|
|
||||
| 首页 | 店铺基础信息统计、待办事项、店铺公告 |
|
||||
| 商品 | 商品发布、商品列表、商品模板、店铺分类 |
|
||||
| 订单 | 商品订单、虚拟订单、订单评价、订单投诉、退款申请、退货申请 |
|
||||
| 财务 | 店铺对账、店铺结算、发票管理 |
|
||||
| 促销 | 优惠券、满额优惠、秒杀、拼团 、分销商品、分校订单 |
|
||||
| 统计 |单统计、流量统计、商品销量统计 |
|
||||
|
||||
| 设置 | 配送公司、物流模板、店铺设置、店铺自提设置、PC装修、移动端装修、店员管理、部门管理、角色管理 |
|
||||
| 消息 | 站内信 |
|
||||
|
||||
|
||||
### 商城前端功能展示
|
||||
|
||||
#### 商城移动端
|
||||
|
||||
<img src="https://static.pickmall.cn/images/other/app.gif" alt="移动端功能展示" style="zoom:50%;" />
|
||||
#### 移动端
|
||||
<img src="https://static.pickmall.cn/images/other/app.gif" alt="移动端功能展示" width="300"/>
|
||||
|
||||
#### 平台管理端
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### 技术选型
|
||||
### 8. 开源与授权
|
||||
|
||||
#### 架构图
|
||||
1. **开源协议**: 本项目遵循 `AGPL-3.0` 开源协议。
|
||||
2. **使用范围**: 仅允许用于个人学习、研究和非商业用途。
|
||||
3. **禁止行为**: 禁止将本项目的代码和资源用于任何形式的商业销售。
|
||||
4. **商业授权**: 如需商业使用,必须获得官方授权。授权为一次性永久授权,并提供持续的版本升级服务。详情请联系官网客服。
|
||||
5. **软件著作权**: 本软件受国家计算机软件著作权保护(登记号:2021SR0805085)。
|
||||
|
||||

|
||||
---
|
||||
|
||||
##### 后台技术选型
|
||||
### 9. 社区与支持
|
||||
|
||||
| 说明 | 框架 | 说明 | |
|
||||
| -------------- | --------------- | -------------- | ------------- |
|
||||
| 基础框架 | Spring Boot | MVC框架 | Spring MVC |
|
||||
| 持久框架 | Mybatis-Plus | 程序构建 | Maven |
|
||||
| 关系型数据库 | MySQL | 消息中间件AMQP | RocketMQ |
|
||||
| 缓存 | Redis +MongoDB | 搜索引擎 | Elasticsearch |
|
||||
| 安全框架 | Spring Security | 数据库连接池 | Druid |
|
||||
| 数据库分库分表 | sharding | 定时任务 | xxl-job |
|
||||
| 负载均衡 | Nginx | 静态资源 | 阿里云OSS |
|
||||
| 短信 | 阿里云短信 | 认证 | JWT |
|
||||
| 日志处理 | Log4j | 接口规范 | RESTful |
|
||||
我们欢迎任何形式的交流与贡献。在提问前,请先查阅 [官方文档](https://docs.pickmall.cn/) ,并参考 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md) 以便高效沟通。
|
||||
|
||||
##### 前端-运营后台、店铺后台
|
||||
- **[在线客服](https://work.weixin.qq.com/kfid/kfc4d8dc24a73c15f44)**
|
||||
- **微信交流1群(已满)**
|
||||
- **微信交流2群**:
|
||||

|
||||
|
||||
| 说明 | 框架 | 说明 | 框架 |
|
||||
| ---------- | ---------- | ---------- | ------- |
|
||||
| 构建工具 | webpack | JS版本 | ES6 |
|
||||
| 基础JS框架 | Vue.js | 视频播放器 | Dplayer |
|
||||
| 路由管理 | Vue Router | 状态管理 | Vuex |
|
||||
| 基础UI库 | iView | UI界面基于 | iView |
|
||||
| 网络请求 | axios | | |
|
||||
|
||||
##### 前端-移动端
|
||||
|
||||
| 说明 | 架构 | 说明 | 架构 |
|
||||
| --------- | ------- | -------- | ------- |
|
||||
| 基础UI库 | uViewui | 基础框架 | uni-app |
|
||||
| CSS预处理 | scss | 地图引擎 | amap |
|
||||
|
||||
### 版本升级
|
||||
|
||||
```
|
||||
系统后续会提供多场景解决方案。
|
||||
更多架构:微服务、Saas、中台等,都会支持。 支持差价升级商业授权
|
||||
```
|
||||
|
||||
### 商业授权
|
||||
商业版本与开源版本代码一致,没有区分
|
||||
|
||||
商业使用需要授权,授权方式可选择联系官网客服,或者qq群联系群主。
|
||||
|
||||
商业授权模式为永久授权,支持永久升级。
|
||||
|
||||
商业案例由于涉及部分多层二开关系,如需了解可以咨询销售。
|
||||
|
||||
|
||||
### 开源须知
|
||||
1.仅允许用于个人学习研究使用.
|
||||
|
||||
2.禁止将本开源的代码和资源进行任何形式任何名义的出售.
|
||||
|
||||
3.软件受国家计算机软件著作权保护(登记号:2021SR0805085)。
|
||||
|
||||
4.限制商用,如果需要商业使用请联系我们。QQ3409056806.或者加入qq群联系群主。
|
||||
|
||||
|
||||
|
||||
### 交流群
|
||||
|
||||
##### 交流 qq 1群 961316482(已满)
|
||||
##### 交流 qq 2群 875294241(已满)
|
||||
##### 交流 qq 3群 263785057(已满)
|
||||
##### 交流 qq 4群 674617534(已满)
|
||||
##### 交流 qq 5群 594675235(已满)
|
||||
|
||||
### 附录
|
||||
有人有自己的学习视频、学习记录文档、希望宣传关联开源项目等均可以私聊仓库所有者。
|
||||
|
||||
类似:
|
||||
|
||||
清晨敲代码同学的分析: https://blog.csdn.net/vaevaevae233/category_12103567.html
|
||||
- **社区贡献内容**:
|
||||
- 清晨敲代码的分析: <https://blog.csdn.net/vaevaevae233/category_12103567.html>
|
||||
- DeepWiki: <https://deepwiki.com/lilishop/lilishop>
|
||||
@@ -59,7 +59,7 @@ public class MemberAddressBuyerController {
|
||||
public ResultMessage<MemberAddress> addShippingAddress(@Valid MemberAddress shippingAddress) {
|
||||
//添加会员地址
|
||||
shippingAddress.setMemberId(Objects.requireNonNull(UserContext.getCurrentUser()).getId());
|
||||
if(shippingAddress.getIsDefault()==null){
|
||||
if(Objects.isNull(shippingAddress.getIsDefault())){
|
||||
shippingAddress.setIsDefault(false);
|
||||
}
|
||||
return ResultUtil.data(memberAddressService.saveMemberAddress(shippingAddress));
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.springframework.web.context.request.async.DeferredResult;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 买家端,会员接口
|
||||
@@ -73,6 +73,8 @@ public class MemberBuyerController {
|
||||
new ResponseEntity<>(ResultUtil.error(ResultCode.ERROR), HttpStatus.OK);
|
||||
int timeoutSecond = 20;
|
||||
DeferredResult<ResponseEntity<Object>> deferredResult = new DeferredResult<>(timeoutSecond * 1000L, timeoutResponseEntity);
|
||||
// 用于记录重试次数
|
||||
AtomicInteger retryCount = new AtomicInteger(0);
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
int i = 0;
|
||||
@@ -83,7 +85,16 @@ public class MemberBuyerController {
|
||||
&& (QRCodeLoginSessionStatusEnum.WAIT_SCANNING.getCode() == status
|
||||
|| QRCodeLoginSessionStatusEnum.SCANNING.getCode() == status)) {
|
||||
//睡眠一秒种,继续等待结果
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
//TimeUnit.SECONDS.sleep(1);
|
||||
|
||||
// 应用指数退避策略
|
||||
int baseSleepTime = 1000; // 基础退避时间(毫秒)
|
||||
int maxSleepTime = 10000; // 最大退避时间(毫秒)
|
||||
|
||||
int sleepTime = Math.min(maxSleepTime, baseSleepTime * (1 + retryCount.getAndIncrement()));
|
||||
int randomFactor = (int) (Math.random() * (sleepTime / 2)); // 随机化因子
|
||||
|
||||
TimeUnit.MILLISECONDS.sleep(sleepTime + randomFactor);
|
||||
} else {
|
||||
deferredResult.setResult(new ResponseEntity<>(ResultUtil.data(queryResult), HttpStatus.OK));
|
||||
break;
|
||||
@@ -167,9 +178,13 @@ public class MemberBuyerController {
|
||||
@RequestHeader String uuid) {
|
||||
if (smsUtil.verifyCode(mobile, VerificationEnums.BIND_MOBILE, uuid, code)) {
|
||||
Member member = memberService.findByUsername(username);
|
||||
Member memberByMobile = memberService.findByMobile(mobile);
|
||||
if (member == null) {
|
||||
throw new ServiceException(ResultCode.USER_NOT_EXIST);
|
||||
}
|
||||
if(memberByMobile != null){
|
||||
throw new ServiceException(ResultCode.USER_MOBILE_REPEATABLE_ERROR);
|
||||
}
|
||||
return ResultUtil.data(memberService.changeMobile(member.getId(), mobile));
|
||||
} else {
|
||||
throw new ServiceException(ResultCode.VERIFICATION_SMS_CHECKED_ERROR);
|
||||
@@ -272,12 +287,9 @@ public class MemberBuyerController {
|
||||
}
|
||||
|
||||
@ApiOperation(value = "注销账号")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "password", value = "密码", required = true, paramType = "query")
|
||||
})
|
||||
@PutMapping("/cancellation")
|
||||
public ResultMessage<Member> cancellation(@NotNull(message = "密码不能为空") @RequestParam String password) {
|
||||
memberService.cancellation(password);
|
||||
public ResultMessage<Member> cancellation() {
|
||||
memberService.cancellation();
|
||||
return ResultUtil.success();
|
||||
}
|
||||
|
||||
|
||||
@@ -67,13 +67,19 @@ public class CouponBuyerController {
|
||||
if (UserContext.getCurrentUser() == null) {
|
||||
return ResultUtil.success();
|
||||
}
|
||||
return ResultUtil.data(couponActivityService.trigger(
|
||||
List<MemberCoupon> memberCouponList = couponActivityService.trigger(
|
||||
CouponActivityTrigger.builder()
|
||||
.couponActivityTypeEnum(CouponActivityTypeEnum.AUTO_COUPON)
|
||||
.nickName(UserContext.getCurrentUser().getNickName())
|
||||
.userId(UserContext.getCurrentUser().getId())
|
||||
.build())
|
||||
);
|
||||
.build());
|
||||
memberCouponList.addAll(couponActivityService.trigger(
|
||||
CouponActivityTrigger.builder()
|
||||
.couponActivityTypeEnum(CouponActivityTypeEnum.SPECIFY)
|
||||
.nickName(UserContext.getCurrentUser().getNickName())
|
||||
.userId(UserContext.getCurrentUser().getId())
|
||||
.build()));
|
||||
return ResultUtil.data(memberCouponList);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
|
||||
@@ -91,15 +91,16 @@ public class BuyerAuthenticationFilter extends BasicAuthenticationFilter {
|
||||
|
||||
try {
|
||||
Claims claims
|
||||
= Jwts.parser()
|
||||
= Jwts.parserBuilder()
|
||||
.setSigningKey(SecretKeyUtil.generalKeyByDecoders())
|
||||
.build()
|
||||
.parseClaimsJws(jwt).getBody();
|
||||
//获取存储在claims中的用户信息
|
||||
// 获取存储在claims中的用户信息
|
||||
String json = claims.get(SecurityEnum.USER_CONTEXT.getValue()).toString();
|
||||
AuthUser authUser = new Gson().fromJson(json, AuthUser.class);
|
||||
|
||||
//校验redis中是否有权限
|
||||
if (cache.hasKey(CachePrefix.ACCESS_TOKEN.getPrefix(UserEnums.MEMBER,authUser.getId()) + jwt)) {
|
||||
if (cache.hasKey(CachePrefix.ACCESS_TOKEN.getPrefix(UserEnums.MEMBER, authUser.getId()) + jwt)) {
|
||||
//构造返回信息
|
||||
List<GrantedAuthority> auths = new ArrayList<>();
|
||||
auths.add(new SimpleGrantedAuthority("ROLE_" + authUser.getRole().name()));
|
||||
|
||||
@@ -213,18 +213,6 @@ lili:
|
||||
lbs:
|
||||
key: 4BYBZ-7MT6S-PUAOA-6BNWL-FJUD7-UUFXT
|
||||
sk: zhNKVrJK6UPOhqIjn8AQvG37b9sz6
|
||||
#域名
|
||||
domain:
|
||||
pc: https://pc-b2b2c.pickmall.cn
|
||||
wap: https://m-b2b2c.pickmall.cn
|
||||
store: https://store-b2b2c.pickmall.cn
|
||||
admin: https://admin-b2b2c.pickmall.cn
|
||||
#api地址
|
||||
api:
|
||||
buyer: https://buyer-api.pickmall.cn
|
||||
common: https://common-api.pickmall.cn
|
||||
manager: https://admin-api.pickmall.cn
|
||||
store: https://store-api.pickmall.cn
|
||||
|
||||
# jwt 细节设定
|
||||
jwt-setting:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.lili.controller.common;
|
||||
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.enums.ResultUtil;
|
||||
import cn.lili.common.security.context.UserContext;
|
||||
import cn.lili.common.vo.ResultMessage;
|
||||
@@ -57,8 +58,10 @@ public class FileDirectoryController {
|
||||
@ApiOperation(value = "删除文件目录")
|
||||
@DeleteMapping("/{id}")
|
||||
public ResultMessage<Object> deleteSceneFileList(@PathVariable String id) {
|
||||
//删除文件夹下面的图片
|
||||
fileService.batchDeleteByDirectory(id);
|
||||
//检测文件夹下是否包含图片
|
||||
if(fileService.countByDirectory(id)){
|
||||
return ResultUtil.error(ResultCode.FILE_DIRECTORY_NOT_EMPTY);
|
||||
}
|
||||
//删除目录
|
||||
fileDirectoryService.removeById(id);
|
||||
return ResultUtil.success();
|
||||
|
||||
@@ -55,6 +55,9 @@ public class UploadController {
|
||||
String base64,
|
||||
@RequestHeader String accessToken, @RequestParam String directoryPath) {
|
||||
|
||||
if(StrUtil.isBlank(directoryPath)){
|
||||
directoryPath = "default";
|
||||
}
|
||||
|
||||
AuthUser authUser = UserContext.getAuthUser(cache, accessToken);
|
||||
//如果用户未登录,则无法上传图片
|
||||
|
||||
@@ -190,18 +190,6 @@ lili:
|
||||
interfereNum: 0
|
||||
#允许误差像素
|
||||
faultTolerant: 3
|
||||
#短信模版配置
|
||||
sms:
|
||||
#登录
|
||||
LOGIN: SMS_205755300
|
||||
#注册
|
||||
REGISTER: SMS_205755298
|
||||
#找回密码
|
||||
FIND_USER: SMS_205755301
|
||||
#设置密码
|
||||
UPDATE_PASSWORD: SMS_205755297
|
||||
#支付密码
|
||||
WALLET_PASSWORD: SMS_205755301
|
||||
system:
|
||||
isTestModel: true
|
||||
statistics:
|
||||
|
||||
@@ -20,6 +20,19 @@ management:
|
||||
exposure:
|
||||
include: '*'
|
||||
spring:
|
||||
mail:
|
||||
host: smtp.qq.com
|
||||
port: 465
|
||||
username: lifenlong@foxmail.com
|
||||
password: dirpxpqgfvysbefh
|
||||
protocol: smtps
|
||||
properties:
|
||||
mail:
|
||||
smtp:
|
||||
auth: true
|
||||
starttls:
|
||||
enable: true
|
||||
|
||||
# 要在其中注册的Spring Boot Admin Server的URL。
|
||||
boot:
|
||||
admin:
|
||||
@@ -29,8 +42,8 @@ spring:
|
||||
type: redis
|
||||
# Redis
|
||||
redis:
|
||||
host: 192.168.31.100
|
||||
port: 30379
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
password: lilishop
|
||||
lettuce:
|
||||
pool:
|
||||
@@ -60,7 +73,7 @@ spring:
|
||||
default-datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://192.168.31.100:30306/lilishop?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
|
||||
url: jdbc:mysql://127.0.0.1:3306/lilishop?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
|
||||
username: root
|
||||
password: lilishop
|
||||
maxActive: 50
|
||||
@@ -209,25 +222,12 @@ lili:
|
||||
interfereNum: 1
|
||||
#允许误差像素
|
||||
faultTolerant: 3
|
||||
#短信模版配置
|
||||
sms:
|
||||
#登录
|
||||
LOGIN: SMS_205755300
|
||||
#注册
|
||||
REGISTER: SMS_205755298
|
||||
#找回密码
|
||||
FIND_USER: SMS_205755301
|
||||
#设置密码
|
||||
UPDATE_PASSWORD: SMS_205755297
|
||||
#支付密码
|
||||
WALLET_PASSWORD: SMS_205755301
|
||||
system:
|
||||
isDemoSite: false
|
||||
isTestModel: true
|
||||
# 脱敏级别:
|
||||
# 0:不做脱敏处理
|
||||
# 1:管理端用户手机号等信息脱敏
|
||||
# 2:商家端信息脱敏(为2时,表示管理端,商家端同时脱敏)
|
||||
# 脱敏级别:
|
||||
# 0:不做脱敏处理
|
||||
# 1:管理端用户手机号等信息脱敏
|
||||
# 2:商家端信息脱敏(为2时,表示管理端,商家端同时脱敏)
|
||||
sensitiveLevel: 1
|
||||
|
||||
statistics:
|
||||
@@ -269,7 +269,7 @@ lili:
|
||||
data:
|
||||
elasticsearch:
|
||||
cluster-name: elasticsearch
|
||||
cluster-nodes: 192.168.31.100:30920
|
||||
cluster-nodes: 127.0.0.1:9200
|
||||
index:
|
||||
number-of-replicas: 0
|
||||
number-of-shards: 3
|
||||
@@ -280,7 +280,7 @@ lili:
|
||||
# password: LiLiShopES
|
||||
|
||||
logstash:
|
||||
server: 192.168.31.100:30560
|
||||
server: 127.0.0.1:4560
|
||||
rocketmq:
|
||||
promotion-topic: shop_lili_promotion_topic
|
||||
promotion-group: shop_lili_promotion_group
|
||||
@@ -301,7 +301,7 @@ lili:
|
||||
after-sale-topic: shop_lili_after_sale_topic
|
||||
after-sale-group: shop_lili_after_sale_group
|
||||
rocketmq:
|
||||
name-server: 192.168.31.100:30876
|
||||
name-server: 127.0.0.1:9876
|
||||
isVIPChannel: false
|
||||
producer:
|
||||
group: lili_group
|
||||
@@ -310,7 +310,7 @@ rocketmq:
|
||||
xxl:
|
||||
job:
|
||||
admin:
|
||||
addresses: http://192.168.31.100:30001/xxl-job-admin
|
||||
addresses: http://127.0.0.1:9001/xxl-job-admin
|
||||
executor:
|
||||
appname: xxl-job-executor-lilishop
|
||||
address:
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.springframework.stereotype.Service;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DistributionOrderExecute implements OrderStatusChangeEvent, EveryDayExecute, AfterSaleStatusChangeEvent {
|
||||
public class DistributionOrderExecute implements OrderStatusChangeEvent, AfterSaleStatusChangeEvent {
|
||||
|
||||
/**
|
||||
* 分销订单
|
||||
@@ -35,10 +35,6 @@ public class DistributionOrderExecute implements OrderStatusChangeEvent, EveryDa
|
||||
@Autowired
|
||||
private DistributionOrderService distributionOrderService;
|
||||
|
||||
@Autowired
|
||||
private SettingService settingService;
|
||||
|
||||
|
||||
@Override
|
||||
public void orderChange(OrderMessage orderMessage) {
|
||||
|
||||
@@ -62,21 +58,6 @@ public class DistributionOrderExecute implements OrderStatusChangeEvent, EveryDa
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
log.info("分销订单定时开始执行");
|
||||
//设置结算天数(解冻日期)
|
||||
Setting setting = settingService.get(SettingEnum.DISTRIBUTION_SETTING.name());
|
||||
DistributionSetting distributionSetting = JSONUtil.toBean(setting.getSettingValue(), DistributionSetting.class);
|
||||
//解冻时间
|
||||
DateTime dateTime = new DateTime();
|
||||
//当前时间-结算天数=最终结算时间
|
||||
dateTime = dateTime.offsetNew(DateField.DAY_OF_MONTH, -distributionSetting.getCashDay());
|
||||
//分销人员订单结算
|
||||
distributionOrderService.updateRebate(dateTime, DistributionOrderStatusEnum.WAIT_BILL.name());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSaleStatusChange(AfterSale afterSale) {
|
||||
if (afterSale.getServiceStatus().equals(AfterSaleStatusEnum.COMPLETE.name())) {
|
||||
|
||||
@@ -4,6 +4,8 @@ import cn.lili.common.utils.CurrencyUtil;
|
||||
import cn.lili.event.AfterSaleStatusChangeEvent;
|
||||
import cn.lili.event.TradeEvent;
|
||||
import cn.lili.modules.order.aftersale.entity.dos.AfterSale;
|
||||
import cn.lili.modules.order.aftersale.entity.vo.AfterSaleSearchParams;
|
||||
import cn.lili.modules.order.aftersale.service.AfterSaleService;
|
||||
import cn.lili.modules.order.cart.entity.dto.TradeDTO;
|
||||
import cn.lili.modules.order.order.entity.dos.Order;
|
||||
import cn.lili.modules.order.order.entity.dos.OrderItem;
|
||||
@@ -34,6 +36,8 @@ public class OrderStatusHandlerExecute implements TradeEvent, AfterSaleStatusCha
|
||||
private OrderItemService orderItemService;
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
@Autowired
|
||||
private AfterSaleService afterSaleService;
|
||||
|
||||
@Override
|
||||
public void orderCreate(TradeDTO tradeDTO) {
|
||||
@@ -64,10 +68,16 @@ public class OrderStatusHandlerExecute implements TradeEvent, AfterSaleStatusCha
|
||||
int returnCount = 0;
|
||||
// 总购买数量
|
||||
int deliverCount = 0;
|
||||
for (OrderItem item : orderItems) {
|
||||
returnCount += item.getReturnGoodsNumber();
|
||||
deliverCount += item.getNum();
|
||||
//获取订单货物已完成售后的数量
|
||||
AfterSaleSearchParams saleSearchParams = new AfterSaleSearchParams();
|
||||
saleSearchParams.setOrderSn(afterSale.getOrderSn());
|
||||
saleSearchParams.setServiceStatus(AfterSaleStatusEnum.COMPLETE.name());
|
||||
List<AfterSale> afterSales = afterSaleService.exportAfterSaleOrder(saleSearchParams);
|
||||
for (AfterSale sale : afterSales) {
|
||||
returnCount += sale.getNum();
|
||||
}
|
||||
//订单货物购买总数
|
||||
deliverCount = order.getGoodsNum();
|
||||
if (returnCount == deliverCount) {
|
||||
orderService.systemCancel(afterSale.getOrderSn(),"订单货物全部退款",false);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import cn.lili.modules.order.order.entity.dto.OrderMessage;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.PayStatusEnum;
|
||||
import cn.lili.modules.order.order.service.OrderService;
|
||||
import cn.lili.modules.order.order.service.StoreFlowService;
|
||||
import cn.lili.modules.payment.entity.RefundLog;
|
||||
import cn.lili.modules.payment.kit.Payment;
|
||||
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
||||
@@ -30,6 +31,8 @@ public class PaymentExecute implements OrderStatusChangeEvent {
|
||||
*/
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
@Autowired
|
||||
private StoreFlowService storeFlowService;
|
||||
|
||||
@Override
|
||||
public void orderChange(OrderMessage orderMessage) {
|
||||
@@ -60,6 +63,8 @@ public class PaymentExecute implements OrderStatusChangeEvent {
|
||||
.refundReason("订单取消")
|
||||
.build();
|
||||
payment.refund(refundLog);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class VerificationOrderExecute implements OrderStatusChangeEvent {
|
||||
//修改虚拟订单货物可以进行售后、投诉
|
||||
orderItemService.update(new LambdaUpdateWrapper<OrderItem>().eq(OrderItem::getOrderSn, orderMessage.getOrderSn())
|
||||
.set(OrderItem::getAfterSaleStatus, OrderItemAfterSaleStatusEnum.NOT_APPLIED)
|
||||
.set(OrderItem::getComplainStatus, OrderComplaintStatusEnum.COMPLETE));
|
||||
.set(OrderItem::getComplainStatus, OrderComplaintStatusEnum.NO_APPLY));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package cn.lili.event.impl;
|
||||
|
||||
import cn.lili.event.OrderStatusChangeEvent;
|
||||
import cn.lili.modules.order.order.entity.dto.OrderMessage;
|
||||
import cn.lili.modules.wechat.service.WechatMPService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service ;
|
||||
|
||||
/**
|
||||
* 微信小程序执行器
|
||||
*
|
||||
* @author Chopper
|
||||
* @version v1.0 2021-04-19 14:25
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WechatMPExecute implements OrderStatusChangeEvent {
|
||||
|
||||
@Autowired
|
||||
private WechatMPService wechatMPService;
|
||||
|
||||
|
||||
/**
|
||||
* 订单已发货、待提货、待核验状态 如果是微信小程序的订单则进行 订单发货信息录入
|
||||
*
|
||||
* @param orderMessage 订单消息
|
||||
*/
|
||||
@Override
|
||||
public void orderChange(OrderMessage orderMessage) {
|
||||
|
||||
switch (orderMessage.getNewStatus()) {
|
||||
case TAKE:
|
||||
case STAY_PICKED_UP:
|
||||
case DELIVERED:
|
||||
try {
|
||||
wechatMPService.uploadShippingInfo(orderMessage.getOrderSn());
|
||||
} catch (Exception e) {
|
||||
log.error("发货信息录入失败", e);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -292,6 +292,9 @@ public class GoodsMessageListener implements RocketMQListener<MessageExt> {
|
||||
searchParams.setCategoryPath(promotions.getScopeId());
|
||||
searchParams.setPageNumber(i);
|
||||
searchParams.setPageSize(BATCH_SIZE);
|
||||
if (CharSequenceUtil.isNotEmpty(promotions.getStoreId()) && !"0".equals(promotions.getStoreId())){
|
||||
searchParams.setStoreId(promotions.getStoreId());
|
||||
}
|
||||
IPage<GoodsSku> goodsSkuByPage = this.goodsSkuService.getGoodsSkuByPage(searchParams);
|
||||
if (goodsSkuByPage == null || goodsSkuByPage.getRecords().isEmpty()) {
|
||||
break;
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package cn.lili.timetask.handler.impl.bill;
|
||||
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.lili.modules.store.entity.dto.StoreSettlementDay;
|
||||
import cn.lili.modules.store.service.BillService;
|
||||
import cn.lili.modules.store.service.StoreDetailService;
|
||||
import cn.lili.timetask.handler.EveryDayExecute;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 店铺结算执行
|
||||
*
|
||||
* @author Bulbasaur
|
||||
* @since 2021/2/18 3:45 下午
|
||||
*/
|
||||
@Component
|
||||
public class BillExecute implements EveryDayExecute {
|
||||
|
||||
/**
|
||||
* 结算单
|
||||
*/
|
||||
@Autowired
|
||||
private BillService billService;
|
||||
/**
|
||||
* 店铺详情
|
||||
*/
|
||||
@Autowired
|
||||
private StoreDetailService storeDetailService;
|
||||
|
||||
/**
|
||||
* 1.查询今日待结算的商家
|
||||
* 2.查询商家上次结算日期,生成本次结算单
|
||||
* 3.记录商家结算日
|
||||
*/
|
||||
@Override
|
||||
public void execute() {
|
||||
|
||||
//获取当前天数
|
||||
int day = DateUtil.date().dayOfMonth();
|
||||
|
||||
//获取待结算商家列表
|
||||
List<StoreSettlementDay> storeList = storeDetailService.getSettlementStore(day);
|
||||
|
||||
//获取当前时间
|
||||
DateTime endTime = DateUtil.date();
|
||||
//批量商家结算
|
||||
for (StoreSettlementDay storeSettlementDay : storeList) {
|
||||
|
||||
//生成结算单
|
||||
billService.createBill(storeSettlementDay.getStoreId(), storeSettlementDay.getSettlementDay(), endTime);
|
||||
|
||||
//修改店铺结算时间
|
||||
storeDetailService.updateSettlementDay(storeSettlementDay.getStoreId(), endTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,10 @@ import cn.lili.modules.order.order.entity.enums.OrderItemAfterSaleStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderStatusEnum;
|
||||
import cn.lili.modules.order.order.service.OrderItemService;
|
||||
import cn.lili.modules.order.order.service.OrderService;
|
||||
import cn.lili.modules.order.order.service.StoreFlowService;
|
||||
import cn.lili.modules.store.entity.dto.StoreSettlementDay;
|
||||
import cn.lili.modules.store.service.BillService;
|
||||
import cn.lili.modules.store.service.StoreDetailService;
|
||||
import cn.lili.modules.system.entity.dos.Setting;
|
||||
import cn.lili.modules.system.entity.dto.OrderSetting;
|
||||
import cn.lili.modules.system.entity.enums.SettingEnum;
|
||||
@@ -28,6 +32,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -65,6 +70,20 @@ public class OrderEveryDayTaskExecute implements EveryDayExecute {
|
||||
@Autowired
|
||||
private DistributionOrderService distributionOrderService;
|
||||
|
||||
@Autowired
|
||||
private StoreFlowService storeFlowService;
|
||||
|
||||
/**
|
||||
* 结算单
|
||||
*/
|
||||
@Autowired
|
||||
private BillService billService;
|
||||
/**
|
||||
* 店铺详情
|
||||
*/
|
||||
@Autowired
|
||||
private StoreDetailService storeDetailService;
|
||||
|
||||
/**
|
||||
* 执行每日任务
|
||||
*/
|
||||
@@ -92,7 +111,7 @@ public class OrderEveryDayTaskExecute implements EveryDayExecute {
|
||||
}
|
||||
try {
|
||||
//关闭允许售后申请
|
||||
closeAfterSale(orderSetting);
|
||||
this.closeAfterSale(orderSetting);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
@@ -102,6 +121,22 @@ public class OrderEveryDayTaskExecute implements EveryDayExecute {
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
//修改分账状态
|
||||
try {
|
||||
storeFlowService.updateProfitSharingStatus();
|
||||
} catch (Exception e) {
|
||||
log.error("修改分账状态失败", e);
|
||||
}
|
||||
|
||||
//生成店铺结算单
|
||||
try {
|
||||
createBill();
|
||||
} catch (Exception e) {
|
||||
log.error("生成店铺结算单", e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +146,6 @@ public class OrderEveryDayTaskExecute implements EveryDayExecute {
|
||||
*/
|
||||
private void completedOrder(OrderSetting orderSetting) {
|
||||
|
||||
|
||||
//订单自动收货时间 = 当前时间 - 自动收货时间天数
|
||||
DateTime receiveTime = DateUtil.offsetDay(DateUtil.date(), -orderSetting.getAutoReceive());
|
||||
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
|
||||
@@ -144,7 +178,9 @@ public class OrderEveryDayTaskExecute implements EveryDayExecute {
|
||||
DateTime receiveTime = DateUtil.offsetDay(DateUtil.date(), -orderSetting.getAutoEvaluation());
|
||||
|
||||
//订单完成时间 <= 订单自动好评时间
|
||||
OrderItemOperationDTO orderItemOperationDTO = OrderItemOperationDTO.builder().receiveTime(receiveTime).commentStatus(CommentStatusEnum.UNFINISHED.name()).build();
|
||||
OrderItemOperationDTO orderItemOperationDTO =
|
||||
OrderItemOperationDTO.builder().receiveTime(receiveTime).commentStatus(CommentStatusEnum.UNFINISHED.name())
|
||||
.build();
|
||||
List<OrderItem> orderItems = orderItemService.waitOperationOrderItem(orderItemOperationDTO);
|
||||
|
||||
//判断是否有符合条件的订单,进行自动评价处理
|
||||
@@ -162,33 +198,30 @@ public class OrderEveryDayTaskExecute implements EveryDayExecute {
|
||||
|
||||
try {
|
||||
memberEvaluationService.addMemberEvaluation(memberEvaluationDTO, false);
|
||||
|
||||
} catch (Exception e) {
|
||||
// 修改订单货物评价状态为已评价避免无限调用评价异常
|
||||
orderItemService.updateCommentStatus(orderItem.getSn(), CommentStatusEnum.FINISHED);
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 关闭允许售后申请
|
||||
*
|
||||
* @param orderSetting 订单设置
|
||||
*/
|
||||
private void closeAfterSale(OrderSetting orderSetting) {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void closeAfterSale(OrderSetting orderSetting) {
|
||||
//订单关闭售后申请时间 = 当前时间 - 自动关闭售后申请天数
|
||||
DateTime receiveTime = DateUtil.offsetDay(DateUtil.date(), -orderSetting.getCloseAfterSale());
|
||||
//关闭售后订单=未售后订单+小于订单关闭售后申请时间
|
||||
OrderItemOperationDTO build = OrderItemOperationDTO.builder().receiveTime(receiveTime).afterSaleStatus(OrderItemAfterSaleStatusEnum.NOT_APPLIED.name()).build();
|
||||
List<OrderItem> orderItems = orderItemService.waitOperationOrderItem(build);
|
||||
|
||||
//判断是否有符合条件的订单,关闭允许售后申请处理
|
||||
if (!orderItems.isEmpty()) {
|
||||
orderItemService.expiredAfterSaleStatus(receiveTime);
|
||||
//修改对应分销订单状态
|
||||
distributionOrderService.updateDistributionOrderStatus(orderItems);
|
||||
}
|
||||
// OrderItemOperationDTO build = OrderItemOperationDTO.builder().receiveTime(receiveTime)
|
||||
// .afterSaleStatus(OrderItemAfterSaleStatusEnum.NOT_APPLIED.name()).build();
|
||||
// List<OrderItem> orderItems = orderItemService.waitOperationOrderItem(build);
|
||||
//关闭售后订单=未售后订单+小于订单关闭售后申请时间
|
||||
orderItemService.expiredAfterSaleStatus(receiveTime);
|
||||
|
||||
}
|
||||
|
||||
@@ -207,7 +240,8 @@ public class OrderEveryDayTaskExecute implements EveryDayExecute {
|
||||
DateTime receiveTime = DateUtil.offsetDay(DateUtil.date(), -orderSetting.getCloseComplaint());
|
||||
|
||||
//关闭售后订单=未售后订单+小于订单关闭售后申请时间
|
||||
OrderItemOperationDTO build = OrderItemOperationDTO.builder().receiveTime(receiveTime).complainStatus(OrderComplaintStatusEnum.NO_APPLY.name()).build();
|
||||
OrderItemOperationDTO build = OrderItemOperationDTO.builder().receiveTime(receiveTime)
|
||||
.complainStatus(OrderComplaintStatusEnum.NO_APPLY.name()).build();
|
||||
List<OrderItem> orderItems = orderItemService.waitOperationOrderItem(build);
|
||||
|
||||
//判断是否有符合条件的订单,关闭允许售后申请处理
|
||||
@@ -217,12 +251,37 @@ public class OrderEveryDayTaskExecute implements EveryDayExecute {
|
||||
List<String> orderItemIdList = orderItems.stream().map(OrderItem::getId).collect(Collectors.toList());
|
||||
|
||||
//修改订单投诉状态
|
||||
LambdaUpdateWrapper<OrderItem> lambdaUpdateWrapper = new LambdaUpdateWrapper<OrderItem>()
|
||||
.set(OrderItem::getComplainStatus, OrderItemAfterSaleStatusEnum.EXPIRED.name())
|
||||
.in(OrderItem::getId, orderItemIdList);
|
||||
LambdaUpdateWrapper<OrderItem> lambdaUpdateWrapper =
|
||||
new LambdaUpdateWrapper<OrderItem>().set(OrderItem::getComplainStatus,
|
||||
OrderItemAfterSaleStatusEnum.EXPIRED.name()).in(OrderItem::getId, orderItemIdList);
|
||||
orderItemService.update(lambdaUpdateWrapper);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 1.查询今日待结算的商家
|
||||
* 2.查询商家上次结算日期,生成本次结算单
|
||||
* 3.记录商家结算日
|
||||
*/
|
||||
private void createBill() {
|
||||
//获取当前天数
|
||||
int day = DateUtil.date().dayOfMonth();
|
||||
|
||||
//获取待结算商家列表
|
||||
List<StoreSettlementDay> storeList = storeDetailService.getSettlementStore(day);
|
||||
|
||||
//获取当前时间
|
||||
DateTime endTime = DateUtil.date();
|
||||
//批量商家结算
|
||||
for (StoreSettlementDay storeSettlementDay : storeList) {
|
||||
|
||||
//生成结算单
|
||||
billService.createBill(storeSettlementDay.getStoreId(), storeSettlementDay.getSettlementDay(), endTime);
|
||||
|
||||
//修改店铺结算时间
|
||||
storeDetailService.updateSettlementDay(storeSettlementDay.getStoreId(), endTime);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
package cn.lili.buyer.test.cart;
|
||||
|
||||
import cn.lili.common.utils.DateUtil;
|
||||
import cn.lili.timetask.handler.impl.statistics.OnlineMemberStatistics;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 订单库存扣减
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest
|
||||
class OnlineTest {
|
||||
|
||||
@Autowired
|
||||
private OnlineMemberStatistics onlineMemberStatistics;
|
||||
|
||||
//订单支付,库存扣减单元测试
|
||||
@Test
|
||||
void everyHour() {
|
||||
onlineMemberStatistics.execute();
|
||||
}
|
||||
|
||||
//订单支付,库存扣减单元测试
|
||||
@Test
|
||||
void customSetting() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - 48 );
|
||||
//循环填充数据
|
||||
for (int i = 0; i < 48; i++) {
|
||||
calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + 1);
|
||||
System.out.println(DateUtil.toString(calendar.getTime(),""));
|
||||
Random random = new Random();
|
||||
onlineMemberStatistics.execute(calendar.getTime(), random.nextInt(1000000));
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - 48 - 1);
|
||||
//循环填充数据
|
||||
for (int i = 0; i < 48; i++) {
|
||||
calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + 1);
|
||||
System.out.println(calendar.getTime().getTime());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -15,15 +15,6 @@
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.qiniu</groupId>
|
||||
<artifactId>qiniu-java-sdk</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.qiniu</groupId>
|
||||
<artifactId>qiniu-java-sdk</artifactId>
|
||||
<version>7.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-properties-migrator</artifactId>
|
||||
@@ -468,6 +459,11 @@
|
||||
<scope>runtime</scope>
|
||||
<classifier>osx-aarch_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.wechatpay-apiv3</groupId>
|
||||
<artifactId>wechatpay-java</artifactId>
|
||||
<version>0.2.15</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package cn.lili.common.enums;
|
||||
|
||||
|
||||
import cn.lili.common.utils.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* 促销分类枚举
|
||||
*
|
||||
@@ -52,4 +57,28 @@ public enum PromotionTypeEnum {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断促销类型是否有效
|
||||
* @param typeEnumValue
|
||||
* @return
|
||||
*/
|
||||
public static boolean isValid(String typeEnumValue) {
|
||||
if (StringUtils.isBlank(typeEnumValue)) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.stream(PromotionTypeEnum.values()).anyMatch(c -> c.name().equals(typeEnumValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断订单类型是否可售后
|
||||
* POINTS\KANJIA 两种促销类型的订单不可进行售后
|
||||
* @return true 可售后 false 不可售后
|
||||
*/
|
||||
public static boolean isCanAfterSale(String promotionType) {
|
||||
if (!isValid(promotionType)) {
|
||||
return true;
|
||||
}
|
||||
EnumSet<PromotionTypeEnum> noAfterSale = EnumSet.of(PromotionTypeEnum.KANJIA, PromotionTypeEnum.POINTS_GOODS);
|
||||
return !noAfterSale.contains(PromotionTypeEnum.valueOf(promotionType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ public enum ResultCode {
|
||||
PLATFORM_NOT_SUPPORTED_IM(1006, "平台未开启IM"),
|
||||
STORE_NOT_SUPPORTED_IM(1007, "店铺未开启IM"),
|
||||
UNINITIALIZED_PASSWORD(1008, "非初始化密码,无法进行初始化设置"),
|
||||
FILE_DIRECTORY_NOT_EMPTY(1012, "文件夹下有文件,请删除所有文件后删除文件夹!"),
|
||||
/**
|
||||
* 分类
|
||||
*/
|
||||
@@ -89,6 +90,7 @@ public enum ResultCode {
|
||||
VIRTUAL_GOODS_NOT_NEED_TEMP(11015, "虚拟商品无需选择配送模板"),
|
||||
GOODS_NOT_EXIST_STORE(11017, "当前用户无权操作此商品"),
|
||||
GOODS_TYPE_ERROR(11016, "需选择商品类型"),
|
||||
GOODS_STOCK_IMPORT_ERROR(11018, "导入商品库存失败,请检查表格数据"),
|
||||
|
||||
/**
|
||||
* 参数
|
||||
@@ -150,6 +152,7 @@ public enum ResultCode {
|
||||
CLERK_DISABLED_ERROR(20031, "店员已禁用"),
|
||||
CLERK_CURRENT_SUPPER(20032, "无法删除当前登录店员"),
|
||||
CANT_EDIT_CLERK_SHOPKEEPER(20033, "无法在店员管理编辑店员信息"),
|
||||
USER_MOBILE_REPEATABLE_ERROR(20034, "该手机号已存在"),
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
@@ -173,6 +176,7 @@ public enum ResultCode {
|
||||
DISTRIBUTION_RETREAT_ERROR(22004, "分销员清退失败"),
|
||||
DISTRIBUTION_CASH_NOT_EXIST(22005, "分销员提现记录不存在"),
|
||||
DISTRIBUTION_GOODS_DOUBLE(22006, "不能重复添加分销商品"),
|
||||
DISTRIBUTION_EDIT_ERROR(22007, "修改分销员失败"),
|
||||
|
||||
/**
|
||||
* 购物车
|
||||
|
||||
@@ -131,4 +131,13 @@ public class ResultUtil<T> {
|
||||
return this.resultMessage;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回失败
|
||||
*
|
||||
* @return 消息
|
||||
*/
|
||||
public static <T> ResultMessage<T> error() {
|
||||
return new ResultUtil<T>().setErrorMsg(ResultCode.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.lili.common.exception;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.enums.ResultUtil;
|
||||
import cn.lili.common.vo.ResultMessage;
|
||||
@@ -42,26 +43,21 @@ public class GlobalControllerExceptionHandler {
|
||||
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||
public ResultMessage<Object> handleServiceException(HttpServletRequest request, final Exception e, HttpServletResponse response) {
|
||||
|
||||
|
||||
//如果是自定义异常,则获取异常,返回自定义错误消息
|
||||
if (e instanceof ServiceException) {
|
||||
|
||||
ServiceException serviceException = ((ServiceException) e);
|
||||
ResultCode resultCode = serviceException.getResultCode();
|
||||
|
||||
Integer code = null;
|
||||
String message = null;
|
||||
Integer code = resultCode.code();
|
||||
String message = resultCode.message();
|
||||
|
||||
if (resultCode != null) {
|
||||
code = resultCode.code();
|
||||
message = resultCode.message();
|
||||
}
|
||||
//如果有扩展消息,则输出异常中,跟随补充异常
|
||||
if (!serviceException.getMsg().equals(ServiceException.DEFAULT_MESSAGE)) {
|
||||
message += ":" + serviceException.getMsg();
|
||||
if (message != null) {
|
||||
message = appendErrorMessage(message, serviceException.getMsg());
|
||||
}
|
||||
|
||||
// 对一些特殊异常处理,不再打印error级别的日志
|
||||
assert serviceException.getResultCode() != null;
|
||||
if (serviceException.getResultCode().equals(ResultCode.DEMO_SITE_EXCEPTION)) {
|
||||
log.debug("[DEMO_SITE_EXCEPTION]:{}", serviceException.getResultCode().message(), e);
|
||||
return ResultUtil.error(code, message);
|
||||
@@ -103,7 +99,30 @@ public class GlobalControllerExceptionHandler {
|
||||
|
||||
log.error("全局异常[RuntimeException]:", e);
|
||||
|
||||
return ResultUtil.error(ResultCode.ERROR);
|
||||
// 检查异常链是否包含 ServiceException
|
||||
ServiceException serviceException = findServiceException(e);
|
||||
|
||||
if (serviceException != null) {
|
||||
ResultCode resultCode = serviceException.getResultCode();
|
||||
Integer code = resultCode.code();
|
||||
String message = resultCode.message();
|
||||
if (message != null) {
|
||||
message = appendErrorMessage(message, serviceException.getMsg());
|
||||
}
|
||||
return ResultUtil.error(code, message);
|
||||
}
|
||||
return ResultUtil.error();
|
||||
}
|
||||
|
||||
// 遍历异常链,查找 ServiceException
|
||||
private ServiceException findServiceException(Throwable ex) {
|
||||
while (ex != null) {
|
||||
if (ex instanceof ServiceException) {
|
||||
return (ServiceException) ex;
|
||||
}
|
||||
ex = ex.getCause();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// /**
|
||||
@@ -145,7 +164,8 @@ public class GlobalControllerExceptionHandler {
|
||||
if (!fieldErrors.isEmpty()) {
|
||||
return ResultUtil.error(ResultCode.PARAMS_ERROR.code(),
|
||||
fieldErrors.stream()
|
||||
.map(FieldError::getDefaultMessage) // 获取每个对象的名称字段
|
||||
// 获取每个对象的名称字段
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.collect(Collectors.joining(", ")));
|
||||
}
|
||||
return ResultUtil.error(ResultCode.PARAMS_ERROR);
|
||||
@@ -168,4 +188,42 @@ public class GlobalControllerExceptionHandler {
|
||||
ConstraintViolationException exception = (ConstraintViolationException) e;
|
||||
return ResultUtil.error(ResultCode.PARAMS_ERROR.code(), exception.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接错误消息
|
||||
*
|
||||
* @param message 原始消息
|
||||
* @param appendMessage 需要拼接的消息
|
||||
* @return 拼接后的消息
|
||||
*/
|
||||
private String appendErrorMessage(String message, String appendMessage) {
|
||||
|
||||
//这里的代码看起来有点乱,简单解释一下
|
||||
//场景1:服务A,服务B=》
|
||||
// 服务A调用服务B=》
|
||||
// 服务B抛出异常{扩展消息},拼接后成为{默认消息}:{扩展消息}
|
||||
// 异常被服务A捕获=》
|
||||
// 最终消息拼接过程中,当前方法体参数message是{默认消息},参数appendMessage是服务A给的{默认消息}+{扩展消息},最终会形成{默认消息}+{默认消息}+{扩展消息}
|
||||
//场景2:只有服务A=》
|
||||
// 服务A抛出异常{扩展消息}=》
|
||||
// 当前方法体拼接{默认消息}:{扩展消息} 并输出返回。
|
||||
//
|
||||
//总的来说,由于消息拼接是一个流式传递,由服务间传递,所以这里的消息可能存在A包含B,也可能出现B包含A,
|
||||
// 所以这里需要双重判定,A包含B=》返回A,B包含A=》返回B,否则返回拼接后的消息
|
||||
|
||||
if (message.contains(appendMessage)) {
|
||||
return message;
|
||||
}
|
||||
if (appendMessage.contains(message)) {
|
||||
return appendMessage;
|
||||
}
|
||||
//忽略默认错误信息,如果有其他错误消息体就不再返回默认的错误消息
|
||||
if (message.equals(ResultCode.ERROR.message())) {
|
||||
return appendMessage;
|
||||
}
|
||||
if (appendMessage.equals(ResultCode.ERROR.message())) {
|
||||
return message;
|
||||
}
|
||||
return CharSequenceUtil.format("{}-{}", message, appendMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,11 @@ public class ServiceException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 3447728300174142127L;
|
||||
|
||||
public static final String DEFAULT_MESSAGE = "网络错误,请稍后重试!";
|
||||
|
||||
/**
|
||||
* 异常消息
|
||||
*/
|
||||
private String msg = DEFAULT_MESSAGE;
|
||||
private String msg = ResultCode.ERROR.message();
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
|
||||
@@ -14,23 +14,23 @@ import org.springframework.context.annotation.Configuration;
|
||||
public class ApiProperties {
|
||||
|
||||
|
||||
/**
|
||||
* 买家api
|
||||
*/
|
||||
private String buyer;
|
||||
// /**
|
||||
// * 买家api
|
||||
// */
|
||||
// private String buyer;
|
||||
|
||||
/**
|
||||
* 管理端域名
|
||||
*/
|
||||
private String store;
|
||||
|
||||
/**
|
||||
* 管理端域名
|
||||
*/
|
||||
private String manager;
|
||||
|
||||
/**
|
||||
* 管理端域名
|
||||
*/
|
||||
private String common;
|
||||
// /**
|
||||
// * 管理端域名
|
||||
// */
|
||||
// private String store;
|
||||
//
|
||||
// /**
|
||||
// * 管理端域名
|
||||
// */
|
||||
// private String manager;
|
||||
//
|
||||
// /**
|
||||
// * 管理端域名
|
||||
// */
|
||||
// private String common;
|
||||
}
|
||||
|
||||
@@ -92,8 +92,9 @@ public class UserContext {
|
||||
try {
|
||||
//获取token的信息
|
||||
Claims claims
|
||||
= Jwts.parser()
|
||||
= Jwts.parserBuilder()
|
||||
.setSigningKey(SecretKeyUtil.generalKeyByDecoders())
|
||||
.build()
|
||||
.parseClaimsJws(accessToken).getBody();
|
||||
//获取存储在claims中的用户信息
|
||||
String json = claims.get(SecurityEnum.USER_CONTEXT.getValue()).toString();
|
||||
|
||||
@@ -144,7 +144,6 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
|
||||
BufferedReader bufferedReader = null;
|
||||
|
||||
InputStreamReader reader = null;
|
||||
|
||||
//获取输入流
|
||||
@@ -163,47 +162,55 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
//继续读取下一行流,直到line为空
|
||||
line = bufferedReader.readLine();
|
||||
}
|
||||
if (CharSequenceUtil.isNotEmpty(body) && Boolean.TRUE.equals(JSONUtil.isJsonObj(body.toString()))) {
|
||||
//将body转换为map
|
||||
Map<String, Object> map = JSONUtil.parseObj(body.toString());
|
||||
//创建空的map用于存储结果
|
||||
Map<String, Object> resultMap = new HashMap<>(map.size());
|
||||
//遍历数组
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
//如果map.get(key)获取到的是字符串就需要进行处理,如果不是直接存储resultMap
|
||||
if (map.get(entry.getKey()) instanceof String) {
|
||||
resultMap.put(entry.getKey(), filterXss(entry.getKey(), entry.getValue().toString()));
|
||||
} else {
|
||||
resultMap.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
// 兼容替换:不再使用过时的 JSONUtil.isJsonObj(String),改为尝试解析并捕获异常
|
||||
if (CharSequenceUtil.isNotEmpty(body)) {
|
||||
Map<String, Object> map = null;
|
||||
try {
|
||||
map = JSONUtil.parseObj(body.toString());
|
||||
} catch (Exception ignore) {
|
||||
map = null;
|
||||
}
|
||||
|
||||
//将resultMap转换为json字符串
|
||||
String resultStr = JSONUtil.toJsonStr(resultMap);
|
||||
//将json字符串转换为字节
|
||||
final ByteArrayInputStream resultBIS = new ByteArrayInputStream(resultStr.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
//实现接口
|
||||
return new ServletInputStream() {
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
if (map != null) {
|
||||
//创建空的map用于存储结果
|
||||
Map<String, Object> resultMap = new HashMap<>(map.size());
|
||||
//遍历数组
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
//如果map.get(key)获取到的是字符串就需要进行处理,如果不是直接存储resultMap
|
||||
if (map.get(entry.getKey()) instanceof String) {
|
||||
resultMap.put(entry.getKey(), filterXss(entry.getKey(), entry.getValue().toString()));
|
||||
} else {
|
||||
resultMap.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return false;
|
||||
}
|
||||
//将resultMap转换为json字符串
|
||||
String resultStr = JSONUtil.toJsonStr(resultMap);
|
||||
//将json字符串转换为字节
|
||||
final ByteArrayInputStream resultBIS = new ByteArrayInputStream(resultStr.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
}
|
||||
//实现接口
|
||||
return new ServletInputStream() {
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
return resultBIS.read();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
return resultBIS.read();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//将json字符串转换为字节
|
||||
|
||||
@@ -65,8 +65,9 @@ public class TokenUtil {
|
||||
|
||||
Claims claims;
|
||||
try {
|
||||
claims = Jwts.parser()
|
||||
claims = Jwts.parserBuilder()
|
||||
.setSigningKey(SecretKeyUtil.generalKeyByDecoders())
|
||||
.build()
|
||||
.parseClaimsJws(oldRefreshToken).getBody();
|
||||
} catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException |
|
||||
IllegalArgumentException e) {
|
||||
|
||||
@@ -125,13 +125,21 @@ public final class CurrencyUtil {
|
||||
return (int) price;
|
||||
}
|
||||
|
||||
public static Long getFenLong(Double money) {
|
||||
BigDecimal bigDecimalValue = BigDecimal.valueOf(money);
|
||||
// 乘以 100 并四舍五入到最接近的整数
|
||||
BigDecimal fenValue = bigDecimalValue.multiply(BigDecimal.valueOf(100)).setScale(0, RoundingMode.HALF_UP);
|
||||
|
||||
return fenValue.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 金额转分
|
||||
*
|
||||
* @param money 金额
|
||||
* @return double类型分
|
||||
*/
|
||||
public static double reversalFen(Double money) {
|
||||
public static double reversalFen(Integer money) {
|
||||
return div(money, 100);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
@Constraint(validatedBy = {PhoneValidator.class})
|
||||
public @interface Phone {
|
||||
|
||||
String regexp() default "1[3|4|5|7|8]\\d{9}";
|
||||
String regexp() default "1[3|4|5|7|8|9]\\d{9}";
|
||||
|
||||
String message() default "手机号码格式不正确";
|
||||
|
||||
|
||||
@@ -90,7 +90,8 @@ public abstract class BaseElasticsearchService {
|
||||
request.settings(Settings.builder()
|
||||
.put("index.number_of_shards", elasticsearchProperties.getIndex().getNumberOfShards())
|
||||
.put("index.number_of_replicas", elasticsearchProperties.getIndex().getNumberOfReplicas())
|
||||
.put("index.max_result_window", 100000) //最大查询结果数
|
||||
//最大查询结果数
|
||||
.put("index.max_result_window", 100000)
|
||||
.put("index.mapping.total_fields.limit", 2000));
|
||||
|
||||
//创建索引
|
||||
|
||||
@@ -66,14 +66,16 @@ public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
|
||||
.setRequestConfigCallback(requestConfigBuilder ->
|
||||
requestConfigBuilder
|
||||
.setConnectTimeout(1000)
|
||||
.setSocketTimeout(12 * 1000));
|
||||
.setSocketTimeout(12 * 1000)
|
||||
.setConnectionRequestTimeout(1000));
|
||||
}
|
||||
|
||||
private HttpAsyncClientBuilder configureHttpClientBuilder(HttpAsyncClientBuilder httpClientBuilder,
|
||||
CredentialsProvider credentialsProvider) {
|
||||
httpClientBuilder
|
||||
.setKeepAliveStrategy(getConnectionKeepAliveStrategy())
|
||||
.setMaxConnPerRoute(10)
|
||||
.setMaxConnPerRoute(50)
|
||||
.setMaxConnTotal(200)
|
||||
.setDefaultIOReactorConfig(
|
||||
IOReactorConfig
|
||||
.custom()
|
||||
|
||||
@@ -55,7 +55,7 @@ public class BaseAuthWeChatPCRequest extends BaseAuthRequest {
|
||||
|
||||
return ConnectAuthUser.builder()
|
||||
.rawUserInfo(object)
|
||||
.username(object.getString("nickname"))
|
||||
.username(object.getString("unionid"))
|
||||
.nickname(object.getString("nickname"))
|
||||
.avatar(object.getString("headimgurl"))
|
||||
.location(location)
|
||||
|
||||
@@ -57,7 +57,7 @@ public class BaseAuthWeChatRequest extends BaseAuthRequest {
|
||||
|
||||
return ConnectAuthUser.builder()
|
||||
.rawUserInfo(object)
|
||||
.username(object.getString("nickname"))
|
||||
.username(object.getString("unionid"))
|
||||
.nickname(object.getString("nickname"))
|
||||
.avatar(object.getString("headimgurl"))
|
||||
.location(location)
|
||||
|
||||
@@ -23,6 +23,7 @@ import cn.lili.modules.connect.request.BaseAuthWeChatPCRequest;
|
||||
import cn.lili.modules.connect.request.BaseAuthWeChatRequest;
|
||||
import cn.lili.modules.connect.service.ConnectService;
|
||||
import cn.lili.modules.system.entity.dos.Setting;
|
||||
import cn.lili.modules.system.entity.dto.connect.ConnectSetting;
|
||||
import cn.lili.modules.system.entity.dto.connect.QQConnectSetting;
|
||||
import cn.lili.modules.system.entity.dto.connect.WechatConnectSetting;
|
||||
import cn.lili.modules.system.entity.dto.connect.dto.QQConnectSettingItem;
|
||||
@@ -70,8 +71,8 @@ public class ConnectUtil {
|
||||
* @param connectAuthEnum 用户枚举
|
||||
* @return 回调地址
|
||||
*/
|
||||
String getRedirectUri(ConnectAuthEnum connectAuthEnum) {
|
||||
return apiProperties.getBuyer() + prefix + connectAuthEnum.getName();
|
||||
String getRedirectUri(ConnectAuthEnum connectAuthEnum,String callbackUrl) {
|
||||
return callbackUrl + prefix + connectAuthEnum.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,10 +107,13 @@ public class ConnectUtil {
|
||||
//缓存写入登录结果,300秒有效
|
||||
cache.put(CachePrefix.CONNECT_RESULT.getPrefix() + callback.getCode(), resultMessage, 300L);
|
||||
|
||||
//登录设置
|
||||
ConnectSetting connectSetting = JSONUtil.toBean(settingService.get(SettingEnum.CONNECT_SETTING.name()).getSettingValue(), ConnectSetting.class);
|
||||
|
||||
//跳转地址
|
||||
String url = this.check(httpServletRequest.getHeader("user-agent")) ?
|
||||
domainProperties.getWap() + "/pages/passport/login?state=" + callback.getCode() :
|
||||
domainProperties.getPc() + "/login?state=" + callback.getCode();
|
||||
connectSetting.getWap() + "/pages/passport/login?state=" + callback.getCode() :
|
||||
connectSetting.getPc() + "/login?state=" + callback.getCode();
|
||||
|
||||
try {
|
||||
httpServletResponse.sendRedirect(url);
|
||||
@@ -151,13 +155,15 @@ public class ConnectUtil {
|
||||
//寻找配置
|
||||
Setting setting = settingService.get(SettingEnum.WECHAT_CONNECT.name());
|
||||
WechatConnectSetting wechatConnectSetting = JSONUtil.toBean(setting.getSettingValue(), WechatConnectSetting.class);
|
||||
//登录设置
|
||||
ConnectSetting connectSetting = JSONUtil.toBean(settingService.get(SettingEnum.CONNECT_SETTING.name()).getSettingValue(), ConnectSetting.class);
|
||||
|
||||
for (WechatConnectSettingItem wechatConnectSettingItem : wechatConnectSetting.getWechatConnectSettingItems()) {
|
||||
if (wechatConnectSettingItem.getClientType().equals(ClientTypeEnum.H5.name())) {
|
||||
authRequest = new BaseAuthWeChatRequest(AuthConfig.builder()
|
||||
.clientId(wechatConnectSettingItem.getAppId())
|
||||
.clientSecret(wechatConnectSettingItem.getAppSecret())
|
||||
.redirectUri(getRedirectUri(authInterface))
|
||||
.redirectUri(getRedirectUri(authInterface, connectSetting.getCallbackUrl()))
|
||||
.build(), cache);
|
||||
}
|
||||
}
|
||||
@@ -167,13 +173,14 @@ public class ConnectUtil {
|
||||
//寻找配置
|
||||
Setting setting = settingService.get(SettingEnum.WECHAT_CONNECT.name());
|
||||
WechatConnectSetting wechatConnectSetting = JSONUtil.toBean(setting.getSettingValue(), WechatConnectSetting.class);
|
||||
|
||||
//登录设置
|
||||
ConnectSetting connectSetting = JSONUtil.toBean(settingService.get(SettingEnum.CONNECT_SETTING.name()).getSettingValue(), ConnectSetting.class);
|
||||
for (WechatConnectSettingItem wechatConnectSettingItem : wechatConnectSetting.getWechatConnectSettingItems()) {
|
||||
if (wechatConnectSettingItem.getClientType().equals(ClientTypeEnum.PC.name())) {
|
||||
authRequest = new BaseAuthWeChatPCRequest(AuthConfig.builder()
|
||||
.clientId(wechatConnectSettingItem.getAppId())
|
||||
.clientSecret(wechatConnectSettingItem.getAppSecret())
|
||||
.redirectUri(getRedirectUri(authInterface))
|
||||
.redirectUri(getRedirectUri(authInterface, connectSetting.getCallbackUrl()))
|
||||
.build(), cache);
|
||||
}
|
||||
}
|
||||
@@ -184,13 +191,14 @@ public class ConnectUtil {
|
||||
//寻找配置
|
||||
Setting setting = settingService.get(SettingEnum.QQ_CONNECT.name());
|
||||
QQConnectSetting qqConnectSetting = JSONUtil.toBean(setting.getSettingValue(), QQConnectSetting.class);
|
||||
|
||||
//登录设置
|
||||
ConnectSetting connectSetting = JSONUtil.toBean(settingService.get(SettingEnum.CONNECT_SETTING.name()).getSettingValue(), ConnectSetting.class);
|
||||
for (QQConnectSettingItem qqConnectSettingItem : qqConnectSetting.getQqConnectSettingItemList()) {
|
||||
if (qqConnectSettingItem.getClientType().equals(ClientTypeEnum.PC.name())) {
|
||||
authRequest = new BaseAuthQQRequest(AuthConfig.builder()
|
||||
.clientId(qqConnectSettingItem.getAppId())
|
||||
.clientSecret(qqConnectSettingItem.getAppKey())
|
||||
.redirectUri(getRedirectUri(authInterface))
|
||||
.redirectUri(getRedirectUri(authInterface, connectSetting.getCallbackUrl()))
|
||||
//这里qq获取unionid 需要配置为true,详情可以查阅属性说明,内部有帮助文档
|
||||
.unionId(true)
|
||||
.build(), cache);
|
||||
|
||||
@@ -36,6 +36,7 @@ public class Distribution extends BaseEntity {
|
||||
this.rebateTotal=0D;
|
||||
this.canRebate=0D;
|
||||
this.commissionFrozen=0D;
|
||||
this.distributionOrderPrice=0D;
|
||||
this.distributionStatus = DistributionStatusEnum.APPLY.name();
|
||||
BeanUtil.copyProperties(distributionApplyDTO, this);
|
||||
}
|
||||
@@ -85,4 +86,7 @@ public class Distribution extends BaseEntity {
|
||||
@ApiModelProperty(value = "结算银行开户支行名称")
|
||||
private String settlementBankBranchName;
|
||||
|
||||
@ApiModelProperty(value = "分销订单金额")
|
||||
private Double distributionOrderPrice;
|
||||
|
||||
}
|
||||
@@ -9,9 +9,11 @@ import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
@@ -51,11 +53,30 @@ public class DistributionCash extends BaseEntity {
|
||||
@ApiModelProperty(value = "状态")
|
||||
private String distributionCashStatus;
|
||||
|
||||
public DistributionCash(String sn, String distributionId, Double price, String memberName) {
|
||||
|
||||
|
||||
@ApiModelProperty(value = "会员姓名")
|
||||
private String name;
|
||||
@ApiModelProperty(value = "身份证号")
|
||||
private String idNumber;
|
||||
@ApiModelProperty(value = "结算银行开户行名称")
|
||||
private String settlementBankAccountName;
|
||||
@ApiModelProperty(value = "结算银行开户账号")
|
||||
private String settlementBankAccountNum;
|
||||
@ApiModelProperty(value = "结算银行开户支行名称")
|
||||
private String settlementBankBranchName;
|
||||
|
||||
public DistributionCash(String sn,Double price, Distribution distribution) {
|
||||
this.sn = sn;
|
||||
this.distributionId = distributionId;
|
||||
this.distributionId = distribution.getId();
|
||||
this.price = price;
|
||||
this.distributionCashStatus = WithdrawStatusEnum.APPLY.name();
|
||||
this.distributionName = memberName;
|
||||
this.distributionName = distribution.getMemberName();
|
||||
|
||||
this.name = distribution.getName();
|
||||
this.idNumber = distribution.getIdNumber();
|
||||
this.settlementBankAccountName = distribution.getSettlementBankAccountName();
|
||||
this.settlementBankAccountNum = distribution.getSettlementBankAccountNum();
|
||||
this.settlementBankBranchName = distribution.getSettlementBankBranchName();
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,8 @@ public class DistributionOrder extends BaseIdEntity {
|
||||
private String image;
|
||||
@ApiModelProperty(value = "商品数量")
|
||||
private Integer num;
|
||||
@ApiModelProperty(value = "退款商品数量")
|
||||
private Integer refundNum;
|
||||
|
||||
public DistributionOrder(StoreFlow storeFlow) {
|
||||
distributionOrderStatus = DistributionOrderStatusEnum.NO_COMPLETED.name();
|
||||
@@ -95,6 +97,8 @@ public class DistributionOrder extends BaseIdEntity {
|
||||
specs = storeFlow.getSpecs();
|
||||
image = storeFlow.getImage();
|
||||
num = storeFlow.getNum();
|
||||
refundNum=0;
|
||||
sellBackRebate=0D;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,16 +6,10 @@ package cn.lili.modules.distribution.entity.enums;
|
||||
* @author pikachu
|
||||
*/
|
||||
public enum DistributionOrderStatusEnum {
|
||||
//未完成
|
||||
|
||||
NO_COMPLETED("未完成"),
|
||||
//待结算(冻结)
|
||||
WAIT_BILL("待结算"),
|
||||
//待提现
|
||||
WAIT_CASH("待提现"),
|
||||
//已提现
|
||||
COMPLETE_CASH("提现完成"),
|
||||
//订单取消
|
||||
CANCEL("订单取消"),
|
||||
//完成
|
||||
COMPLETE("完成"),
|
||||
//订单取消
|
||||
REFUND("退款");
|
||||
|
||||
|
||||
@@ -13,25 +13,32 @@ import org.apache.ibatis.annotations.Update;
|
||||
*/
|
||||
public interface DistributionMapper extends BaseMapper<Distribution> {
|
||||
|
||||
/**
|
||||
* 修改分销员可提现金额
|
||||
*
|
||||
* @param commissionFrozen 分销金额
|
||||
* @param distributionId 分销员ID
|
||||
*/
|
||||
@Update("UPDATE li_distribution set commission_frozen = (IFNULL(commission_frozen,0)+#{commissionFrozen}) " +
|
||||
", rebate_total=(IFNULL(rebate_total,0)+#{commissionFrozen}) WHERE id = #{distributionId}")
|
||||
void subCanRebate(Double commissionFrozen, String distributionId);
|
||||
@Update("UPDATE li_distribution set commission_frozen = (IFNULL(commission_frozen,0) - #{commissionFrozen}) " +
|
||||
", rebate_total=(IFNULL(rebate_total,0) - #{commissionFrozen}) " +
|
||||
", distribution_order_count=(IFNULL(distribution_order_count,0)-1) " +
|
||||
" WHERE id = #{distributionId}")
|
||||
void subRebate(Double commissionFrozen, String distributionId, Double distributionOrderPrice);
|
||||
|
||||
/**
|
||||
* 添加分销金额
|
||||
*
|
||||
* @param commissionFrozen 分销金额
|
||||
* @param distributionId 分销员ID
|
||||
*/
|
||||
@Update("UPDATE li_distribution set commission_frozen = (IFNULL(commission_frozen,0)+#{commissionFrozen}) " +
|
||||
", rebate_total=(IFNULL(rebate_total,0)+#{commissionFrozen}) " +
|
||||
", distribution_order_count=(IFNULL(distribution_order_count,0)+1) WHERE id = #{distributionId}")
|
||||
void addCanRebate(Double commissionFrozen, String distributionId);
|
||||
", distribution_order_price=(IFNULL(distribution_order_price,0)+#{distributionOrderPrice}) " +
|
||||
", distribution_order_count=(IFNULL(distribution_order_count,0)+1) " +
|
||||
" WHERE id = #{distributionId}")
|
||||
void addRebate(Double commissionFrozen, String distributionId, Double distributionOrderPrice);
|
||||
|
||||
|
||||
@Update("UPDATE li_distribution SET commission_frozen = (IFNULL(commission_frozen,0) - #{rebate}) " +
|
||||
",can_rebate=(IFNULL(can_rebate,0) + #{rebate}) " +
|
||||
" WHERE id = #{distributionId}")
|
||||
void addCanRebate(Double rebate, String distributionId);
|
||||
|
||||
@Update("UPDATE li_distribution SET can_rebate=(IFNULL(can_rebate,0) - #{rebate}),cash_rebate=(IFNULL(cash_rebate,0) + #{rebate}) " +
|
||||
" WHERE id = #{distributionId}")
|
||||
void addCashRebate(Double rebate, String distributionId);
|
||||
|
||||
|
||||
@Update("UPDATE li_distribution SET cash_rebate=(IFNULL(cash_rebate,0) - #{rebate}) " +
|
||||
" WHERE id = #{distributionId}")
|
||||
void subCashRebate(Double rebate, String distributionId);
|
||||
|
||||
}
|
||||
@@ -3,6 +3,9 @@ package cn.lili.modules.distribution.mapper;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.lili.modules.distribution.entity.dos.DistributionOrder;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
/**
|
||||
@@ -24,4 +27,15 @@ public interface DistributionOrderMapper extends BaseMapper<DistributionOrder> {
|
||||
",d.commission_frozen =(ifnull(d.commission_frozen,0) -(SELECT SUM( dorder.rebate ) FROM li_distribution_order AS dorder WHERE dorder.distribution_order_status = #{distributionOrderStatus} AND dorder.settle_cycle< #{settleCycle} AND dorder.distribution_id = d.id ) )")
|
||||
void rebate(String distributionOrderStatus, DateTime settleCycle);
|
||||
|
||||
/**
|
||||
* 查询待结算的分销订单
|
||||
* @return 待结算的分销订单
|
||||
*/
|
||||
@Select("UPDATE li_distribution_order distribution_order"
|
||||
+ " INNER JOIN li_order_item oi ON oi.sn = distribution_order.order_item_sn"
|
||||
+ " SET distribution_order.distribution_order_status = 'WAIT_BILL',"
|
||||
+ " distribution_order.settle_cycle = #{settleCycle} "
|
||||
+ " WHERE distribution_order.distribution_order_status = 'NO_COMPLETED'"
|
||||
+ " AND oi.after_sale_status = 'EXPIRED';")
|
||||
List<DistributionOrder> distributionSettlementOrder(Date settleCycle);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 分销佣金业务层
|
||||
*
|
||||
@@ -40,6 +42,9 @@ public interface DistributionCashService extends IService<DistributionCash> {
|
||||
*/
|
||||
IPage<DistributionCash> getDistributionCash(DistributionCashSearchParams distributionCashSearchParams);
|
||||
|
||||
|
||||
void queryExport(HttpServletResponse response,DistributionCashSearchParams distributionCashSearchParams);
|
||||
|
||||
/**
|
||||
* 审核分销提现申请
|
||||
*
|
||||
|
||||
@@ -5,6 +5,7 @@ import cn.lili.modules.distribution.entity.dos.DistributionOrder;
|
||||
import cn.lili.modules.distribution.entity.vos.DistributionOrderSearchParams;
|
||||
import cn.lili.modules.order.aftersale.entity.dos.AfterSale;
|
||||
import cn.lili.modules.order.order.entity.dos.OrderItem;
|
||||
import cn.lili.modules.order.order.entity.dos.StoreFlow;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
@@ -45,22 +46,12 @@ public interface DistributionOrderService extends IService<DistributionOrder> {
|
||||
/**
|
||||
* 订单退款
|
||||
* 记录分销订单
|
||||
*
|
||||
* @param afterSaleSn 售后单号
|
||||
*/
|
||||
void refundOrder(AfterSale afterSale);
|
||||
|
||||
/**
|
||||
* 分销订单状态修改
|
||||
*
|
||||
* @param orderItems
|
||||
* 分销订单完成
|
||||
*/
|
||||
void updateDistributionOrderStatus(List<OrderItem> orderItems);
|
||||
void completeOrder(StoreFlow storeFlow);
|
||||
|
||||
/**
|
||||
* 分销订单结算
|
||||
* @param dateTime
|
||||
* @param distributionOrderStatus
|
||||
*/
|
||||
void updateRebate(DateTime dateTime, String distributionOrderStatus);
|
||||
}
|
||||
@@ -78,18 +78,42 @@ public interface DistributionService extends IService<Distribution> {
|
||||
void checkDistributionSetting();
|
||||
|
||||
/**
|
||||
* 修改可提现金额
|
||||
*
|
||||
* @param canRebate 修改金额
|
||||
* @param distributionId 分销员ID
|
||||
*/
|
||||
void subCanRebate(Double canRebate, String distributionId);
|
||||
|
||||
/**
|
||||
* 添加分销金额
|
||||
* 添加分销冻结金额
|
||||
* 创建分销订单时进行调用
|
||||
*
|
||||
* @param rebate 金额
|
||||
* @param distributionId 分销员ID
|
||||
* @param distributionOrderPrice 分销订单金额
|
||||
*/
|
||||
void addRebate(Double rebate, String distributionId);
|
||||
void addRebate(Double rebate, String distributionId, Double distributionOrderPrice);
|
||||
|
||||
/**
|
||||
* 扣减分销冻结金额
|
||||
* 订单取消/退款时进行调用
|
||||
*
|
||||
* @param rebate 佣金
|
||||
* @param distributionId 分销员ID
|
||||
*/
|
||||
void subRebate(Double rebate, String distributionId, Double distributionOrderPrice);
|
||||
|
||||
/**
|
||||
* 添加分销可提现金额
|
||||
* 订单完成时进行调用
|
||||
* @param rebate 佣金
|
||||
* @param distributionId 分销员ID
|
||||
*/
|
||||
void addCanRebate(Double rebate, String distributionId);
|
||||
|
||||
/**
|
||||
* 添加提现金额
|
||||
* @param rebate
|
||||
* @param distributionId
|
||||
*/
|
||||
void addCashRebate(Double rebate, String distributionId);
|
||||
/**
|
||||
* 扣减提现金额
|
||||
* @param rebate
|
||||
* @param distributionId
|
||||
*/
|
||||
void subCashRebate(Double rebate, String distributionId);
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
package cn.lili.modules.distribution.serviceimpl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.lili.common.context.ThreadContextHolder;
|
||||
import cn.lili.common.enums.ClientTypeEnum;
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.properties.RocketmqCustomProperties;
|
||||
@@ -13,6 +20,14 @@ import cn.lili.modules.distribution.entity.vos.DistributionCashSearchParams;
|
||||
import cn.lili.modules.distribution.mapper.DistributionCashMapper;
|
||||
import cn.lili.modules.distribution.service.DistributionCashService;
|
||||
import cn.lili.modules.distribution.service.DistributionService;
|
||||
import cn.lili.modules.order.order.entity.dto.OrderExportDTO;
|
||||
import cn.lili.modules.order.order.entity.dto.OrderExportDetailDTO;
|
||||
import cn.lili.modules.order.order.entity.dto.OrderSearchParams;
|
||||
import cn.lili.modules.order.order.entity.dto.PriceDetailDTO;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderItemAfterSaleStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderTypeEnum;
|
||||
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
||||
import cn.lili.modules.wallet.entity.dto.MemberWalletUpdateDTO;
|
||||
import cn.lili.modules.wallet.entity.dto.MemberWithdrawalMessage;
|
||||
import cn.lili.modules.wallet.entity.enums.DepositServiceTypeEnum;
|
||||
@@ -25,12 +40,23 @@ import cn.lili.rocketmq.tags.MemberTagsEnum;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
@@ -76,7 +102,7 @@ public class DistributionCashServiceImpl extends ServiceImpl<DistributionCashMap
|
||||
distribution.setCommissionFrozen(CurrencyUtil.add(distribution.getCommissionFrozen(), applyMoney));
|
||||
distributionService.updateById(distribution);
|
||||
//提现申请记录
|
||||
DistributionCash distributionCash = new DistributionCash("D" + SnowFlake.getId(), distribution.getId(), applyMoney, distribution.getMemberName());
|
||||
DistributionCash distributionCash = new DistributionCash("D" + SnowFlake.getId(),applyMoney, distribution);
|
||||
boolean result = this.save(distributionCash);
|
||||
if (result) {
|
||||
//发送提现消息
|
||||
@@ -109,6 +135,28 @@ public class DistributionCashServiceImpl extends ServiceImpl<DistributionCashMap
|
||||
return this.page(PageUtil.initPage(distributionCashSearchParams), distributionCashSearchParams.queryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryExport(HttpServletResponse response, DistributionCashSearchParams distributionCashSearchParams) {
|
||||
XSSFWorkbook workbook = initExportData(this.list(distributionCashSearchParams.queryWrapper()));
|
||||
try {
|
||||
// 设置响应头
|
||||
String fileName = URLEncoder.encode("分销提现列表", "UTF-8");
|
||||
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
|
||||
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
workbook.write(out);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
workbook.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public DistributionCash audit(String id, String result) {
|
||||
@@ -123,17 +171,12 @@ public class DistributionCashServiceImpl extends ServiceImpl<DistributionCashMap
|
||||
//获取分销员
|
||||
Distribution distribution = distributionService.getById(distributorCash.getDistributionId());
|
||||
if (distribution != null && distribution.getDistributionStatus().equals(DistributionStatusEnum.PASS.name())) {
|
||||
MemberWithdrawalMessage memberWithdrawalMessage = new MemberWithdrawalMessage();
|
||||
//审核通过
|
||||
if (result.equals(WithdrawStatusEnum.VIA_AUDITING.name())) {
|
||||
memberWithdrawalMessage.setStatus(WithdrawStatusEnum.VIA_AUDITING.name());
|
||||
//分销记录操作
|
||||
distributorCash.setDistributionCashStatus(WithdrawStatusEnum.VIA_AUDITING.name());
|
||||
distributorCash.setPayTime(new Date());
|
||||
//提现到余额
|
||||
memberWalletService.increase(new MemberWalletUpdateDTO(distributorCash.getPrice(), distribution.getMemberId(), "分销[" + distributorCash.getSn() + "]佣金提现到余额[" + distributorCash.getPrice() + "]", DepositServiceTypeEnum.WALLET_COMMISSION.name()));
|
||||
} else {
|
||||
memberWithdrawalMessage.setStatus(WithdrawStatusEnum.FAIL_AUDITING.name());
|
||||
//分销员可提现金额退回
|
||||
distribution.setCanRebate(CurrencyUtil.add(distribution.getCanRebate(), distributorCash.getPrice()));
|
||||
distributorCash.setDistributionCashStatus(WithdrawStatusEnum.FAIL_AUDITING.name());
|
||||
@@ -142,14 +185,7 @@ public class DistributionCashServiceImpl extends ServiceImpl<DistributionCashMap
|
||||
//分销员金额相关处理
|
||||
distributionService.updateById(distribution);
|
||||
//修改分销提现申请
|
||||
boolean bool = this.updateById(distributorCash);
|
||||
//if (bool) {
|
||||
// //组织会员提现审核消息
|
||||
// memberWithdrawalMessage.setMemberId(distribution.getMemberId());
|
||||
// memberWithdrawalMessage.setPrice(distributorCash.getPrice());
|
||||
// String destination = rocketmqCustomProperties.getMemberTopic() + ":" + MemberTagsEnum.MEMBER_WITHDRAWAL.name();
|
||||
// rocketMQTemplate.asyncSend(destination, memberWithdrawalMessage, RocketmqSendCallbackBuilder.commonCallback());
|
||||
//}
|
||||
this.updateById(distributorCash);
|
||||
return distributorCash;
|
||||
}
|
||||
throw new ServiceException(ResultCode.DISTRIBUTION_NOT_EXIST);
|
||||
@@ -157,4 +193,38 @@ public class DistributionCashServiceImpl extends ServiceImpl<DistributionCashMap
|
||||
throw new ServiceException(ResultCode.DISTRIBUTION_CASH_NOT_EXIST);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化填充导出数据
|
||||
*
|
||||
* @param distributionCashList 导出的数据
|
||||
* @return 填充导出数据
|
||||
*/
|
||||
private XSSFWorkbook initExportData(List<DistributionCash> distributionCashList) {
|
||||
|
||||
XSSFWorkbook workbook = new XSSFWorkbook();
|
||||
Sheet sheet = workbook.createSheet("订单列表");
|
||||
|
||||
// 创建表头
|
||||
Row header = sheet.createRow(0);
|
||||
String[] headers = {"编号", "姓名", "身份证号", "结算银行开户行名称", "结算银行开户账号", "结算银行开户支行名称"};
|
||||
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
Cell cell = header.createCell(i);
|
||||
cell.setCellValue(headers[i]);
|
||||
}
|
||||
// 填充数据
|
||||
for (int i = 0; i < distributionCashList.size(); i++) {
|
||||
DistributionCash distributionCash = distributionCashList.get(i);
|
||||
Row row = sheet.createRow(i + 1);
|
||||
row.createCell(0).setCellValue(distributionCash.getSn());
|
||||
row.createCell(1).setCellValue(distributionCash.getName());
|
||||
row.createCell(2).setCellValue(distributionCash.getIdNumber());
|
||||
row.createCell(3).setCellValue(distributionCash.getSettlementBankAccountName());
|
||||
row.createCell(4).setCellValue(distributionCash.getSettlementBankAccountNum());
|
||||
row.createCell(5).setCellValue(distributionCash.getSettlementBankBranchName());
|
||||
}
|
||||
return workbook;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +1,23 @@
|
||||
package cn.lili.modules.distribution.serviceimpl;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.date.DateField;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.lili.common.utils.CurrencyUtil;
|
||||
import cn.lili.common.utils.SpringContextUtil;
|
||||
import cn.lili.modules.distribution.entity.dos.Distribution;
|
||||
import cn.lili.modules.distribution.entity.dos.DistributionOrder;
|
||||
import cn.lili.modules.distribution.entity.enums.DistributionOrderStatusEnum;
|
||||
import cn.lili.modules.distribution.entity.enums.DistributionStatusEnum;
|
||||
import cn.lili.modules.distribution.entity.vos.DistributionOrderSearchParams;
|
||||
import cn.lili.modules.distribution.mapper.DistributionOrderMapper;
|
||||
import cn.lili.modules.distribution.service.DistributionOrderService;
|
||||
import cn.lili.modules.distribution.service.DistributionService;
|
||||
import cn.lili.modules.order.aftersale.entity.dos.AfterSale;
|
||||
import cn.lili.modules.order.order.entity.dos.Order;
|
||||
import cn.lili.modules.order.order.entity.dos.OrderItem;
|
||||
import cn.lili.modules.order.order.entity.dos.StoreFlow;
|
||||
import cn.lili.modules.order.order.entity.dto.StoreFlowProfitSharingDTO;
|
||||
import cn.lili.modules.order.order.entity.dto.StoreFlowQueryDTO;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderItemAfterSaleStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.FlowTypeEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.PayStatusEnum;
|
||||
import cn.lili.modules.order.order.service.OrderService;
|
||||
import cn.lili.modules.order.order.service.StoreFlowService;
|
||||
import cn.lili.modules.system.entity.dos.Setting;
|
||||
import cn.lili.modules.system.entity.dto.DistributionSetting;
|
||||
import cn.lili.modules.system.entity.enums.SettingEnum;
|
||||
import cn.lili.modules.system.service.SettingService;
|
||||
import cn.lili.mybatis.util.PageUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
@@ -39,12 +29,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
* 分销订单接口实现
|
||||
@@ -54,7 +40,8 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DistributionOrderServiceImpl extends ServiceImpl<DistributionOrderMapper, DistributionOrder> implements DistributionOrderService {
|
||||
public class DistributionOrderServiceImpl extends ServiceImpl<DistributionOrderMapper, DistributionOrder>
|
||||
implements DistributionOrderService {
|
||||
|
||||
/**
|
||||
* 订单
|
||||
@@ -71,15 +58,12 @@ public class DistributionOrderServiceImpl extends ServiceImpl<DistributionOrderM
|
||||
*/
|
||||
@Autowired
|
||||
private DistributionService distributionService;
|
||||
/**
|
||||
* 系统设置
|
||||
*/
|
||||
@Autowired
|
||||
private SettingService settingService;
|
||||
|
||||
@Override
|
||||
public IPage<DistributionOrder> getDistributionOrderPage(DistributionOrderSearchParams distributionOrderSearchParams) {
|
||||
return this.page(PageUtil.initPage(distributionOrderSearchParams), distributionOrderSearchParams.queryWrapper());
|
||||
public IPage<DistributionOrder> getDistributionOrderPage(
|
||||
DistributionOrderSearchParams distributionOrderSearchParams) {
|
||||
return this.page(PageUtil.initPage(distributionOrderSearchParams),
|
||||
distributionOrderSearchParams.queryWrapper());
|
||||
|
||||
}
|
||||
|
||||
@@ -100,8 +84,8 @@ public class DistributionOrderServiceImpl extends ServiceImpl<DistributionOrderM
|
||||
//判断是否为分销订单,如果为分销订单则获取分销佣金
|
||||
if (order.getDistributionId() != null) {
|
||||
//根据订单编号获取有分销金额的店铺流水记录
|
||||
List<StoreFlow> storeFlowList = storeFlowService
|
||||
.listStoreFlow(StoreFlowQueryDTO.builder().justDistribution(true).orderSn(orderSn).build());
|
||||
List<StoreFlow> storeFlowList = storeFlowService.listStoreFlow(
|
||||
StoreFlowQueryDTO.builder().justDistribution(true).orderSn(orderSn).build());
|
||||
double rebate = 0.0;
|
||||
//循环店铺流水记录判断是否包含分销商品
|
||||
//包含分销商品则进行记录分销订单、计算分销总额
|
||||
@@ -116,39 +100,21 @@ public class DistributionOrderServiceImpl extends ServiceImpl<DistributionOrderM
|
||||
Distribution distribution = distributionService.getById(order.getDistributionId());
|
||||
distributionOrder.setDistributionName(distribution.getMemberName());
|
||||
|
||||
//设置结算天数(解冻日期)
|
||||
Setting setting = settingService.get(SettingEnum.DISTRIBUTION_SETTING.name());
|
||||
DistributionSetting distributionSetting = JSONUtil.toBean(setting.getSettingValue(), DistributionSetting.class);
|
||||
|
||||
|
||||
//添加分销订单
|
||||
this.save(distributionOrder);
|
||||
|
||||
//记录会员的分销总额
|
||||
if (rebate != 0.0) {
|
||||
distributionService.addRebate(rebate, order.getDistributionId());
|
||||
|
||||
//如果天数写0则立即进行结算
|
||||
// if (distributionSetting.getCashDay().equals(0)) {
|
||||
// DateTime dateTime = new DateTime();
|
||||
// dateTime = dateTime.offsetNew(DateField.DAY_OF_MONTH, -distributionSetting.getCashDay());
|
||||
// //防止事务失效,采用上下文获取bean
|
||||
// DistributionOrderService bean = SpringContextUtil.getBean(DistributionOrderService.class);
|
||||
// //分销订单结算
|
||||
// bean.updateRebate(dateTime, DistributionOrderStatusEnum.WAIT_BILL.name());
|
||||
// }
|
||||
distributionService.addRebate(rebate, order.getDistributionId(), storeFlow.getFinalPrice());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 1.获取订单判断是否为已付款的分销订单
|
||||
* 2.查看店铺流水记录分销佣金
|
||||
* 3.修改分销员的分销总金额、可提现金额
|
||||
* 1.获取订单判断是否为已付款的分销订单 2.查看店铺流水记录分销佣金 3.修改分销员的分销总金额、可提现金额
|
||||
*
|
||||
* @param orderSn 订单编号
|
||||
*/
|
||||
@@ -162,41 +128,35 @@ public class DistributionOrderServiceImpl extends ServiceImpl<DistributionOrderM
|
||||
if (order.getDistributionId() != null && order.getPayStatus().equals(PayStatusEnum.PAID.name())) {
|
||||
|
||||
//根据订单编号获取有分销金额的店铺流水记录
|
||||
List<DistributionOrder> distributionOrderList = this.list(new LambdaQueryWrapper<DistributionOrder>()
|
||||
.eq(DistributionOrder::getOrderSn, orderSn));
|
||||
List<DistributionOrder> distributionOrderList =
|
||||
this.list(new LambdaQueryWrapper<DistributionOrder>().eq(DistributionOrder::getOrderSn, orderSn));
|
||||
|
||||
//如果没有分销定单,则直接返回
|
||||
if (distributionOrderList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
//分销金额
|
||||
double rebate = 0.0;
|
||||
|
||||
//包含分销商品则进行记录分销订单、计算分销总额
|
||||
for (DistributionOrder distributionOrder : distributionOrderList) {
|
||||
rebate = CurrencyUtil.add(rebate, distributionOrder.getRebate());
|
||||
}
|
||||
|
||||
//如果包含分销商品则记录会员的分销总额
|
||||
if (rebate != 0.0) {
|
||||
distributionService.subCanRebate(CurrencyUtil.sub(0, rebate), order.getDistributionId());
|
||||
distributionService.subRebate(distributionOrder.getRebate(), order.getDistributionId(), distributionOrder.getSellBackRebate());
|
||||
}
|
||||
}
|
||||
|
||||
//修改分销订单的状态
|
||||
this.update(new LambdaUpdateWrapper<DistributionOrder>().eq(DistributionOrder::getOrderSn, orderSn)
|
||||
.set(DistributionOrder::getDistributionOrderStatus, DistributionOrderStatusEnum.CANCEL.name()));
|
||||
.set(DistributionOrder::getDistributionOrderStatus, DistributionOrderStatusEnum.REFUND.name()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refundOrder(AfterSale afterSale) {
|
||||
//判断是否为分销订单
|
||||
StoreFlow refundStoreFlow = storeFlowService.queryOne(StoreFlowQueryDTO.builder().justDistribution(true).refundSn(afterSale.getSn()).build());
|
||||
StoreFlow refundStoreFlow = storeFlowService.queryOne(
|
||||
StoreFlowQueryDTO.builder().justDistribution(true).refundSn(afterSale.getSn()).build());
|
||||
if (refundStoreFlow != null) {
|
||||
//获取收款分销订单
|
||||
DistributionOrder distributionOrder = this.getOne(new LambdaQueryWrapper<DistributionOrder>()
|
||||
.eq(DistributionOrder::getOrderItemSn, afterSale.getOrderItemSn()));
|
||||
DistributionOrder distributionOrder = this.getOne(
|
||||
new LambdaQueryWrapper<DistributionOrder>().eq(DistributionOrder::getOrderItemSn,
|
||||
afterSale.getOrderItemSn()));
|
||||
//分销订单不存在,则直接返回
|
||||
if (distributionOrder == null) {
|
||||
return;
|
||||
@@ -204,143 +164,41 @@ public class DistributionOrderServiceImpl extends ServiceImpl<DistributionOrderM
|
||||
if (distributionOrder.getSellBackRebate() == null) {
|
||||
distributionOrder.setSellBackRebate(refundStoreFlow.getDistributionRebate());
|
||||
} else {
|
||||
distributionOrder.setSellBackRebate(CurrencyUtil.add(distributionOrder.getSellBackRebate(), refundStoreFlow.getDistributionRebate()));
|
||||
distributionOrder.setSellBackRebate(
|
||||
CurrencyUtil.add(distributionOrder.getSellBackRebate(), refundStoreFlow.getDistributionRebate()));
|
||||
}
|
||||
|
||||
distributionOrder.setRebate(CurrencyUtil.sub(distributionOrder.getRebate(), refundStoreFlow.getDistributionRebate()));
|
||||
if (distributionOrder.getRebate() == 0) {
|
||||
distributionOrder.setDistributionOrderStatus(DistributionOrderStatusEnum.REFUND.name());
|
||||
}
|
||||
distributionOrder.setRefundNum(distributionOrder.getRefundNum() + afterSale.getNum());
|
||||
this.updateById(distributionOrder);
|
||||
|
||||
// 修改分销员提成金额
|
||||
distributionService.subCanRebate(CurrencyUtil.sub(0, refundStoreFlow.getDistributionRebate()), distributionOrder.getDistributionId());
|
||||
if (refundStoreFlow.getDistributionRebate() != 0.0) {
|
||||
distributionService.subRebate(refundStoreFlow.getDistributionRebate(), distributionOrder.getDistributionId(), refundStoreFlow.getFinalPrice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDistributionOrderStatus(List<OrderItem> orderItems) {
|
||||
if (orderItems.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//获取未完成分销订单
|
||||
List<DistributionOrder> distributionOrderList = this.list(new LambdaQueryWrapper<DistributionOrder>()
|
||||
.eq(DistributionOrder::getDistributionOrderStatus, DistributionOrderStatusEnum.NO_COMPLETED.name()));
|
||||
|
||||
if (distributionOrderList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<DistributionOrder> list = ListUtil.list(false);
|
||||
|
||||
orderItems.stream().forEach(orderItem -> {
|
||||
//订单售后状态为已失效并且投诉状态为已失效
|
||||
if (StrUtil.equals(OrderItemAfterSaleStatusEnum.EXPIRED.name(), orderItem.getAfterSaleStatus())) {
|
||||
|
||||
|
||||
List<DistributionOrder> collect = distributionOrderList.stream()
|
||||
.filter(distributionOrder -> StrUtil.equals(distributionOrder.getOrderItemSn(), orderItem.getSn()))
|
||||
.map((distributionOrder) -> {
|
||||
distributionOrder.setDistributionOrderStatus(DistributionOrderStatusEnum.WAIT_BILL.name());
|
||||
distributionOrder.setSettleCycle(new Date());
|
||||
return distributionOrder;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
list.addAll(collect);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
//批量修改分销订单结算状态
|
||||
this.updateBatchById(list);
|
||||
public void completeOrder(StoreFlow storeFlow) {
|
||||
if (storeFlow.getFlowType().equals(FlowTypeEnum.PAY.name())
|
||||
&&storeFlow.getDistributionRebate() != null
|
||||
&& storeFlow.getDistributionRebate() != 0) {
|
||||
//获取分账内容
|
||||
StoreFlowProfitSharingDTO storeFlowProfitSharingDTO = JSONUtil.toBean(storeFlow.getProfitSharing(), StoreFlowProfitSharingDTO.class);
|
||||
//获取分销订单
|
||||
DistributionOrder distributionOrder = this.getOne(new LambdaQueryWrapper<DistributionOrder>().eq(DistributionOrder::getOrderItemSn, storeFlow.getOrderItemSn()));
|
||||
//解冻分销金额
|
||||
distributionService.addCanRebate(storeFlowProfitSharingDTO.getDistributionPrice(), distributionOrder.getDistributionId());
|
||||
// 订单完成
|
||||
this.update(new LambdaUpdateWrapper<DistributionOrder>()
|
||||
.eq(DistributionOrder::getId, distributionOrder.getId())
|
||||
.set(DistributionOrder::getDistributionOrderStatus, DistributionOrderStatusEnum.COMPLETE.name()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRebate(DateTime dateTime, String distributionOrderStatus) {
|
||||
//结算时间延后五分钟
|
||||
dateTime = dateTime.offsetNew(DateField.MINUTE, 5);
|
||||
//获取待结算订单
|
||||
List<DistributionOrder> distributionOrderList = this.list(new LambdaQueryWrapper<DistributionOrder>()
|
||||
.eq(DistributionOrder::getDistributionOrderStatus, distributionOrderStatus)
|
||||
.isNotNull(DistributionOrder::getSettleCycle)
|
||||
.le(DistributionOrder::getSettleCycle, dateTime));
|
||||
//校验待结算订单
|
||||
if (ObjectUtil.isNotNull(distributionOrderList) && distributionOrderList.size() > 0) {
|
||||
//结算分销人员信息列表
|
||||
List<Distribution> distributionUpdateList = new ArrayList<>();
|
||||
//获取分销员信息
|
||||
List<Distribution> distributionList = distributionService.list(new LambdaQueryWrapper<Distribution>()
|
||||
.eq(Distribution::getDistributionStatus, DistributionStatusEnum.PASS.name()));
|
||||
//根据销人员获取对应分销订单
|
||||
Map<String, List<DistributionOrder>> distributionOrderList1 = distributionOrderList.stream()
|
||||
.collect(Collectors.groupingBy(DistributionOrder::getDistributionId));
|
||||
|
||||
//校验分销订单不为空
|
||||
if (ObjectUtil.isNotNull(distributionOrderList1) && distributionOrderList1.size() > 0) {
|
||||
//遍历分销订单map
|
||||
distributionOrderList1.forEach((key, value) -> {
|
||||
//计算分销结算金额
|
||||
distributionUpdateList.add(checkDistribution(key, value, distributionList));
|
||||
});
|
||||
}
|
||||
|
||||
//校验分销信息列表不为空
|
||||
if (ObjectUtil.isNotNull(distributionUpdateList) && !distributionUpdateList.isEmpty()) {
|
||||
//修改分销员收益
|
||||
distributionService.updateBatchById(distributionUpdateList);
|
||||
distributionOrderList.stream().forEach(distributionOrder -> {
|
||||
//修改分销订单状态为待提现
|
||||
distributionOrder.setDistributionOrderStatus(DistributionOrderStatusEnum.WAIT_CASH.name());
|
||||
});
|
||||
}
|
||||
|
||||
//修改分销订单状态
|
||||
this.updateBatchById(distributionOrderList);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 计算分销结算金额
|
||||
*
|
||||
* @param distributionId 分销ID
|
||||
* @param list 分销订单
|
||||
* @param distributionList 分销列表
|
||||
* @return
|
||||
*/
|
||||
public Distribution checkDistribution(String
|
||||
distributionId, List<DistributionOrder> list, List<Distribution> distributionList) {
|
||||
//获取所有待结算订单分销人员信息
|
||||
Distribution distribution = distributionList.parallelStream().filter(a -> StrUtil.equals(a.getId(), distributionId)).collect(Collectors.toList()).get(0);
|
||||
|
||||
//获取分销订单总金额
|
||||
double rebate = list.stream().mapToDouble(DistributionOrder::getRebate).sum();
|
||||
|
||||
//检验单分销人员冻结金额为负数时.扣除负数冻结金额后再结算
|
||||
if (distribution.getCommissionFrozen() < 0) {
|
||||
rebate = CurrencyUtil.add(distribution.getCommissionFrozen() == null ? 0.0 : distribution.getCommissionFrozen(), rebate);
|
||||
}
|
||||
//结算订单总金额+分销可提现金额
|
||||
Double canRebate = CurrencyUtil.add(rebate, distribution.getCanRebate() == null ? 0.0 : distribution.getCanRebate());
|
||||
//结算金额小于0
|
||||
if (canRebate < 0) {
|
||||
//结算订单总金额+分销可提现金额
|
||||
distribution.setCanRebate(0.0);
|
||||
//冻结金额
|
||||
distribution.setCommissionFrozen(canRebate);
|
||||
} else {
|
||||
//结算订单总金额+分销可提现金额
|
||||
distribution.setCanRebate(canRebate);
|
||||
//冻结金额
|
||||
distribution.setCommissionFrozen(0.0);
|
||||
}
|
||||
|
||||
return distribution;
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ public class DistributionServiceImpl extends ServiceImpl<DistributionMapper, Dis
|
||||
default:
|
||||
throw new ServiceException(ResultCode.DISTRIBUTION_IS_APPLY);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
//如果未申请分销员则新增进行申请
|
||||
//获取当前登录用户
|
||||
Member member = memberService.getUserInfo();
|
||||
@@ -181,14 +181,30 @@ public class DistributionServiceImpl extends ServiceImpl<DistributionMapper, Dis
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void subCanRebate(Double canRebate, String distributionId) {
|
||||
this.baseMapper.subCanRebate(canRebate, distributionId);
|
||||
public void subRebate(Double canRebate, String distributionId, Double distributionOrderPrice) {
|
||||
this.baseMapper.subRebate(canRebate, distributionId, distributionOrderPrice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRebate(Double rebate, String distributionId) {
|
||||
public void addRebate(Double rebate, String distributionId, Double distributionOrderPrice) {
|
||||
this.baseMapper.addRebate(rebate, distributionId, distributionOrderPrice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCanRebate(Double rebate, String distributionId) {
|
||||
this.baseMapper.addCanRebate(rebate, distributionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCashRebate(Double rebate, String distributionId) {
|
||||
this.baseMapper.addCashRebate(rebate, distributionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subCashRebate(Double rebate, String distributionId) {
|
||||
this.baseMapper.subCashRebate(rebate, distributionId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,6 +31,13 @@ public interface FileService extends IService<File> {
|
||||
*/
|
||||
void batchDeleteByDirectory(String directoryId);
|
||||
|
||||
/**
|
||||
* 根据文件夹ID查看是否有文件
|
||||
* @param directoryId 文件夹ID
|
||||
* @return
|
||||
*/
|
||||
Boolean countByDirectory(String directoryId);
|
||||
|
||||
/**
|
||||
* 所有者批量删除
|
||||
*
|
||||
|
||||
@@ -4,8 +4,6 @@ import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.security.AuthUser;
|
||||
import cn.lili.common.vo.PageVO;
|
||||
import cn.lili.common.vo.SearchVO;
|
||||
import cn.lili.modules.file.entity.File;
|
||||
import cn.lili.modules.file.entity.dto.FileOwnerDTO;
|
||||
import cn.lili.modules.file.mapper.FileMapper;
|
||||
@@ -15,11 +13,10 @@ import cn.lili.mybatis.util.PageUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 文件管理业务层实现
|
||||
@@ -42,7 +39,9 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements Fi
|
||||
List<File> files = this.list(queryWrapper);
|
||||
List<String> keys = new ArrayList<>();
|
||||
files.forEach(item -> keys.add(item.getFileKey()));
|
||||
filePluginFactory.filePlugin().deleteFile(keys);
|
||||
if (!keys.isEmpty()) {
|
||||
filePluginFactory.filePlugin().deleteFile(keys);
|
||||
}
|
||||
this.remove(queryWrapper);
|
||||
}
|
||||
|
||||
@@ -54,10 +53,17 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements Fi
|
||||
List<File> files = this.list(queryWrapper);
|
||||
List<String> keys = new ArrayList<>();
|
||||
files.forEach(item -> keys.add(item.getFileKey()));
|
||||
filePluginFactory.filePlugin().deleteFile(keys);
|
||||
if (!keys.isEmpty()) {
|
||||
filePluginFactory.filePlugin().deleteFile(keys);
|
||||
}
|
||||
this.remove(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean countByDirectory(String directoryId) {
|
||||
return this.count(new LambdaQueryWrapper<File>().eq(File::getFileDirectoryId, directoryId))>0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void batchDelete(List<String> ids, AuthUser authUser) {
|
||||
LambdaQueryWrapper<File> queryWrapper = new LambdaQueryWrapper<>();
|
||||
@@ -88,26 +94,33 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements Fi
|
||||
public IPage<File> customerPage(FileOwnerDTO fileOwnerDTO) {
|
||||
LambdaQueryWrapper<File> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getName()), File::getName, fileOwnerDTO.getName())
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getOwnerName()), File::getOwnerName, fileOwnerDTO.getOwnerName())
|
||||
.eq(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileDirectoryId()),File::getFileDirectoryId, fileOwnerDTO.getFileDirectoryId())
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileKey()), File::getFileKey, fileOwnerDTO.getFileKey())
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileType()), File::getFileType, fileOwnerDTO.getFileType())
|
||||
.between(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getStartDate()) && CharSequenceUtil.isNotEmpty(fileOwnerDTO.getEndDate()),
|
||||
File::getCreateTime, fileOwnerDTO.getStartDate(), fileOwnerDTO.getEndDate());
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getOwnerName()), File::getOwnerName,
|
||||
fileOwnerDTO.getOwnerName())
|
||||
.eq(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileDirectoryId()), File::getFileDirectoryId,
|
||||
fileOwnerDTO.getFileDirectoryId())
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileKey()), File::getFileKey, fileOwnerDTO.getFileKey())
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileType()), File::getFileType,
|
||||
fileOwnerDTO.getFileType()).between(
|
||||
CharSequenceUtil.isNotEmpty(fileOwnerDTO.getStartDate()) && CharSequenceUtil.isNotEmpty(
|
||||
fileOwnerDTO.getEndDate()), File::getCreateTime, fileOwnerDTO.getStartDate(),
|
||||
fileOwnerDTO.getEndDate());
|
||||
return this.page(PageUtil.initPage(fileOwnerDTO), queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<File> customerPageOwner(FileOwnerDTO fileOwnerDTO) {
|
||||
LambdaQueryWrapper<File> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getOwnerId()), File::getOwnerId, fileOwnerDTO.getOwnerId())
|
||||
.eq(File::getUserEnums, fileOwnerDTO.getUserEnums())
|
||||
.eq(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileDirectoryId()),File::getFileDirectoryId, fileOwnerDTO.getFileDirectoryId())
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getName()), File::getName, fileOwnerDTO.getName())
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileKey()), File::getFileKey, fileOwnerDTO.getFileKey())
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileType()), File::getFileType, fileOwnerDTO.getFileType())
|
||||
.between(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getStartDate()) && CharSequenceUtil.isNotEmpty(fileOwnerDTO.getEndDate()),
|
||||
File::getCreateTime, fileOwnerDTO.getStartDate(), fileOwnerDTO.getEndDate());
|
||||
queryWrapper.eq(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getOwnerId()), File::getOwnerId,
|
||||
fileOwnerDTO.getOwnerId()).eq(File::getUserEnums, fileOwnerDTO.getUserEnums())
|
||||
.eq(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileDirectoryId()), File::getFileDirectoryId,
|
||||
fileOwnerDTO.getFileDirectoryId())
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getName()), File::getName, fileOwnerDTO.getName())
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileKey()), File::getFileKey, fileOwnerDTO.getFileKey())
|
||||
.like(CharSequenceUtil.isNotEmpty(fileOwnerDTO.getFileType()), File::getFileType,
|
||||
fileOwnerDTO.getFileType()).between(
|
||||
CharSequenceUtil.isNotEmpty(fileOwnerDTO.getStartDate()) && CharSequenceUtil.isNotEmpty(
|
||||
fileOwnerDTO.getEndDate()), File::getCreateTime, fileOwnerDTO.getStartDate(),
|
||||
fileOwnerDTO.getEndDate());
|
||||
return this.page(PageUtil.initPage(fileOwnerDTO), queryWrapper);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import lombok.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 商品查询条件
|
||||
@@ -27,6 +28,7 @@ public class GoodsSearchParams extends PageVO {
|
||||
|
||||
private static final long serialVersionUID = 2544015852728566887L;
|
||||
|
||||
|
||||
@ApiModelProperty(value = "商品编号")
|
||||
private String goodsId;
|
||||
|
||||
@@ -69,6 +71,9 @@ public class GoodsSearchParams extends PageVO {
|
||||
@ApiModelProperty(value = "审核状态")
|
||||
private String authFlag;
|
||||
|
||||
@ApiModelProperty(value = "商品状态")
|
||||
private String goodsStatus;
|
||||
|
||||
@ApiModelProperty(value = "库存数量")
|
||||
private Integer leQuantity;
|
||||
|
||||
@@ -95,6 +100,8 @@ public class GoodsSearchParams extends PageVO {
|
||||
|
||||
public <T> QueryWrapper<T> queryWrapper() {
|
||||
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
// 统一使用 CharSequenceUtil.isNotEmpty() 处理字符串
|
||||
if (CharSequenceUtil.isNotEmpty(goodsId)) {
|
||||
queryWrapper.eq("goods_id", goodsId);
|
||||
}
|
||||
@@ -104,9 +111,12 @@ public class GoodsSearchParams extends PageVO {
|
||||
if (CharSequenceUtil.isNotEmpty(id)) {
|
||||
queryWrapper.in("id", Arrays.asList(id.split(",")));
|
||||
}
|
||||
|
||||
// 统一使用 CollUtil.isNotEmpty() 处理集合
|
||||
if (CollUtil.isNotEmpty(ids)) {
|
||||
queryWrapper.in("id", ids);
|
||||
}
|
||||
|
||||
if (CharSequenceUtil.isNotEmpty(storeId)) {
|
||||
queryWrapper.eq("store_id", storeId);
|
||||
}
|
||||
@@ -119,36 +129,55 @@ public class GoodsSearchParams extends PageVO {
|
||||
if (CharSequenceUtil.isNotEmpty(storeCategoryPath)) {
|
||||
queryWrapper.like("store_category_path", storeCategoryPath);
|
||||
}
|
||||
if (selfOperated != null) {
|
||||
if (CharSequenceUtil.isNotEmpty(goodsStatus)) {
|
||||
if(goodsStatus.equals(GoodsStatusEnum.UPPER.name())){
|
||||
queryWrapper.eq("auth_flag", GoodsAuthEnum.PASS.name());
|
||||
queryWrapper.eq("market_enable", GoodsStatusEnum.UPPER.name());
|
||||
}else if(goodsStatus.equals(GoodsStatusEnum.DOWN.name())){
|
||||
queryWrapper.eq("auth_flag", GoodsAuthEnum.PASS.name());
|
||||
queryWrapper.eq("market_enable", GoodsStatusEnum.DOWN.name());
|
||||
}else if(goodsStatus.equals(GoodsAuthEnum.TOBEAUDITED.name())){
|
||||
queryWrapper.eq("auth_flag", GoodsAuthEnum.TOBEAUDITED.name());
|
||||
}else if(goodsStatus.equals(GoodsAuthEnum.REFUSE.name())){
|
||||
queryWrapper.eq("auth_flag", GoodsAuthEnum.REFUSE.name());
|
||||
}
|
||||
}
|
||||
|
||||
// 统一使用 Objects.nonNull() 处理对象非空判断
|
||||
if (Objects.nonNull(selfOperated)) {
|
||||
queryWrapper.eq("self_operated", selfOperated);
|
||||
}
|
||||
|
||||
if (CharSequenceUtil.isNotEmpty(marketEnable)) {
|
||||
queryWrapper.eq("market_enable", marketEnable);
|
||||
}
|
||||
if (CharSequenceUtil.isNotEmpty(authFlag)) {
|
||||
queryWrapper.eq("auth_flag", authFlag);
|
||||
}
|
||||
if (leQuantity != null) {
|
||||
|
||||
if (Objects.nonNull(leQuantity)) {
|
||||
queryWrapper.le("quantity", leQuantity);
|
||||
}
|
||||
if (geQuantity != null) {
|
||||
if (Objects.nonNull(geQuantity)) {
|
||||
queryWrapper.gt("quantity", geQuantity);
|
||||
}
|
||||
if (recommend != null) {
|
||||
if (Objects.nonNull(recommend)) {
|
||||
queryWrapper.le("recommend", recommend);
|
||||
}
|
||||
|
||||
if (CharSequenceUtil.isNotEmpty(goodsType)) {
|
||||
queryWrapper.eq("goods_type", goodsType);
|
||||
}
|
||||
if (CharSequenceUtil.isNotEmpty(salesModel)) {
|
||||
queryWrapper.eq("sales_model", salesModel);
|
||||
}
|
||||
if(alertQuantity != null && alertQuantity){
|
||||
|
||||
if(Objects.nonNull(alertQuantity) && alertQuantity){
|
||||
queryWrapper.apply("quantity <= alert_quantity");
|
||||
queryWrapper.ge("alert_quantity", 0);
|
||||
}
|
||||
queryWrapper.in(CollUtil.isNotEmpty(ids), "id", ids);
|
||||
|
||||
queryWrapper.in(CollUtil.isNotEmpty(ids), "id", ids);
|
||||
queryWrapper.eq("delete_flag", false);
|
||||
this.betweenWrapper(queryWrapper);
|
||||
return queryWrapper;
|
||||
|
||||
@@ -23,4 +23,19 @@ public class GoodsSkuStockDTO {
|
||||
|
||||
@ApiModelProperty(value = "预警库存")
|
||||
private Integer alertQuantity;
|
||||
|
||||
@ApiModelProperty(value = "规格信息")
|
||||
private String simpleSpecs;
|
||||
|
||||
@ApiModelProperty(value = "商品编号")
|
||||
private String sn;
|
||||
|
||||
@ApiModelProperty(value = "商品名称")
|
||||
private String goodsName;
|
||||
|
||||
/**
|
||||
* @see cn.lili.modules.goods.entity.enums.GoodsStockTypeEnum
|
||||
*/
|
||||
@ApiModelProperty(value = "类型")
|
||||
private String type;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.lili.modules.goods.entity.enums;
|
||||
|
||||
/**
|
||||
* 库存操作类型
|
||||
*/
|
||||
public enum GoodsStockTypeEnum {
|
||||
|
||||
|
||||
SUB("减"),
|
||||
|
||||
ADD("增");
|
||||
|
||||
private final String description;
|
||||
|
||||
GoodsStockTypeEnum(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
// 根据描述获取枚举实例
|
||||
public static GoodsStockTypeEnum fromDescription(String description) {
|
||||
for (GoodsStockTypeEnum type : GoodsStockTypeEnum.values()) {
|
||||
if (type.getDescription().equals(description)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("No matching enum constant for description: " + description);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.lili.modules.goods.entity.vos;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class GoodsNumVO {
|
||||
|
||||
@ApiModelProperty(value = "出售中的商品数量")
|
||||
private Integer upperGoodsNum;
|
||||
@ApiModelProperty(value = "仓库中的商品数量")
|
||||
private Integer downGoodsNum;
|
||||
@ApiModelProperty(value = "待审核商品数量")
|
||||
private Integer auditGoodsNum;
|
||||
@ApiModelProperty(value = "审核未通过数量")
|
||||
private Integer refuseGoodsNum;
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package cn.lili.modules.goods.mapper;
|
||||
import cn.lili.modules.goods.entity.dos.GoodsSku;
|
||||
import cn.lili.modules.goods.entity.dto.GoodsSkuDTO;
|
||||
import cn.lili.modules.goods.entity.dto.GoodsSkuStockDTO;
|
||||
import cn.lili.modules.order.order.entity.dto.OrderExportDTO;
|
||||
import cn.lili.modules.order.order.entity.vo.OrderSimpleVO;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
@@ -115,6 +117,7 @@ public interface GoodsSkuMapper extends BaseMapper<GoodsSku> {
|
||||
@Select("SELECT *,g.params as params FROM li_goods_sku gs inner join li_goods g on gs.goods_id = g.id ${ew.customSqlSegment}")
|
||||
IPage<GoodsSkuDTO> queryByParams(IPage<GoodsSkuDTO> page, @Param(Constants.WRAPPER) Wrapper<GoodsSkuDTO> queryWrapper);
|
||||
|
||||
@Select("SELECT id as sku_id, quantity, goods_id FROM li_goods_sku ${ew.customSqlSegment}")
|
||||
@Select("SELECT id as sku_id, quantity, goods_id,simple_specs,sn,goods_name FROM li_goods_sku ${ew.customSqlSegment}")
|
||||
List<GoodsSkuStockDTO> queryStocks(@Param(Constants.WRAPPER) Wrapper<GoodsSku> queryWrapper);
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import cn.lili.modules.goods.entity.dto.GoodsOperationDTO;
|
||||
import cn.lili.modules.goods.entity.dto.GoodsSearchParams;
|
||||
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
|
||||
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
|
||||
import cn.lili.modules.goods.entity.vos.GoodsNumVO;
|
||||
import cn.lili.modules.goods.entity.vos.GoodsVO;
|
||||
import cn.lili.modules.store.entity.dos.Store;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
@@ -83,6 +84,14 @@ public interface GoodsService extends IService<Goods> {
|
||||
*/
|
||||
IPage<Goods> queryByParams(GoodsSearchParams goodsSearchParams);
|
||||
|
||||
/**
|
||||
* 获取商品数量
|
||||
*
|
||||
* @param goodsSearchParams 查询参数
|
||||
* @return 商品数量
|
||||
*/
|
||||
GoodsNumVO getGoodsNumVO(GoodsSearchParams goodsSearchParams);
|
||||
|
||||
|
||||
/**
|
||||
* 商品查询
|
||||
@@ -191,6 +200,11 @@ public interface GoodsService extends IService<Goods> {
|
||||
*/
|
||||
void categoryGoodsName(String categoryId);
|
||||
|
||||
|
||||
/**
|
||||
* 添加商品评价数量
|
||||
*
|
||||
* @param commentNum 评价数量
|
||||
* @param goodsId 商品ID
|
||||
*/
|
||||
void addGoodsCommentNum(Integer commentNum, String goodsId);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@ import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -146,7 +148,20 @@ public interface GoodsSkuService extends IService<GoodsSku> {
|
||||
* @return 商品sku信息
|
||||
*/
|
||||
IPage<GoodsSku> getGoodsSkuByPage(GoodsSearchParams searchParams);
|
||||
/**
|
||||
* 查询导出商品库存
|
||||
*
|
||||
* @param searchParams 查询参数
|
||||
* @return 导出商品库存
|
||||
*/
|
||||
void queryExportStock(HttpServletResponse response, GoodsSearchParams searchParams);
|
||||
|
||||
/**
|
||||
* 导入商品库存
|
||||
* @param storeId 店铺ID
|
||||
* @param files 文件
|
||||
*/
|
||||
void importStock(String storeId, MultipartFile files);
|
||||
|
||||
/**
|
||||
* 分页查询商品sku信息
|
||||
@@ -187,6 +202,7 @@ public interface GoodsSkuService extends IService<GoodsSku> {
|
||||
* @param goodsSkuStockDTOS sku库存修改实体
|
||||
*/
|
||||
void updateStocks(List<GoodsSkuStockDTO> goodsSkuStockDTOS);
|
||||
void updateStocksByType(List<GoodsSkuStockDTO> goodsSkuStockDTOS);
|
||||
|
||||
/**
|
||||
* 更新SKU预警库存
|
||||
@@ -207,6 +223,7 @@ public interface GoodsSkuService extends IService<GoodsSku> {
|
||||
* @param quantity 设置的库存数量
|
||||
*/
|
||||
void updateStock(String skuId, Integer quantity);
|
||||
void updateStock(String skuId, Integer quantity,String type);
|
||||
|
||||
/**
|
||||
* 获取商品sku库存
|
||||
@@ -279,4 +296,13 @@ public interface GoodsSkuService extends IService<GoodsSku> {
|
||||
* @return 库存数量
|
||||
*/
|
||||
Integer getGoodsStock(String goodsId);
|
||||
|
||||
/**
|
||||
* 更新sku运费模版
|
||||
*
|
||||
* @param goodsId 商品id
|
||||
* @param templateId 运费模版id
|
||||
* @return 操作结果
|
||||
*/
|
||||
Boolean freight(List<String> goodsId, String templateId);
|
||||
}
|
||||
@@ -205,7 +205,7 @@ public class GoodsImportServiceImpl implements GoodsImportService {
|
||||
goodsImportDTO.setCategory(category);
|
||||
goodsImportDTO.setTemplate(templateId);
|
||||
goodsImportDTO.setGoodsUnit(objects.get(4).toString().substring(objects.get(4).toString().indexOf("-") + 1));
|
||||
goodsImportDTO.setRelease(objects.get(5).toString().equals("上架"));
|
||||
goodsImportDTO.setRelease("上架".equals(objects.get(5).toString()));
|
||||
|
||||
List<String> goodsGalleryList = new ArrayList<>();
|
||||
goodsGalleryList.add(objects.get(6).toString());
|
||||
|
||||
@@ -20,6 +20,7 @@ import cn.lili.modules.goods.entity.dto.GoodsParamsDTO;
|
||||
import cn.lili.modules.goods.entity.dto.GoodsSearchParams;
|
||||
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
|
||||
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
|
||||
import cn.lili.modules.goods.entity.vos.GoodsNumVO;
|
||||
import cn.lili.modules.goods.entity.vos.GoodsSkuVO;
|
||||
import cn.lili.modules.goods.entity.vos.GoodsVO;
|
||||
import cn.lili.modules.goods.mapper.GoodsMapper;
|
||||
@@ -272,7 +273,7 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
|
||||
goodsVO.setWholesaleList(wholesaleList);
|
||||
}
|
||||
|
||||
cache.put(CachePrefix.GOODS.getPrefix() + goodsId, goodsVO);
|
||||
cache.put(CachePrefix.GOODS.getPrefix() + goodsId, goodsVO,7200L);
|
||||
return goodsVO;
|
||||
}
|
||||
|
||||
@@ -281,6 +282,40 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
|
||||
return this.page(PageUtil.initPage(goodsSearchParams), goodsSearchParams.queryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoodsNumVO getGoodsNumVO(GoodsSearchParams goodsSearchParams) {
|
||||
GoodsNumVO goodsNumVO = new GoodsNumVO();
|
||||
|
||||
// 获取基础查询条件
|
||||
QueryWrapper<Goods> baseWrapper = goodsSearchParams.queryWrapper();
|
||||
|
||||
// 使用聚合查询一次性获取所有状态的商品数量
|
||||
List<Map<String, Object>> results = this.baseMapper.selectMaps(
|
||||
baseWrapper.select(
|
||||
"COUNT(CASE WHEN auth_flag = 'PASS' AND market_enable = 'UPPER' THEN 1 END) as upperGoodsNum",
|
||||
"COUNT(CASE WHEN auth_flag = 'PASS' AND market_enable = 'DOWN' THEN 1 END) as downGoodsNum",
|
||||
"COUNT(CASE WHEN auth_flag = 'TOBEAUDITED' THEN 1 END) as auditGoodsNum",
|
||||
"COUNT(CASE WHEN auth_flag = 'REFUSE' THEN 1 END) as refuseGoodsNum"
|
||||
)
|
||||
);
|
||||
|
||||
if (!results.isEmpty()) {
|
||||
Map<String, Object> result = results.get(0);
|
||||
goodsNumVO.setUpperGoodsNum(((Number) result.get("upperGoodsNum")).intValue());
|
||||
goodsNumVO.setDownGoodsNum(((Number) result.get("downGoodsNum")).intValue());
|
||||
goodsNumVO.setAuditGoodsNum(((Number) result.get("auditGoodsNum")).intValue());
|
||||
goodsNumVO.setRefuseGoodsNum(((Number) result.get("refuseGoodsNum")).intValue());
|
||||
} else {
|
||||
// 如果没有结果,设置默认值为0
|
||||
goodsNumVO.setUpperGoodsNum(0);
|
||||
goodsNumVO.setDownGoodsNum(0);
|
||||
goodsNumVO.setAuditGoodsNum(0);
|
||||
goodsNumVO.setRefuseGoodsNum(0);
|
||||
}
|
||||
|
||||
return goodsNumVO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品查询
|
||||
*
|
||||
@@ -437,6 +472,7 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
|
||||
lambdaUpdateWrapper.in(Goods::getId, goodsIds);
|
||||
List<String> goodsCache = goodsIds.stream().map(item -> CachePrefix.GOODS.getPrefix() + item).collect(Collectors.toList());
|
||||
cache.multiDel(goodsCache);
|
||||
goodsSkuService.freight(goodsIds, templateId);
|
||||
return this.update(lambdaUpdateWrapper);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package cn.lili.modules.goods.serviceimpl;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.lili.cache.Cache;
|
||||
@@ -23,6 +25,7 @@ import cn.lili.modules.goods.entity.dto.GoodsSkuStockDTO;
|
||||
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
|
||||
import cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum;
|
||||
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
|
||||
import cn.lili.modules.goods.entity.enums.GoodsStockTypeEnum;
|
||||
import cn.lili.modules.goods.entity.vos.GoodsSkuSpecVO;
|
||||
import cn.lili.modules.goods.entity.vos.GoodsSkuVO;
|
||||
import cn.lili.modules.goods.entity.vos.GoodsVO;
|
||||
@@ -54,12 +57,22 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -493,6 +506,116 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
|
||||
return this.page(PageUtil.initPage(searchParams), searchParams.queryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryExportStock(HttpServletResponse response, GoodsSearchParams searchParams) {
|
||||
List<GoodsSkuStockDTO> goodsSkuStockDTOList = this.baseMapper.queryStocks(searchParams.queryWrapper());
|
||||
XSSFWorkbook workbook = initStockExportData(goodsSkuStockDTOList);
|
||||
try {
|
||||
// 设置响应头
|
||||
String fileName = URLEncoder.encode("商品库存", "UTF-8");
|
||||
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
|
||||
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
workbook.write(out);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
workbook.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importStock(String storeId, MultipartFile file) {
|
||||
List<GoodsSkuStockDTO> goodsSkuStockDTOList = new ArrayList<>();
|
||||
try (InputStream inputStream = file.getInputStream()) {
|
||||
// 使用 WorkbookFactory.create 方法读取 Excel 文件
|
||||
Workbook workbook = WorkbookFactory.create(inputStream);
|
||||
// 我们只读取第一个sheet
|
||||
Sheet sheet = workbook.getSheetAt(0);
|
||||
|
||||
// 检查第一个sheet的行数是否超过10002行
|
||||
if (sheet.getPhysicalNumberOfRows() > 10002) {
|
||||
throw new ServiceException(ResultCode.GOODS_STOCK_IMPORT_ERROR, "Excel行数超过10002行");
|
||||
}
|
||||
// 遍历行和单元格
|
||||
Iterator<Row> rowIterator = sheet.rowIterator();
|
||||
int rowIndex = 0;
|
||||
while (rowIterator.hasNext()) {
|
||||
Row row = rowIterator.next();
|
||||
rowIndex++;
|
||||
|
||||
// 跳过表头
|
||||
if (rowIndex < 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Object> objects = new ArrayList<>();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
objects.add(getCellValue(row.getCell(i)));
|
||||
}
|
||||
log.error(getCellValue(row.getCell(2)));
|
||||
log.error(getCellValue(row.getCell(3)));
|
||||
// 判断数据格式
|
||||
if (!"增".equals(getCellValue(row.getCell(2))) && !"减".equals(getCellValue(row.getCell(2)))) {
|
||||
throw new ServiceException(ResultCode.GOODS_STOCK_IMPORT_ERROR, "库存修改方向列数据必须是“增”或“减”");
|
||||
} else if (!NumberUtil.isInteger(getCellValue(row.getCell(3))) || Integer.parseInt(getCellValue(row.getCell(3))) < 0) {
|
||||
throw new ServiceException(ResultCode.GOODS_STOCK_IMPORT_ERROR, "库存必须是正整数");
|
||||
} else if (this.count(new LambdaQueryWrapper<GoodsSku>()
|
||||
.eq(GoodsSku::getGoodsId, getCellValue(row.getCell(0)))
|
||||
.eq(GoodsSku::getId, getCellValue(row.getCell(1)))
|
||||
.eq(GoodsSku::getStoreId, storeId)) == 0) {
|
||||
throw new ServiceException(ResultCode.GOODS_STOCK_IMPORT_ERROR, "第" + rowIndex + "行商品不存在");
|
||||
}
|
||||
GoodsSkuStockDTO goodsSkuStockDTO = new GoodsSkuStockDTO();
|
||||
goodsSkuStockDTO.setGoodsId(getCellValue(row.getCell(0)));
|
||||
goodsSkuStockDTO.setSkuId(getCellValue(row.getCell(1)));
|
||||
goodsSkuStockDTO.setType(GoodsStockTypeEnum.fromDescription(getCellValue(row.getCell(2))).name());
|
||||
goodsSkuStockDTO.setQuantity(Integer.parseInt(getCellValue(row.getCell(3))));
|
||||
goodsSkuStockDTOList.add(goodsSkuStockDTO);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("IOException occurred while processing the Excel file.", e);
|
||||
throw new ServiceException(ResultCode.GOODS_STOCK_IMPORT_ERROR, e.getMessage());
|
||||
}
|
||||
|
||||
// 批量修改商品库存
|
||||
this.updateStocksByType(goodsSkuStockDTOList);
|
||||
}
|
||||
|
||||
private String getCellValue(Cell cell) {
|
||||
if (cell == null) {
|
||||
return "";
|
||||
}
|
||||
switch (cell.getCellType()) {
|
||||
case STRING:
|
||||
return cell.getStringCellValue();
|
||||
case NUMERIC:
|
||||
if (DateUtil.isCellDateFormatted(cell)) {
|
||||
return cell.getDateCellValue().toString();
|
||||
} else {
|
||||
// 将数值转换为整数以去掉小数点
|
||||
double numericValue = cell.getNumericCellValue();
|
||||
if (numericValue == (long) numericValue) {
|
||||
return String.valueOf((long) numericValue);
|
||||
} else {
|
||||
return String.valueOf(numericValue);
|
||||
}
|
||||
}
|
||||
case BOOLEAN:
|
||||
return String.valueOf(cell.getBooleanCellValue());
|
||||
case FORMULA:
|
||||
return cell.getCellFormula();
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IPage<GoodsSkuDTO> getGoodsSkuDTOByPage(Page<GoodsSkuDTO> page, Wrapper<GoodsSkuDTO> queryWrapper) {
|
||||
return this.baseMapper.queryByParams(page, queryWrapper);
|
||||
@@ -529,6 +652,27 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateStocksByType(List<GoodsSkuStockDTO> goodsSkuStockDTOS) {
|
||||
|
||||
// 获取所有的goodsID,并去除相同的goodsID
|
||||
List<String> goodsIds = goodsSkuStockDTOS.stream()
|
||||
.map(GoodsSkuStockDTO::getGoodsId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
//更新SKU库存
|
||||
for (GoodsSkuStockDTO goodsSkuStockDTO : goodsSkuStockDTOS) {
|
||||
this.updateStock(goodsSkuStockDTO.getSkuId(), goodsSkuStockDTO.getQuantity(), goodsSkuStockDTO.getType());
|
||||
}
|
||||
//更新SPU库存
|
||||
for (String goodsId : goodsIds) {
|
||||
goodsService.updateStock(goodsId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateAlertQuantity(GoodsSkuStockDTO goodsSkuStockDTO) {
|
||||
GoodsSku goodsSku = this.getById(goodsSkuStockDTO.getSkuId());
|
||||
@@ -559,7 +703,6 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
|
||||
this.updateBatchById(goodsSkuList);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateStock(String skuId, Integer quantity) {
|
||||
@@ -591,6 +734,45 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateStock(String skuId, Integer quantity, String type) {
|
||||
GoodsSku goodsSku = getGoodsSkuByIdFromCache(skuId);
|
||||
if (goodsSku != null) {
|
||||
|
||||
//计算修改库存
|
||||
if (type.equals(GoodsStockTypeEnum.ADD.name())) {
|
||||
quantity = Convert.toInt(NumberUtil.add(goodsSku.getQuantity(), quantity));
|
||||
} else {
|
||||
quantity = Convert.toInt(NumberUtil.sub(goodsSku.getQuantity(), quantity));
|
||||
}
|
||||
goodsSku.setQuantity(quantity);
|
||||
|
||||
//判断商品sku是否已经下架(修改商品库存为0时 会自动下架商品),再次更新商品库存时 需更新商品索引
|
||||
boolean isFlag = goodsSku.getQuantity() <= 0;
|
||||
|
||||
boolean update = this.update(new LambdaUpdateWrapper<GoodsSku>().eq(GoodsSku::getId, skuId).set(GoodsSku::getQuantity, quantity));
|
||||
if (update) {
|
||||
cache.remove(CachePrefix.GOODS.getPrefix() + goodsSku.getGoodsId());
|
||||
}
|
||||
cache.put(GoodsSkuService.getCacheKeys(skuId), goodsSku);
|
||||
cache.put(GoodsSkuService.getStockCacheKey(skuId), quantity);
|
||||
|
||||
this.promotionGoodsService.updatePromotionGoodsStock(goodsSku.getId(), quantity);
|
||||
//商品库存为0是删除商品索引
|
||||
if (quantity <= 0) {
|
||||
goodsIndexService.deleteIndexById(goodsSku.getId());
|
||||
}
|
||||
//商品SKU库存为0并且商品sku状态为上架时更新商品库存
|
||||
if (isFlag && CharSequenceUtil.equals(goodsSku.getMarketEnable(), GoodsStatusEnum.UPPER.name())) {
|
||||
List<String> goodsIds = new ArrayList<>();
|
||||
goodsIds.add(goodsSku.getGoodsId());
|
||||
applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("更新商品", rocketmqCustomProperties.getGoodsTopic(),
|
||||
GoodsTagsEnum.UPDATE_GOODS_INDEX.name(), goodsIds));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getStock(String skuId) {
|
||||
String cacheKeys = GoodsSkuService.getStockCacheKey(skuId);
|
||||
@@ -707,6 +889,17 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean freight(List<String> goodsId, String templateId) {
|
||||
LambdaUpdateWrapper<GoodsSku> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.in(GoodsSku::getGoodsId, goodsId);
|
||||
updateWrapper.set(GoodsSku::getFreightTemplateId, templateId);
|
||||
updateWrapper.set(GoodsSku::getUpdateTime, new Date());
|
||||
List<String> skuIds = this.list(updateWrapper).stream().map(GoodsSku::getId).collect(Collectors.toList());
|
||||
skuIds.forEach(this::clearCache);
|
||||
return this.update(updateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染商品sku
|
||||
*
|
||||
@@ -743,6 +936,9 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
|
||||
* @param goodsSku sku
|
||||
*/
|
||||
void renderImages(GoodsSku goodsSku, List<String> goodsImages) {
|
||||
if (goodsImages == null || goodsImages.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
JSONObject jsonObject = JSONUtil.parseObj(goodsSku.getSpecs());
|
||||
List<String> images = jsonObject.getBeanList("images", String.class);
|
||||
GoodsGallery goodsGallery;
|
||||
@@ -777,4 +973,151 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
|
||||
return skuSpecVOList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化填充商品库存导出数据
|
||||
*
|
||||
* @param goodsSkuStockDTOList 导出的库存数据
|
||||
* @return 商品库存导出列表
|
||||
*/
|
||||
private XSSFWorkbook initStockExportData(List<GoodsSkuStockDTO> goodsSkuStockDTOList) {
|
||||
|
||||
XSSFWorkbook workbook = new XSSFWorkbook();
|
||||
// 创建模板
|
||||
this.createTemplate(workbook);
|
||||
// 创建sku库存列表
|
||||
this.skuStockList(workbook, goodsSkuStockDTOList);
|
||||
// 创建sku库存列表
|
||||
this.skuList(workbook, goodsSkuStockDTOList);
|
||||
return workbook;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建模板
|
||||
*
|
||||
* @param workbook
|
||||
*/
|
||||
private void createTemplate(XSSFWorkbook workbook) {
|
||||
Sheet templateSheet = workbook.createSheet("商品库存编辑模板");
|
||||
|
||||
// 创建表头
|
||||
Row description = templateSheet.createRow(0);
|
||||
description.setHeightInPoints(90);
|
||||
Cell descriptionCell = description.createCell(0);
|
||||
descriptionCell.setCellValue("填写说明(请勿删除本说明):\n" +
|
||||
"1.可批量设置多个商品的库存,一次最多10000行\n" +
|
||||
"2.库存修改方向:选择库存方向后,会在原先库存基础上进行增加或者减少\n" +
|
||||
"3.库存变更数量:需要为整数,不能填写0和负数");
|
||||
// 合并描述行的单元格
|
||||
templateSheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));
|
||||
|
||||
// 设置描述行单元格样式(例如,自动换行)
|
||||
CellStyle descriptionStyle = workbook.createCellStyle();
|
||||
descriptionStyle.setWrapText(true);
|
||||
descriptionStyle.setAlignment(HorizontalAlignment.LEFT);
|
||||
descriptionStyle.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
descriptionCell.setCellStyle(descriptionStyle);
|
||||
|
||||
// 创建表头
|
||||
Row header = templateSheet.createRow(1);
|
||||
|
||||
String[] headers = {"商品ID(必填)", "skuID(必填)", "库存修改方向(必填,填 增 或者 减)", "库存变更数量(必填)"};
|
||||
|
||||
CellStyle headerStyle = workbook.createCellStyle();
|
||||
Font headerFont = workbook.createFont();
|
||||
headerFont.setBold(true);
|
||||
headerStyle.setFont(headerFont);
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
Cell cell = header.createCell(i);
|
||||
cell.setCellValue(headers[i]);
|
||||
cell.setCellStyle(headerStyle);
|
||||
}
|
||||
//修改列宽
|
||||
templateSheet.setColumnWidth(0, 30 * 256);
|
||||
templateSheet.setColumnWidth(1, 30 * 256);
|
||||
templateSheet.setColumnWidth(2, 40 * 256);
|
||||
templateSheet.setColumnWidth(3, 25 * 256);
|
||||
|
||||
// 设置下拉列表数据验证
|
||||
DataValidationHelper validationHelper = templateSheet.getDataValidationHelper();
|
||||
DataValidationConstraint constraint = validationHelper.createExplicitListConstraint(new String[]{"增", "减"});
|
||||
// 从第3行到第10002行,第3列
|
||||
CellRangeAddressList addressList = new CellRangeAddressList(2, 10001, 2, 2);
|
||||
DataValidation validation = validationHelper.createValidation(constraint, addressList);
|
||||
validation.setSuppressDropDownArrow(true);
|
||||
validation.setShowErrorBox(true);
|
||||
templateSheet.addValidationData(validation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建sku库存列表
|
||||
*
|
||||
* @param workbook
|
||||
*/
|
||||
private void skuStockList(XSSFWorkbook workbook, List<GoodsSkuStockDTO> goodsSkuStockDTOList) {
|
||||
Sheet skuListSheet = workbook.createSheet("商品库存信息");
|
||||
|
||||
// 创建表头
|
||||
Row header = skuListSheet.createRow(0);
|
||||
|
||||
String[] headers = {"商品ID", "商品名称", "规格ID(SKUID)", "规格名称", "货号", "当前库存数量"};
|
||||
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
Cell cell = header.createCell(i);
|
||||
cell.setCellValue(headers[i]);
|
||||
}
|
||||
|
||||
|
||||
// 填充数据
|
||||
for (int i = 0; i < goodsSkuStockDTOList.size(); i++) {
|
||||
GoodsSkuStockDTO dto = goodsSkuStockDTOList.get(i);
|
||||
Row row = skuListSheet.createRow(i + 1);
|
||||
row.createCell(0).setCellValue(dto.getGoodsId());
|
||||
row.createCell(1).setCellValue(dto.getGoodsName());
|
||||
row.createCell(2).setCellValue(dto.getSkuId());
|
||||
row.createCell(3).setCellValue(dto.getSimpleSpecs());
|
||||
row.createCell(4).setCellValue(dto.getSn());
|
||||
row.createCell(5).setCellValue(dto.getQuantity());
|
||||
}
|
||||
|
||||
//修改列宽
|
||||
skuListSheet.setColumnWidth(0, 30 * 256);
|
||||
skuListSheet.setColumnWidth(1, 30 * 256);
|
||||
skuListSheet.setColumnWidth(2, 30 * 256);
|
||||
skuListSheet.setColumnWidth(3, 30 * 256);
|
||||
skuListSheet.setColumnWidth(4, 30 * 256);
|
||||
skuListSheet.setColumnWidth(5, 15 * 256);
|
||||
}
|
||||
|
||||
private void skuList(XSSFWorkbook workbook, List<GoodsSkuStockDTO> goodsSkuStockDTOList) {
|
||||
Sheet skuListSheet = workbook.createSheet("商品规格");
|
||||
|
||||
// 创建表头
|
||||
Row header = skuListSheet.createRow(0);
|
||||
|
||||
String[] headers = {"商品ID", "商品名称", "规格ID(SKUID)", "规格名称", "货号"};
|
||||
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
Cell cell = header.createCell(i);
|
||||
cell.setCellValue(headers[i]);
|
||||
}
|
||||
|
||||
// 填充数据
|
||||
for (int i = 0; i < goodsSkuStockDTOList.size(); i++) {
|
||||
GoodsSkuStockDTO dto = goodsSkuStockDTOList.get(i);
|
||||
Row row = skuListSheet.createRow(i + 1);
|
||||
row.createCell(0).setCellValue(dto.getGoodsId());
|
||||
row.createCell(1).setCellValue(dto.getGoodsName());
|
||||
row.createCell(2).setCellValue(dto.getSkuId());
|
||||
row.createCell(3).setCellValue(dto.getSimpleSpecs());
|
||||
row.createCell(4).setCellValue(dto.getSn());
|
||||
}
|
||||
|
||||
//修改列宽
|
||||
skuListSheet.setColumnWidth(0, 30 * 256);
|
||||
skuListSheet.setColumnWidth(1, 30 * 256);
|
||||
skuListSheet.setColumnWidth(2, 30 * 256);
|
||||
skuListSheet.setColumnWidth(3, 30 * 256);
|
||||
skuListSheet.setColumnWidth(4, 30 * 256);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class ImTalkServiceImpl extends ServiceImpl<ImTalkMapper, ImTalk> impleme
|
||||
|
||||
@Autowired
|
||||
private ImMessageService imMessageService;
|
||||
|
||||
@Override
|
||||
public ImTalk getTalkByUser(String userId) {
|
||||
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
||||
AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser());
|
||||
|
||||
@@ -131,50 +131,67 @@ public class KdniaoPlugin implements LogisticsPlugin {
|
||||
StoreLogistics storeLogistics = labelOrderDTO.getStoreLogistics();
|
||||
|
||||
//组装快递鸟应用级参数
|
||||
String resultDate = "{" +
|
||||
"'OrderCode': '" + order.getSn() + "'," + //订单编码
|
||||
"'ShipperCode': '" + logistics.getCode() + "'," + //快递公司编码
|
||||
"'CustomerName': '" + storeLogistics.getCustomerName() + "'," +//客户编码
|
||||
"'CustomerPwd': '" + storeLogistics.getCustomerPwd() + "'," + //客户密码
|
||||
"'MonthCode': '" + storeLogistics.getMonthCode() + "'," + //密钥
|
||||
"'SendSite': '" + storeLogistics.getSendSite() + "'," + //归属网点
|
||||
"'SendStaff': '" + storeLogistics.getSendStaff() + "'," + //收件快递员
|
||||
"'PayType': " + storeLogistics.getPayType() + "," +
|
||||
"'ExpType': " + storeLogistics.getExpType() + "," +
|
||||
//发件人信息
|
||||
"'Sender': {" +
|
||||
"'Name': '" + storeDeliverGoodsAddressDTO.getSalesConsignorName() + "'," +
|
||||
"'Mobile': '" + storeDeliverGoodsAddressDTO.getSalesConsignorMobile() + "'," +
|
||||
"'ProvinceName': '" + consignorAddress[0] + "'," + //省
|
||||
"'CityName': '" + consignorAddress[1] + "'," + //市
|
||||
"'ExpAreaName': '" + consignorAddress[2] + "'," + //区
|
||||
"'Address': '" + storeDeliverGoodsAddressDTO.getSalesConsignorDetail() + "'" + //发件人详细地址
|
||||
"}," +
|
||||
//收件人信息
|
||||
"'Receiver': {" +
|
||||
"'Name': '" + order.getConsigneeName() + "'," +
|
||||
"'Mobile': '" + order.getConsigneeMobile() + "'," +
|
||||
"'ProvinceName': '" + ConsigneeAddress[0] + "'," + //省
|
||||
"'CityName': '" + ConsigneeAddress[1] + "'," + //市
|
||||
"'ExpAreaName': '" + ConsigneeAddress[2] + "'," + //区
|
||||
"'Address': '" + order.getConsigneeDetail() + "'" + //收件人详细地址
|
||||
"}," +
|
||||
//商品信息
|
||||
"'Commodity': [";
|
||||
String resultDate = "{"
|
||||
// 订单编码
|
||||
+ "'OrderCode': '" + order.getSn() + "',"
|
||||
// 快递公司编码
|
||||
+ "'ShipperCode': '" + logistics.getCode() + "',"
|
||||
// 客户编码
|
||||
+ "'CustomerName': '" + storeLogistics.getCustomerName() + "',"
|
||||
// 客户密码
|
||||
+ "'CustomerPwd': '" + storeLogistics.getCustomerPwd() + "',"
|
||||
// 密钥
|
||||
+ "'MonthCode': '" + storeLogistics.getMonthCode() + "',"
|
||||
// 归属网点
|
||||
+ "'SendSite': '" + storeLogistics.getSendSite() + "',"
|
||||
// 收件快递员
|
||||
+ "'SendStaff': '" + storeLogistics.getSendStaff() + "',"
|
||||
+ "'PayType': " + storeLogistics.getPayType() + ","
|
||||
+ "'ExpType': " + storeLogistics.getExpType() + ","
|
||||
// 发件人信息
|
||||
+ "'Sender': {"
|
||||
+ "'Name': '" + storeDeliverGoodsAddressDTO.getSalesConsignorName() + "',"
|
||||
+ "'Mobile': '" + storeDeliverGoodsAddressDTO.getSalesConsignorMobile() + "',"
|
||||
// 省
|
||||
+ "'ProvinceName': '" + consignorAddress[0] + "',"
|
||||
// 市
|
||||
+ "'CityName': '" + consignorAddress[1] + "',"
|
||||
// 区
|
||||
+ "'ExpAreaName': '" + consignorAddress[2] + "',"
|
||||
// 发件人详细地址
|
||||
+ "'Address': '" + storeDeliverGoodsAddressDTO.getSalesConsignorDetail() + "'"
|
||||
+ "},"
|
||||
// 收件人信息
|
||||
+ "'Receiver': {"
|
||||
+ "'Name': '" + order.getConsigneeName() + "',"
|
||||
+ "'Mobile': '" + order.getConsigneeMobile() + "',"
|
||||
// 省
|
||||
+ "'ProvinceName': '" + ConsigneeAddress[0] + "',"
|
||||
// 市
|
||||
+ "'CityName': '" + ConsigneeAddress[1] + "',"
|
||||
// 区
|
||||
+ "'ExpAreaName': '" + ConsigneeAddress[2] + "',"
|
||||
// 收件人详细地址
|
||||
+ "'Address': '" + order.getConsigneeDetail() + "'"
|
||||
+ "},"
|
||||
// 商品信息
|
||||
+ "'Commodity': [";
|
||||
|
||||
//子订单信息
|
||||
for (OrderItem orderItem : orderItems) {
|
||||
resultDate = resultDate + "{" +
|
||||
"'GoodsName': '" + orderItem.getGoodsName() + "'," +
|
||||
"'Goodsquantity': '" + orderItem.getNum() + "'" +
|
||||
"},";
|
||||
resultDate = resultDate + "{"
|
||||
+ "'GoodsName': '" + orderItem.getGoodsName() + "',"
|
||||
+ "'Goodsquantity': '" + orderItem.getNum() + "'"
|
||||
+ "},";
|
||||
}
|
||||
resultDate = resultDate + "]," +
|
||||
"'Quantity': " + orderItems.size() + "," + //包裹数
|
||||
"'IsReturnPrintTemplate':1," + //生成电子面单模板
|
||||
"'Remark': '" + order.getRemark() + "'" +//商家备注
|
||||
"}";
|
||||
|
||||
resultDate = resultDate + "],"
|
||||
// 包裹数
|
||||
+ "'Quantity': " + orderItems.size() + ","
|
||||
// 生成电子面单模板
|
||||
+ "'IsReturnPrintTemplate':1,"
|
||||
// 商家备注
|
||||
+ "'Remark': '" + order.getRemark() + "'"
|
||||
+ "}";
|
||||
|
||||
//组织系统级参数
|
||||
Map<String, String> params = new HashMap<>();
|
||||
@@ -200,9 +217,9 @@ public class KdniaoPlugin implements LogisticsPlugin {
|
||||
JSONObject obj = JSONObject.parseObject(result);
|
||||
log.info("电子面单响应:{}", result);
|
||||
if (!"100".equals(obj.getString("ResultCode"))) {
|
||||
// resultMap.put("Reason",obj.getString("Reason"));
|
||||
// resultMap.put("Reason",obj.getString("Reason"));
|
||||
throw new ServiceException(obj.getString("Reason"));
|
||||
// return resultMap;
|
||||
// return resultMap;
|
||||
}
|
||||
|
||||
JSONObject orderJson = JSONObject.parseObject(obj.getString("Order"));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.lili.modules.logistics.plugin.kuaidi100;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.lili.modules.logistics.LogisticsPlugin;
|
||||
import cn.lili.modules.logistics.entity.dto.LabelOrderDTO;
|
||||
import cn.lili.modules.logistics.entity.enums.LogisticsEnum;
|
||||
@@ -28,6 +29,7 @@ import com.kuaidi100.sdk.request.labelV2.OrderReq;
|
||||
import com.kuaidi100.sdk.response.QueryTrackData;
|
||||
import com.kuaidi100.sdk.response.QueryTrackMapResp;
|
||||
import com.kuaidi100.sdk.response.QueryTrackResp;
|
||||
import com.kuaidi100.sdk.response.labelV2.OrderResult;
|
||||
import com.kuaidi100.sdk.response.samecity.OrderResp;
|
||||
import com.kuaidi100.sdk.utils.SignUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -140,25 +142,74 @@ public class Kuaidi100Plugin implements LogisticsPlugin {
|
||||
StoreLogistics storeLogistics = labelOrderDTO.getStoreLogistics();
|
||||
|
||||
|
||||
ManInfo recManInfo = new ManInfo();
|
||||
recManInfo.setName(order.getConsigneeName());
|
||||
recManInfo.setMobile(order.getConsigneeMobile());
|
||||
recManInfo.setPrintAddr(consigneeAddress[0] + consigneeAddress[1] + consigneeAddress[2] + consigneeAddress[3] + order.getConsigneeDetail());
|
||||
|
||||
ManInfo sendManInfo = new ManInfo();
|
||||
sendManInfo.setName(storeDeliverGoodsAddressDTO.getSalesConsignorName());
|
||||
sendManInfo.setMobile(storeDeliverGoodsAddressDTO.getSalesConsignorMobile());
|
||||
sendManInfo.setPrintAddr(consignorAddress[0] + consignorAddress[1] + consignorAddress[2] + consignorAddress[3] + storeDeliverGoodsAddressDTO.getSalesConsignorDetail());
|
||||
|
||||
OrderReq orderReq = new OrderReq();
|
||||
//打印类型,NON:只下单不打印(默认); IMAGE:生成图片短链;HTML:生成html短链; CLOUD:使用快递100云打印机打印,使用CLOUD时siid必填
|
||||
orderReq.setPrintType(PrintType.HTML);
|
||||
//电子面单客户账户或月结账号,需贵司向当地快递公司网点申请(参考电子面单申请指南); 是否必填该属性,请查看参数字典
|
||||
orderReq.setPartnerId(storeLogistics.getCustomerName());
|
||||
//电子面单密码,需贵司向当地快递公司网点申请; 是否必填该属性,请查看参数字典
|
||||
if(CharSequenceUtil.isNotEmpty(storeLogistics.getCustomerPwd())){
|
||||
orderReq.setPartnerKey(storeLogistics.getCustomerPwd());
|
||||
}
|
||||
|
||||
//电子面单密钥,需贵司向当地快递公司网点申请; 是否必填该属性,请查看参数字典
|
||||
if(CharSequenceUtil.isNotEmpty(storeLogistics.getMonthCode())) {
|
||||
orderReq.setPartnerSecret(storeLogistics.getMonthCode());
|
||||
}
|
||||
//电子面单客户账户名称,需贵司向当地快递公司网点申请; 是否必填该属性,请查看参数字典
|
||||
if(CharSequenceUtil.isNotEmpty(storeLogistics.getPartnerName())) {
|
||||
orderReq.setPartnerName(storeLogistics.getPartnerName());
|
||||
}
|
||||
// orderReq.setNet();
|
||||
// 电子面单承载编号,需贵司向当地快递公司网点申请; 是否必填该属性,请查看参数字典
|
||||
if(CharSequenceUtil.isNotEmpty(storeLogistics.getSendSite())) {
|
||||
orderReq.setCode(storeLogistics.getSendSite());
|
||||
}
|
||||
//电子面单承载快递员名,需贵司向当地快递公司网点申请; 是否必填该属性,请查看参数字典
|
||||
if(CharSequenceUtil.isNotEmpty(storeLogistics.getSendStaff())) {
|
||||
orderReq.setCheckMan(storeLogistics.getSendStaff());
|
||||
}
|
||||
|
||||
//快递公司的编码,一律用小写字母,请查看参数字典
|
||||
orderReq.setKuaidicom(logistics.getCode());
|
||||
orderReq.setCount(1);
|
||||
//收件人信息
|
||||
ManInfo manInfo=new ManInfo();
|
||||
//收件人姓名
|
||||
manInfo.setName(order.getConsigneeName());
|
||||
//收件人的手机号,手机号和电话号二者其一必填
|
||||
manInfo.setMobile(order.getConsigneeMobile());
|
||||
//收件人的电话号,手机号和电话号二者其一必填
|
||||
// manInfo.setTel("");
|
||||
//收件人所在完整地址,如广东深圳市南山区科技南十二路金蝶软件园B10
|
||||
manInfo.setPrintAddr(consigneeAddress[0]+consigneeAddress[1]+consigneeAddress[2]+consigneeAddress[3]+order.getConsigneeDetail());
|
||||
orderReq.setRecMan(manInfo);
|
||||
ManInfo sendMan=new ManInfo();
|
||||
// 寄件人信息
|
||||
sendMan.setName(storeDeliverGoodsAddressDTO.getSalesConsignorName());
|
||||
// 寄件人的手机号,手机号和电话号二者其一必填
|
||||
sendMan.setMobile(storeDeliverGoodsAddressDTO.getSalesConsignorMobile());
|
||||
//寄件人的电话号,手机号和电话号二者其一必填
|
||||
// sendMan.setTel("");
|
||||
//寄件人所在的完整地址,如广东深圳市南山区科技南十二路金蝶软件园B10
|
||||
sendMan.setPrintAddr(consignorAddress[0]+consignorAddress[1]+consignorAddress[2]+consignorAddress[3]+storeDeliverGoodsAddressDTO.getSalesConsignorDetail());
|
||||
//寄件人所在公司名称
|
||||
// sendMan.setCompany("");
|
||||
orderReq.setSendMan(sendMan);
|
||||
//物品名称,例:文件
|
||||
String goodsName="";
|
||||
for (OrderItem orderItem : orderItems) {
|
||||
goodsName+=orderItem.getGoodsName() + "',";
|
||||
}
|
||||
|
||||
orderReq.setCargo(goodsName);
|
||||
// 包裹总数量。
|
||||
orderReq.setCount(orderItems.size());
|
||||
//打印设备,通过打印机输出的设备码进行获取,printType为CLOUD时必填
|
||||
// orderReq.setSiid("");
|
||||
|
||||
// orderReq.setSiid(siid);
|
||||
//orderReq.setTempId("60f6c17c7c223700131d8bc3");
|
||||
orderReq.setSendMan(sendManInfo);
|
||||
orderReq.setRecMan(recManInfo);
|
||||
|
||||
orderReq.setPrintType(PrintType.CLOUD);
|
||||
|
||||
String param = new Gson().toJson(orderReq);
|
||||
String t = System.currentTimeMillis() + "";
|
||||
@@ -167,14 +218,19 @@ public class Kuaidi100Plugin implements LogisticsPlugin {
|
||||
printReq.setT(t);
|
||||
printReq.setKey(logisticsSetting.getKuaidi100Key());
|
||||
printReq.setSign(SignUtils.printSign(param, t, logisticsSetting.getKuaidi100Key(), logisticsSetting.getKuaidi100Customer()));
|
||||
printReq.setMethod(ApiInfoConstant.ORDER);
|
||||
printReq.setMethod(ApiInfoConstant.NEW_TEMPLATE_URL);
|
||||
printReq.setParam(param);
|
||||
|
||||
IBaseClient baseClient = new LabelV2();
|
||||
HttpResult result = baseClient.execute(printReq);
|
||||
System.out.println(result.getBody());
|
||||
QueryTrackMapResp queryTrackMapResp = new Gson().fromJson(result.getBody(), QueryTrackMapResp.class);
|
||||
OrderResp orderResp = new Gson().fromJson(result.getBody(), OrderResp.class);
|
||||
|
||||
|
||||
|
||||
OrderResult orderResult = new Gson().fromJson(result.getBody(), OrderResult.class);
|
||||
log.info("电子面单响应:{}", orderResult);
|
||||
System.out.println("快递单号:"+orderResult.getKdComOrderNum());
|
||||
System.out.println("面单短链:"+orderResult.getLabel());
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -22,13 +22,13 @@ import com.sf.csim.express.service.HttpClientUtil;
|
||||
import com.sf.csim.express.service.IServiceCodeStandard;
|
||||
import com.sf.csim.express.service.code.ExpressServiceCodeEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 顺丰插件
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
@Slf4j
|
||||
@@ -43,7 +43,8 @@ public class ShunfengPlugin implements LogisticsPlugin {
|
||||
**/
|
||||
private LogisticsSetting logisticsSetting;
|
||||
|
||||
public ShunfengPlugin(){}
|
||||
public ShunfengPlugin() {
|
||||
}
|
||||
|
||||
public ShunfengPlugin(LogisticsSetting logisticsSetting) {
|
||||
this.logisticsSetting = logisticsSetting;
|
||||
@@ -59,10 +60,11 @@ public class ShunfengPlugin implements LogisticsPlugin {
|
||||
*
|
||||
* @param orderDetailVO
|
||||
*/
|
||||
@Override
|
||||
public String createOrder(OrderDetailVO orderDetailVO) {
|
||||
StoreDetailService storeService = SpringContextUtil.getBean(StoreDetailService.class);
|
||||
StoreDeliverGoodsAddressDTO storeDeliverGoodsAddressDTO = storeService.getStoreDeliverGoodsAddressDto(orderDetailVO.getOrder().getStoreId());
|
||||
if(storeDeliverGoodsAddressDTO == null){
|
||||
if (storeDeliverGoodsAddressDTO == null) {
|
||||
throw new ServiceException(ResultCode.STORE_DELIVER_ADDRESS_EXIST);
|
||||
}
|
||||
try {
|
||||
@@ -108,7 +110,7 @@ public class ShunfengPlugin implements LogisticsPlugin {
|
||||
|
||||
String result = sendPost(ExpressServiceCodeEnum.EXP_RECE_CREATE_ORDER, msgDataMap);
|
||||
JSONObject resultData = JSONUtil.parseObj(result).getJSONObject("apiResultData");
|
||||
if(Boolean.TRUE.toString().equals(resultData.get("success").toString())){
|
||||
if (Boolean.TRUE.toString().equals(resultData.get("success").toString())) {
|
||||
return resultData.getJSONObject("msgData").getJSONArray("waybillNoInfoList").getJSONObject(0).get("waybillNo").toString();
|
||||
}
|
||||
throw new ServiceException(resultData.get("errorMsg").toString());
|
||||
@@ -141,10 +143,10 @@ public class ShunfengPlugin implements LogisticsPlugin {
|
||||
msgDataMap.put("trackingNumber", trackingNumber);
|
||||
JSONObject result = JSONUtil.parseObj(sendPost(ExpressServiceCodeEnum.EXP_RECE_SEARCH_ROUTES, msgDataMap));
|
||||
JSONObject resultData = result.getJSONObject("apiResultData");
|
||||
if(Boolean.TRUE.toString().equals(resultData.get("success").toString())){
|
||||
if (Boolean.TRUE.toString().equals(resultData.get("success").toString())) {
|
||||
JSONArray routesJson = resultData.getJSONObject("msgData").getJSONArray("routeResps").getJSONObject(0).getJSONArray("routes");
|
||||
List<Map> routes = routesJson.toList(Map.class);
|
||||
return new Traces(logistics.getName(),expNo,routes);
|
||||
return new Traces(logistics.getName(), expNo, routes);
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -164,7 +166,7 @@ public class ShunfengPlugin implements LogisticsPlugin {
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Map<String,Object> labelOrder(LabelOrderDTO labelOrderDTO) {
|
||||
public Map<String, Object> labelOrder(LabelOrderDTO labelOrderDTO) {
|
||||
try {
|
||||
Map<String, Object> msgDataMap = new HashMap<>();
|
||||
//模板编码
|
||||
@@ -173,15 +175,15 @@ public class ShunfengPlugin implements LogisticsPlugin {
|
||||
//业务数据
|
||||
Map<String, Object> documents = new HashMap<>();
|
||||
documents.put("masterWaybillNo", labelOrderDTO.getOrder().getLogisticsNo());
|
||||
msgDataMap.put("documents",documents);
|
||||
msgDataMap.put("sync",true);
|
||||
msgDataMap.put("documents", documents);
|
||||
msgDataMap.put("sync", true);
|
||||
/**
|
||||
* 版本号,传固定值:2.0
|
||||
*/
|
||||
msgDataMap.put("version", "2.0");
|
||||
JSONObject result = JSONUtil.parseObj(sendPost(ExpressServiceCodeEnum.COM_RECE_CLOUD_PRINT_WAYBILLS, msgDataMap));
|
||||
JSONObject resultData = result.getJSONObject("apiResultData");
|
||||
if(Boolean.TRUE.toString().equals(resultData.get("success").toString())){
|
||||
if (Boolean.TRUE.toString().equals(resultData.get("success").toString())) {
|
||||
return resultData.getJSONObject("obj").getJSONArray("files").toList(Map.class).get(0);
|
||||
}
|
||||
throw new ServiceException(resultData.getJSONArray("errorMessage").get(0).toString());
|
||||
@@ -204,13 +206,13 @@ public class ShunfengPlugin implements LogisticsPlugin {
|
||||
//校验类型 1,电话号码校验 2,月结卡号校验
|
||||
msgDataMap.put("checkType", 1);
|
||||
//校验值 当校验类型为1时传电话号码 当校验类型为2时传月结卡号
|
||||
List<String> mobileList= new ArrayList<>();
|
||||
List<String> mobileList = new ArrayList<>();
|
||||
mobileList.add(checkNos);
|
||||
msgDataMap.put("checkNos", mobileList);
|
||||
JSONObject result = JSONUtil.parseObj(sendPost(ExpressServiceCodeEnum.EXP_RECE_SEARCH_PROMITM, msgDataMap));
|
||||
JSONObject resultData = result.getJSONObject("apiResultData");
|
||||
if(Boolean.TRUE.toString().equals(resultData.get("success").toString())){
|
||||
return resultData.getJSONObject("msgData").get("promiseTm").toString();
|
||||
if (Boolean.TRUE.toString().equals(resultData.get("success").toString())) {
|
||||
return resultData.getJSONObject("msgData").get("promiseTm").toString();
|
||||
}
|
||||
throw new ServiceException(resultData.get("errorMsg").toString());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
@@ -219,7 +221,6 @@ public class ShunfengPlugin implements LogisticsPlugin {
|
||||
}
|
||||
|
||||
private String sendPost(IServiceCodeStandard standardService, Map<String, Object> msgDataMap) throws UnsupportedEncodingException {
|
||||
CallExpressServiceTools tools = CallExpressServiceTools.getInstance();
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
String timeStamp = String.valueOf(System.currentTimeMillis());
|
||||
// 顾客编码
|
||||
@@ -230,7 +231,7 @@ public class ShunfengPlugin implements LogisticsPlugin {
|
||||
params.put("timestamp", timeStamp);
|
||||
params.put("msgData", JSONUtil.toJsonStr(msgDataMap));
|
||||
|
||||
params.put("msgDigest", tools.getMsgDigest(params.get("msgData"), timeStamp, logisticsSetting.getCheckWord()));
|
||||
params.put("msgDigest", CallExpressServiceTools.getMsgDigest(params.get("msgData"), timeStamp, logisticsSetting.getCheckWord()));
|
||||
String result = HttpClientUtil.post(logisticsSetting.getCallUrl(), params);
|
||||
|
||||
log.info("===调用地址 ===" + logisticsSetting.getCallUrl());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.lili.modules.member.entity.dos;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.lili.modules.member.entity.dto.ClerkAddDTO;
|
||||
import cn.lili.modules.store.entity.dos.Store;
|
||||
@@ -59,7 +60,7 @@ public class Clerk extends BaseEntity {
|
||||
* @param clerkAddDTO
|
||||
*/
|
||||
public Clerk(ClerkAddDTO clerkAddDTO) {
|
||||
if (clerkAddDTO.getRoles()!=null && !clerkAddDTO.getRoles().isEmpty()) {
|
||||
if (CollUtil.isNotEmpty(clerkAddDTO.getRoles()) && !clerkAddDTO.getRoles().isEmpty()) {
|
||||
this.roleIds = CharSequenceUtil.join(",", clerkAddDTO.getRoles());
|
||||
}
|
||||
this.memberId = clerkAddDTO.getMemberId();
|
||||
|
||||
@@ -24,13 +24,16 @@ public class MemberGrade extends BaseEntity {
|
||||
private String gradeName;
|
||||
|
||||
@NotNull
|
||||
@ApiModelProperty(value = "等级图片")
|
||||
@ApiModelProperty(value = "等级图片 1029*498")
|
||||
private String gradeImage;
|
||||
|
||||
@NotNull
|
||||
@ApiModelProperty(value = "所需经验值")
|
||||
private Integer experienceValue;
|
||||
@ApiModelProperty(value = "会员等级")
|
||||
private Integer level;
|
||||
|
||||
@ApiModelProperty(value = "是否为默认等级")
|
||||
private Boolean isDefault;
|
||||
@ApiModelProperty(value = "累计实付")
|
||||
private Double payPrice;
|
||||
|
||||
@ApiModelProperty(value = "累计购买次数")
|
||||
private Integer count;
|
||||
}
|
||||
|
||||
@@ -135,10 +135,9 @@ public interface MemberService extends IService<Member> {
|
||||
/**
|
||||
* 注销账号
|
||||
*
|
||||
* @param password 密码
|
||||
* @return 操作结果
|
||||
*/
|
||||
void cancellation(String password);
|
||||
void cancellation();
|
||||
/**
|
||||
* 修改当前会员的手机号
|
||||
*
|
||||
|
||||
@@ -102,8 +102,18 @@ public class MemberEvaluationServiceImpl extends ServiceImpl<MemberEvaluationMap
|
||||
public MemberEvaluationDTO addMemberEvaluation(MemberEvaluationDTO memberEvaluationDTO, Boolean isSelf) {
|
||||
//获取子订单信息
|
||||
OrderItem orderItem = orderItemService.getBySn(memberEvaluationDTO.getOrderItemSn());
|
||||
|
||||
if (orderItem == null) {
|
||||
throw new ServiceException(ResultCode.ORDER_ITEM_NOT_EXIST);
|
||||
}
|
||||
|
||||
//获取订单信息
|
||||
Order order = orderService.getBySn(orderItem.getOrderSn());
|
||||
|
||||
if (order == null) {
|
||||
throw new ServiceException(ResultCode.ORDER_NOT_EXIST);
|
||||
}
|
||||
|
||||
//检测是否可以添加会员评价
|
||||
Member member;
|
||||
|
||||
@@ -119,8 +129,14 @@ public class MemberEvaluationServiceImpl extends ServiceImpl<MemberEvaluationMap
|
||||
throw new ServiceException(ResultCode.USER_NOT_EXIST);
|
||||
}
|
||||
}
|
||||
|
||||
//获取商品信息
|
||||
GoodsSku goodsSku = goodsSkuService.getGoodsSkuByIdFromCache(memberEvaluationDTO.getSkuId());
|
||||
|
||||
if (goodsSku == null) {
|
||||
throw new ServiceException(ResultCode.GOODS_NOT_EXIST);
|
||||
}
|
||||
|
||||
//新增用户评价
|
||||
MemberEvaluation memberEvaluation = new MemberEvaluation(memberEvaluationDTO, goodsSku, member, order);
|
||||
//过滤商品咨询敏感词
|
||||
|
||||
@@ -118,7 +118,11 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
||||
public Member getUserInfo() {
|
||||
AuthUser tokenUser = UserContext.getCurrentUser();
|
||||
if (tokenUser != null) {
|
||||
return this.findByUsername(tokenUser.getUsername());
|
||||
Member member = this.findByUsername(tokenUser.getUsername());
|
||||
if(member != null && !member.getDisabled()){
|
||||
throw new ServiceException(ResultCode.USER_STATUS_ERROR);
|
||||
}
|
||||
return member;
|
||||
}
|
||||
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||
}
|
||||
@@ -233,7 +237,7 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
||||
private Member findMember(String userName) {
|
||||
QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("username", userName).or().eq("mobile", userName);
|
||||
return this.getOne(queryWrapper);
|
||||
return this.getOne(queryWrapper, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -286,12 +290,16 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
||||
public Token mobilePhoneLogin(String mobilePhone) {
|
||||
QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("mobile", mobilePhone);
|
||||
Member member = this.baseMapper.selectOne(queryWrapper);
|
||||
Member member = this.baseMapper.selectOne(queryWrapper, false);
|
||||
//如果手机号不存在则自动注册用户
|
||||
if (member == null) {
|
||||
member = new Member(mobilePhone, UuidUtils.getUUID(), mobilePhone);
|
||||
registerHandler(member);
|
||||
}
|
||||
//判断用户是否有效
|
||||
if (member.getDisabled().equals(false) || member.getDeleteFlag().equals(true)) {
|
||||
throw new ServiceException(ResultCode.USER_STATUS_ERROR);
|
||||
}
|
||||
loginBindUser(member);
|
||||
return memberTokenGenerate.createToken(member, false);
|
||||
}
|
||||
@@ -327,6 +335,7 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
||||
}
|
||||
|
||||
@DemoSite
|
||||
@Override
|
||||
public Member modifyPass(String oldPassword, String newPassword) {
|
||||
AuthUser tokenUser = UserContext.getCurrentUser();
|
||||
if (tokenUser == null) {
|
||||
@@ -375,19 +384,17 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancellation(String password) {
|
||||
public void cancellation() {
|
||||
|
||||
AuthUser tokenUser = UserContext.getCurrentUser();
|
||||
if (tokenUser == null) {
|
||||
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||
}
|
||||
Member member = this.getById(tokenUser.getId());
|
||||
if (member.getPassword().equals(new BCryptPasswordEncoder().encode(password))) {
|
||||
//删除联合登录
|
||||
connectService.deleteByMemberId(member.getId());
|
||||
//混淆用户信息
|
||||
this.confusionMember(member);
|
||||
}
|
||||
//删除联合登录
|
||||
connectService.deleteByMemberId(member.getId());
|
||||
//混淆用户信息
|
||||
this.confusionMember(member);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package cn.lili.modules.order.aftersale.entity.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 售后数量VO
|
||||
*
|
||||
* @author Bulbasaur
|
||||
* @since 2021/3/12 10:32 上午
|
||||
*/
|
||||
@Data
|
||||
public class AfterSaleNumVO {
|
||||
|
||||
@ApiModelProperty(value = "申请中售后数量")
|
||||
private Integer applyNum;
|
||||
@ApiModelProperty(value = "已通过售后数量")
|
||||
private Integer passNum;
|
||||
@ApiModelProperty(value = "已拒绝售后数量")
|
||||
private Integer refuseNum;
|
||||
@ApiModelProperty(value = "待卖家收货售后数量")
|
||||
private Integer buyerReturnNum;
|
||||
@ApiModelProperty(value = "卖家确认收货售后数量")
|
||||
private Integer sellerConfirmNum;
|
||||
@ApiModelProperty(value = "卖家终止售后售后数量")
|
||||
private Integer sellerTerminationNum;
|
||||
@ApiModelProperty(value = "买家取消售后售后数量")
|
||||
private Integer buyerCancelNum;
|
||||
@ApiModelProperty(value = "等待平台退款售后数量")
|
||||
private Integer waitRefundNum;
|
||||
@ApiModelProperty(value = "已完成售后数量")
|
||||
private Integer completeNum;
|
||||
}
|
||||
@@ -86,20 +86,23 @@ public class AfterSaleSearchParams extends PageVO {
|
||||
if (CharSequenceUtil.isNotEmpty(orderSn)) {
|
||||
queryWrapper.like("order_sn", orderSn);
|
||||
}
|
||||
//按买家查询
|
||||
if (CharSequenceUtil.equals(UserContext.getCurrentUser().getRole().name(), UserEnums.MEMBER.name())) {
|
||||
queryWrapper.eq("member_id", UserContext.getCurrentUser().getId());
|
||||
}
|
||||
//按卖家查询
|
||||
if (CharSequenceUtil.equals(UserContext.getCurrentUser().getRole().name(), UserEnums.STORE.name())) {
|
||||
queryWrapper.eq("store_id", UserContext.getCurrentUser().getStoreId());
|
||||
if(UserContext.getCurrentUser() != null){
|
||||
//按买家查询
|
||||
if (CharSequenceUtil.equals(UserContext.getCurrentUser().getRole().name(), UserEnums.MEMBER.name())) {
|
||||
queryWrapper.eq("member_id", UserContext.getCurrentUser().getId());
|
||||
}
|
||||
//按卖家查询
|
||||
if (CharSequenceUtil.equals(UserContext.getCurrentUser().getRole().name(), UserEnums.STORE.name())) {
|
||||
queryWrapper.eq("store_id", UserContext.getCurrentUser().getStoreId());
|
||||
}
|
||||
|
||||
if (CharSequenceUtil.equals(UserContext.getCurrentUser().getRole().name(), UserEnums.MANAGER.name())
|
||||
&& CharSequenceUtil.isNotEmpty(storeId)
|
||||
) {
|
||||
queryWrapper.eq("store_id", storeId);
|
||||
}
|
||||
}
|
||||
|
||||
if (CharSequenceUtil.equals(UserContext.getCurrentUser().getRole().name(), UserEnums.MANAGER.name())
|
||||
&& CharSequenceUtil.isNotEmpty(storeId)
|
||||
) {
|
||||
queryWrapper.eq("store_id", storeId);
|
||||
}
|
||||
if (CharSequenceUtil.isNotEmpty(memberName)) {
|
||||
queryWrapper.like("member_name", memberName);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package cn.lili.modules.order.aftersale.service;
|
||||
import cn.lili.modules.order.aftersale.entity.dos.AfterSale;
|
||||
import cn.lili.modules.order.aftersale.entity.dto.AfterSaleDTO;
|
||||
import cn.lili.modules.order.aftersale.entity.vo.AfterSaleApplyVO;
|
||||
import cn.lili.modules.order.aftersale.entity.vo.AfterSaleNumVO;
|
||||
import cn.lili.modules.order.aftersale.entity.vo.AfterSaleSearchParams;
|
||||
import cn.lili.modules.order.aftersale.entity.vo.AfterSaleVO;
|
||||
import cn.lili.modules.store.entity.dto.StoreAfterSaleAddressDTO;
|
||||
@@ -30,6 +31,9 @@ public interface AfterSaleService extends IService<AfterSale> {
|
||||
*/
|
||||
IPage<AfterSaleVO> getAfterSalePages(AfterSaleSearchParams saleSearchParams);
|
||||
|
||||
|
||||
AfterSaleNumVO getAfterSaleNumVO(AfterSaleSearchParams saleSearchParams);
|
||||
|
||||
/**
|
||||
* 查询导出售后信息
|
||||
*
|
||||
|
||||
@@ -2,9 +2,9 @@ package cn.lili.modules.order.aftersale.serviceimpl;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.event.TransactionCommitSendMQEvent;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.properties.RocketmqCustomProperties;
|
||||
import cn.lili.common.security.AuthUser;
|
||||
@@ -17,6 +17,7 @@ import cn.lili.modules.order.aftersale.aop.AfterSaleLogPoint;
|
||||
import cn.lili.modules.order.aftersale.entity.dos.AfterSale;
|
||||
import cn.lili.modules.order.aftersale.entity.dto.AfterSaleDTO;
|
||||
import cn.lili.modules.order.aftersale.entity.vo.AfterSaleApplyVO;
|
||||
import cn.lili.modules.order.aftersale.entity.vo.AfterSaleNumVO;
|
||||
import cn.lili.modules.order.aftersale.entity.vo.AfterSaleSearchParams;
|
||||
import cn.lili.modules.order.aftersale.entity.vo.AfterSaleVO;
|
||||
import cn.lili.modules.order.aftersale.mapper.AfterSaleMapper;
|
||||
@@ -38,7 +39,6 @@ import cn.lili.modules.system.entity.dos.Logistics;
|
||||
import cn.lili.modules.system.entity.vo.Traces;
|
||||
import cn.lili.modules.system.service.LogisticsService;
|
||||
import cn.lili.mybatis.util.PageUtil;
|
||||
import cn.lili.rocketmq.RocketmqSendCallbackBuilder;
|
||||
import cn.lili.rocketmq.tags.AfterSaleTagsEnum;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
@@ -46,13 +46,14 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -95,17 +96,64 @@ public class AfterSaleServiceImpl extends ServiceImpl<AfterSaleMapper, AfterSale
|
||||
*/
|
||||
@Autowired
|
||||
private RocketmqCustomProperties rocketmqCustomProperties;
|
||||
/**
|
||||
* RocketMQ
|
||||
*/
|
||||
@Autowired
|
||||
private RocketMQTemplate rocketMQTemplate;
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
|
||||
@Override
|
||||
public IPage<AfterSaleVO> getAfterSalePages(AfterSaleSearchParams saleSearchParams) {
|
||||
return baseMapper.queryByParams(PageUtil.initPage(saleSearchParams), saleSearchParams.queryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AfterSaleNumVO getAfterSaleNumVO(AfterSaleSearchParams saleSearchParams) {
|
||||
AfterSaleNumVO afterSaleNumVO = new AfterSaleNumVO();
|
||||
|
||||
// 获取基础查询条件
|
||||
QueryWrapper<AfterSale> baseWrapper = saleSearchParams.queryWrapper();
|
||||
|
||||
// 使用聚合查询一次性获取所有状态的售后数量
|
||||
List<Map<String, Object>> results = this.baseMapper.selectMaps(
|
||||
baseWrapper.select(
|
||||
"COUNT(CASE WHEN service_status = 'APPLY' THEN 1 END) as applyNum",
|
||||
"COUNT(CASE WHEN service_status = 'PASS' THEN 1 END) as passNum",
|
||||
"COUNT(CASE WHEN service_status = 'REFUSE' THEN 1 END) as refuseNum",
|
||||
"COUNT(CASE WHEN service_status = 'BUYER_RETURN' THEN 1 END) as buyerReturnNum",
|
||||
"COUNT(CASE WHEN service_status = 'SELLER_CONFIRM' THEN 1 END) as sellerConfirmNum",
|
||||
"COUNT(CASE WHEN service_status = 'SELLER_TERMINATION' THEN 1 END) as sellerTerminationNum",
|
||||
"COUNT(CASE WHEN service_status = 'BUYER_CANCEL' THEN 1 END) as buyerCancelNum",
|
||||
"COUNT(CASE WHEN service_status = 'WAIT_REFUND' THEN 1 END) as waitRefundNum",
|
||||
"COUNT(CASE WHEN service_status = 'COMPLETE' THEN 1 END) as completeNum"
|
||||
)
|
||||
);
|
||||
|
||||
if (!results.isEmpty()) {
|
||||
Map<String, Object> result = results.get(0);
|
||||
afterSaleNumVO.setApplyNum(((Number) result.get("applyNum")).intValue());
|
||||
afterSaleNumVO.setPassNum(((Number) result.get("passNum")).intValue());
|
||||
afterSaleNumVO.setRefuseNum(((Number) result.get("refuseNum")).intValue());
|
||||
afterSaleNumVO.setBuyerReturnNum(((Number) result.get("buyerReturnNum")).intValue());
|
||||
afterSaleNumVO.setSellerConfirmNum(((Number) result.get("sellerConfirmNum")).intValue());
|
||||
afterSaleNumVO.setSellerTerminationNum(((Number) result.get("sellerTerminationNum")).intValue());
|
||||
afterSaleNumVO.setBuyerCancelNum(((Number) result.get("buyerCancelNum")).intValue());
|
||||
afterSaleNumVO.setWaitRefundNum(((Number) result.get("waitRefundNum")).intValue());
|
||||
afterSaleNumVO.setCompleteNum(((Number) result.get("completeNum")).intValue());
|
||||
} else {
|
||||
// 如果没有结果,设置默认值为0
|
||||
afterSaleNumVO.setApplyNum(0);
|
||||
afterSaleNumVO.setPassNum(0);
|
||||
afterSaleNumVO.setRefuseNum(0);
|
||||
afterSaleNumVO.setBuyerReturnNum(0);
|
||||
afterSaleNumVO.setSellerConfirmNum(0);
|
||||
afterSaleNumVO.setSellerTerminationNum(0);
|
||||
afterSaleNumVO.setBuyerCancelNum(0);
|
||||
afterSaleNumVO.setWaitRefundNum(0);
|
||||
afterSaleNumVO.setCompleteNum(0);
|
||||
}
|
||||
|
||||
return afterSaleNumVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AfterSale> exportAfterSaleOrder(AfterSaleSearchParams saleSearchParams) {
|
||||
return this.list(saleSearchParams.queryWrapper());
|
||||
@@ -580,11 +628,10 @@ public class AfterSaleServiceImpl extends ServiceImpl<AfterSaleMapper, AfterSale
|
||||
*
|
||||
* @param afterSale 售后对象
|
||||
*/
|
||||
private void sendAfterSaleMessage(AfterSale afterSale) {
|
||||
//发送售后创建消息
|
||||
String destination = rocketmqCustomProperties.getAfterSaleTopic() + ":" + AfterSaleTagsEnum.AFTER_SALE_STATUS_CHANGE.name();
|
||||
//发送订单变更mq消息
|
||||
rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(afterSale), RocketmqSendCallbackBuilder.commonCallback());
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void sendAfterSaleMessage(AfterSale afterSale) {
|
||||
applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("发送售后单状态变更MQ消息", rocketmqCustomProperties.getAfterSaleTopic(),
|
||||
AfterSaleTagsEnum.AFTER_SALE_STATUS_CHANGE.name(), JSONUtil.toJsonStr(afterSale)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,7 +19,11 @@ public enum DeliveryMethodEnum {
|
||||
/**
|
||||
* "物流"
|
||||
*/
|
||||
LOGISTICS("物流");
|
||||
LOGISTICS("物流"),
|
||||
/**
|
||||
* 虚拟发货
|
||||
*/
|
||||
VIRTUAL("虚拟发货");
|
||||
|
||||
private final String description;
|
||||
|
||||
|
||||
@@ -212,14 +212,27 @@ public class CouponRender implements CartRenderStep {
|
||||
MemberCouponDTO platformCoupon = tradeDTO.getPlatformCoupon();
|
||||
//如果有勾选平台优惠券
|
||||
if (platformCoupon != null) {
|
||||
renderSku(tradeDTO, platformCoupon);
|
||||
//判断该优惠券是否可以使用,如果可以进行价格渲染,如果不可以使用,去掉该优惠券的使用
|
||||
boolean checkFlag = tradeDTO.getCanUseCoupons().stream().anyMatch(item -> item.getCouponId().equals(platformCoupon.getMemberCoupon().getCouponId()));
|
||||
if(checkFlag){
|
||||
renderSku(tradeDTO, platformCoupon);
|
||||
}else{
|
||||
tradeDTO.setPlatformCoupon(null);
|
||||
}
|
||||
}
|
||||
//计算商家优惠券
|
||||
Map<String, MemberCouponDTO> map = tradeDTO.getStoreCoupons();
|
||||
if (map != null && map.size() > 0) {
|
||||
for (MemberCouponDTO memberCouponDTO : map.values()) {
|
||||
renderSku(tradeDTO, memberCouponDTO);
|
||||
//判断该优惠券是否可以使用,如果可以进行价格渲染,如果不可以使用,去掉该优惠券的使用
|
||||
boolean storeCouponCheck = tradeDTO.getCanUseCoupons().stream().anyMatch(item -> item.getCouponId().equals(memberCouponDTO.getMemberCoupon().getCouponId()));
|
||||
if(storeCouponCheck){
|
||||
renderSku(tradeDTO, memberCouponDTO);
|
||||
}else{
|
||||
map.values().remove(memberCouponDTO);
|
||||
}
|
||||
}
|
||||
tradeDTO.setStoreCoupons(map);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -141,6 +141,7 @@ public class SkuPromotionRender implements CartRenderStep {
|
||||
KanjiaActivitySearchParams kanjiaActivitySearchParams = new KanjiaActivitySearchParams();
|
||||
kanjiaActivitySearchParams.setGoodsSkuId(cartSkuVO.getGoodsSku().getId());
|
||||
kanjiaActivitySearchParams.setMemberId(Objects.requireNonNull(UserContext.getCurrentUser()).getId());
|
||||
kanjiaActivitySearchParams.setKanjiaActivityId(cartSkuVO.getKanjiaId());
|
||||
kanjiaActivitySearchParams.setStatus(KanJiaStatusEnum.SUCCESS.name());
|
||||
KanjiaActivityVO kanjiaActivityVO = kanjiaActivityService.getKanjiaActivityVO(kanjiaActivitySearchParams);
|
||||
//可以砍价金额购买,则处理信息
|
||||
@@ -266,8 +267,8 @@ public class SkuPromotionRender implements CartRenderStep {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (quantity != null && cartSkuVO.getNum() > (Integer) quantity) {//设置购物车未选中
|
||||
//设置购物车未选中
|
||||
if (quantity != null && cartSkuVO.getNum() > (Integer) quantity) {
|
||||
cartSkuVO.setChecked(false);
|
||||
//设置失效消息
|
||||
cartSkuVO.setErrorMessage("促销商品库存不足,现有库存数量[" + quantity + "]");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.lili.modules.order.cart.render.util;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.lili.common.enums.PromotionTypeEnum;
|
||||
import cn.lili.common.utils.CurrencyUtil;
|
||||
import cn.lili.modules.order.cart.entity.dto.TradeDTO;
|
||||
@@ -10,7 +11,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 促销价格计算业务层实现
|
||||
@@ -33,7 +35,7 @@ public class PromotionPriceUtil {
|
||||
PromotionTypeEnum promotionTypeEnum, String activityId) {
|
||||
|
||||
// sku 促销信息非空判定
|
||||
if (skuPromotionDetail == null || skuPromotionDetail.size() == 0) {
|
||||
if (skuPromotionDetail == null || skuPromotionDetail.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -68,40 +70,39 @@ public class PromotionPriceUtil {
|
||||
List<CartSkuVO> skuVOList = tradeDTO.getSkuList();
|
||||
|
||||
// 获取map分配sku的总数,如果是最后一个商品分配金额,则将金额从百分比改为总金额扣减,避免出现小数除不尽
|
||||
int count = skuPromotionDetail.size();
|
||||
AtomicInteger count = new AtomicInteger(skuPromotionDetail.size());
|
||||
|
||||
//已优惠金额
|
||||
Double deducted = 0D;
|
||||
AtomicReference<Double> deducted = new AtomicReference<>(0D);
|
||||
|
||||
for (String skuId : skuPromotionDetail.keySet()) {
|
||||
|
||||
//获取对应商品进行计算
|
||||
for (CartSkuVO cartSkuVO : skuVOList) {
|
||||
|
||||
if (cartSkuVO.getGoodsSku().getId().equals(skuId)) {
|
||||
Double finalDiscountPrice = discountPrice;
|
||||
Double finalTotalPrice = totalPrice;
|
||||
skuVOList.stream().filter(l -> l.getGoodsSku().getId().equals(skuId)).findFirst().ifPresent(cartSkuVO -> {
|
||||
//sku 优惠金额
|
||||
Double skuDiscountPrice;
|
||||
count.getAndDecrement();
|
||||
|
||||
count--;
|
||||
|
||||
//sku 优惠金额
|
||||
Double skuDiscountPrice;
|
||||
|
||||
//非最后一个商品,则按照比例计算
|
||||
if (count > 0) {
|
||||
//商品金额占比
|
||||
double point = CurrencyUtil.div(cartSkuVO.getPriceDetailDTO().getGoodsPrice(), totalPrice, 4);
|
||||
//商品优惠金额
|
||||
skuDiscountPrice = CurrencyUtil.mul(discountPrice, point);
|
||||
//累加已优惠金额
|
||||
deducted = CurrencyUtil.add(deducted, skuDiscountPrice);
|
||||
}
|
||||
// 如果是最后一个商品 则减去之前优惠的金额来进行计算
|
||||
else {
|
||||
skuDiscountPrice = CurrencyUtil.sub(discountPrice, deducted);
|
||||
}
|
||||
|
||||
calculateCartSkuPromotionsPrice(cartSkuVO, skuDiscountPrice, promotionTypeEnum, activityId);
|
||||
//非最后一个商品,则按照比例计算
|
||||
if (count.get() > 0) {
|
||||
//商品金额占比
|
||||
double point = CurrencyUtil.div(cartSkuVO.getPriceDetailDTO().getGoodsPrice(), finalTotalPrice, 4);
|
||||
//商品优惠金额
|
||||
skuDiscountPrice = CurrencyUtil.mul(finalDiscountPrice, point);
|
||||
//累加已优惠金额
|
||||
deducted.set(CurrencyUtil.add(deducted.get(), skuDiscountPrice));
|
||||
}
|
||||
}
|
||||
// 如果是最后一个商品 则减去之前优惠的金额来进行计算
|
||||
else {
|
||||
skuDiscountPrice = CurrencyUtil.sub(finalDiscountPrice, deducted.get());
|
||||
}
|
||||
|
||||
calculateCartSkuPromotionsPrice(cartSkuVO, skuDiscountPrice, promotionTypeEnum, activityId);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
calculateNotEnoughPromotionsPrice(skuVOList, skuPromotionDetail, discountPrice, totalPrice, promotionTypeEnum, activityId);
|
||||
@@ -186,51 +187,100 @@ public class PromotionPriceUtil {
|
||||
// 特殊情况处理,如参与多个促销活动,部分商品在其他促销计算后的金额不足以满足与当前参与的促销活动的优惠金额
|
||||
// 但当前购物车内存在当前当前促销活动的其他商品且剩余金额也满足分摊不足商品的不足金额,则分摊到其他商品上
|
||||
// 满足当前促销的总优惠金额
|
||||
if (skuPromotionDetail == null || skuPromotionDetail.isEmpty()) {
|
||||
if (skuPromotionDetail == null || skuPromotionDetail.size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// clone skuPromotionDetail
|
||||
Map<String, Double> skuPromotionDetailClone = MapUtil.sortByValue(skuPromotionDetail, false);
|
||||
|
||||
// 未满足优惠金额的商品
|
||||
long matchPromotionsZeroCount =
|
||||
skuVOList.stream().filter(l -> l.getPriceDetailDTO().getFlowPrice() == 0 && skuPromotionDetail.containsKey(l.getGoodsSku().getId())).count();
|
||||
long matchPromotionsCount = skuVOList.stream().filter(l -> skuPromotionDetail.containsKey(l.getGoodsSku().getId())).count();
|
||||
skuVOList.stream().filter(l -> l.getPriceDetailDTO().getFlowPrice() == 0 && skuPromotionDetailClone.containsKey(l.getGoodsSku().getId())).count();
|
||||
// 参与当前促销活动的商品
|
||||
long matchPromotionsCount = skuVOList.stream().filter(l -> skuPromotionDetailClone.containsKey(l.getGoodsSku().getId())).count();
|
||||
if (matchPromotionsZeroCount == matchPromotionsCount) {
|
||||
return;
|
||||
}
|
||||
// 获取剩余金额不足优惠金额的商品
|
||||
List<CartSkuVO> unEnoughSku = skuVOList.stream().filter(k -> {
|
||||
if (skuPromotionDetail.containsKey(k.getGoodsSku().getId()) && skuPromotionDetail.size() >= 2) {
|
||||
//商品金额占比
|
||||
double point = CurrencyUtil.div(k.getPriceDetailDTO().getGoodsPrice(), totalPrice, 4);
|
||||
//商品优惠金额
|
||||
Double skuDiscountPrice = CurrencyUtil.mul(discountPrice, point);
|
||||
return k.getPriceDetailDTO().getCouponPrice() > 0 && skuDiscountPrice > k.getPriceDetailDTO().getCouponPrice();
|
||||
// 分配到其他商品的优惠金额
|
||||
AtomicReference<Double> balance = new AtomicReference<>(0D);
|
||||
StringBuilder lastSkuId = new StringBuilder();
|
||||
|
||||
// 计数器
|
||||
int count = 0;
|
||||
|
||||
|
||||
// 检查是否有不满足优惠金额的商品
|
||||
filterEnoughSku(skuVOList, skuPromotionDetailClone, discountPrice, totalPrice, balance, lastSkuId, promotionTypeEnum, activityId);
|
||||
|
||||
// 循环 优惠金额分摊,直到所有商品都满足优惠金额
|
||||
while (true) {
|
||||
// 如果还有剩余金额,则继续分摊
|
||||
if (balance.get() > 0) {
|
||||
skuPromotionDetailClone.remove(lastSkuId.toString());
|
||||
double lastDiscountPrice = CurrencyUtil.sub(discountPrice, skuPromotionDetail.get(lastSkuId.toString()));
|
||||
double lastTotalPrice = CurrencyUtil.sub(totalPrice, skuPromotionDetail.get(lastSkuId.toString()));
|
||||
filterEnoughSku(skuVOList, skuPromotionDetailClone, lastDiscountPrice, lastTotalPrice, balance, lastSkuId, promotionTypeEnum, activityId);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}).collect(Collectors.toList());
|
||||
if (!unEnoughSku.isEmpty()) {
|
||||
if (unEnoughSku.size() == skuVOList.size()) {
|
||||
return;
|
||||
count++;
|
||||
|
||||
// 防止死循环
|
||||
if (count > skuPromotionDetail.size()) {
|
||||
break;
|
||||
}
|
||||
for (CartSkuVO cartSkuVO : skuVOList) {
|
||||
if (unEnoughSku.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
if (skuPromotionDetail.containsKey(cartSkuVO.getGoodsSku().getId()) && unEnoughSku.stream().noneMatch(k -> k.getGoodsSku().getId().equals(cartSkuVO.getGoodsSku().getId()))) {
|
||||
// 商品金额占比
|
||||
double point = CurrencyUtil.div(cartSkuVO.getPriceDetailDTO().getGoodsPrice(), totalPrice, 4);
|
||||
// 商品优惠金额
|
||||
Double skuDiscountPrice = CurrencyUtil.mul(discountPrice, point);
|
||||
// 商品优惠金额 - 不足优惠金额 = 差额
|
||||
Double sub = CurrencyUtil.sub(skuDiscountPrice, unEnoughSku.get(0).getPriceDetailDTO().getCouponPrice());
|
||||
// 分摊到其他商品: 其他商品原优惠金额 + 差额
|
||||
calculateCartSkuPromotionsPrice(cartSkuVO, sub, promotionTypeEnum, activityId);
|
||||
// 从不足商品列表中移除
|
||||
unEnoughSku.remove(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
calculateNotEnoughPromotionsPrice(skuVOList, skuPromotionDetail, discountPrice, totalPrice, promotionTypeEnum, activityId);
|
||||
}
|
||||
|
||||
|
||||
private static void filterEnoughSku(List<CartSkuVO> skuVOList, Map<String, Double> skuPromotionDetail,
|
||||
Double discountPrice, Double totalPrice,
|
||||
AtomicReference<Double> balance, StringBuilder lastSkuId,
|
||||
PromotionTypeEnum promotionTypeEnum, String activityId) {
|
||||
AtomicInteger count = new AtomicInteger(skuPromotionDetail.size());
|
||||
AtomicReference<Double> countPrice = new AtomicReference<>(0D);
|
||||
for (String skuId : skuPromotionDetail.keySet()) {
|
||||
skuVOList.forEach(l -> {
|
||||
if (l.getGoodsSku().getId().equals(skuId)) {
|
||||
count.getAndDecrement();
|
||||
|
||||
//商品金额占比
|
||||
double point = CurrencyUtil.div(l.getPriceDetailDTO().getGoodsPrice(), totalPrice, 4);
|
||||
|
||||
//商品优惠金额
|
||||
Double skuDiscountPrice;
|
||||
|
||||
if (count.get() > 0) {
|
||||
//非最后一个商品,则按照比例计算
|
||||
skuDiscountPrice = CurrencyUtil.mul(discountPrice, point);
|
||||
} else {
|
||||
// 如果是最后一个商品 则减去之前优惠的金额来进行计算
|
||||
skuDiscountPrice = CurrencyUtil.sub(discountPrice, countPrice.get());
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (balance.get() > 0) {
|
||||
// 分摊到其他商品: 其他商品原优惠金额 + 差额
|
||||
calculateCartSkuPromotionsPrice(l, balance.get(), promotionTypeEnum, activityId);
|
||||
}
|
||||
|
||||
// 如果商品优惠金额大于商品金额,则取商品金额。差额分摊到其他商品
|
||||
if (skuDiscountPrice > l.getPriceDetailDTO().getGoodsPrice()) {
|
||||
balance.set(CurrencyUtil.sub(skuDiscountPrice, l.getPriceDetailDTO().getGoodsPrice()));
|
||||
lastSkuId.append(skuId);
|
||||
skuDiscountPrice = l.getPriceDetailDTO().getGoodsPrice();
|
||||
} else {
|
||||
balance.set(0D);
|
||||
}
|
||||
|
||||
|
||||
countPrice.set(CurrencyUtil.add(countPrice.get(), skuDiscountPrice));
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -638,18 +638,20 @@ public class CartServiceImpl implements CartService {
|
||||
if (Boolean.FALSE.equals(cartSkuVO.getChecked())) {
|
||||
continue;
|
||||
}
|
||||
//使用优惠券时判断最新的sku价格。与后面渲染一致
|
||||
GoodsSku goodsSku = goodsSkuService.getGoodsSkuByIdFromCache(cartSkuVO.getGoodsSku().getId());
|
||||
//有促销金额则用促销金额,否则用商品原价
|
||||
if (cartSkuVO.getPromotionMap() != null && !cartSkuVO.getPromotionMap().isEmpty()) {
|
||||
if (cartSkuVO.getPromotionMap().keySet().stream().anyMatch(i -> i.contains(PromotionTypeEnum.PINTUAN.name()) || i.contains(PromotionTypeEnum.SECKILL.name()))) {
|
||||
cartPrice = CurrencyUtil.add(cartPrice, CurrencyUtil.mul(cartSkuVO.getPurchasePrice(), cartSkuVO.getNum()));
|
||||
skuPrice.put(cartSkuVO.getGoodsSku().getId(), CurrencyUtil.mul(cartSkuVO.getPurchasePrice(), cartSkuVO.getNum()));
|
||||
} else {
|
||||
cartPrice = CurrencyUtil.add(cartPrice, CurrencyUtil.mul(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getNum()));
|
||||
skuPrice.put(cartSkuVO.getGoodsSku().getId(), CurrencyUtil.mul(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getNum()));
|
||||
cartPrice = CurrencyUtil.add(cartPrice, CurrencyUtil.mul(goodsSku.getPrice(), cartSkuVO.getNum()));
|
||||
skuPrice.put(cartSkuVO.getGoodsSku().getId(), CurrencyUtil.mul(goodsSku.getPrice(), cartSkuVO.getNum()));
|
||||
}
|
||||
} else {
|
||||
cartPrice = CurrencyUtil.add(cartPrice, CurrencyUtil.mul(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getNum()));
|
||||
skuPrice.put(cartSkuVO.getGoodsSku().getId(), CurrencyUtil.mul(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getNum()));
|
||||
cartPrice = CurrencyUtil.add(cartPrice, CurrencyUtil.mul(goodsSku.getPrice(), cartSkuVO.getNum()));
|
||||
skuPrice.put(cartSkuVO.getGoodsSku().getId(), CurrencyUtil.mul(goodsSku.getPrice(), cartSkuVO.getNum()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +148,9 @@ public class Order extends BaseEntity {
|
||||
@ApiModelProperty(value = "买家订单备注")
|
||||
private String remark;
|
||||
|
||||
@ApiModelProperty(value = "卖家订单备注")
|
||||
private String sellerRemark;
|
||||
|
||||
@ApiModelProperty(value = "订单取消原因")
|
||||
private String cancelReason;
|
||||
|
||||
@@ -240,7 +243,7 @@ public class Order extends BaseEntity {
|
||||
this.setDeliverStatus(DeliverStatusEnum.UNDELIVERED.name());
|
||||
this.setTradeSn(tradeDTO.getSn());
|
||||
this.setRemark(cartVO.getRemark());
|
||||
this.setFreightPrice(tradeDTO.getPriceDetailDTO().getFreightPrice());
|
||||
this.setFreightPrice(cartVO.getPriceDetailDTO().getFreightPrice());
|
||||
//会员收件信息
|
||||
if (tradeDTO.getMemberAddress() != null && DeliveryMethodEnum.LOGISTICS.name().equals(cartVO.getDeliveryMethod())) {
|
||||
this.setConsigneeAddressIdPath(tradeDTO.getMemberAddress().getConsigneeAddressIdPath());
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.lili.modules.order.order.entity.dos;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.lili.common.enums.PromotionTypeEnum;
|
||||
import cn.lili.common.utils.BeanUtil;
|
||||
import cn.lili.common.utils.SnowFlake;
|
||||
import cn.lili.modules.order.cart.entity.dto.TradeDTO;
|
||||
@@ -187,4 +188,10 @@ public class OrderItem extends BaseEntity {
|
||||
this.priceDetail = JSONUtil.toJsonStr(priceDetail);
|
||||
}
|
||||
|
||||
public String getAfterSaleStatus() {
|
||||
if (!PromotionTypeEnum.isCanAfterSale(this.promotionType)) {
|
||||
return OrderItemAfterSaleStatusEnum.EXPIRED.name();
|
||||
}
|
||||
return afterSaleStatus;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.lili.modules.order.order.entity.dos;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.lili.common.utils.BeanUtil;
|
||||
@@ -8,6 +9,7 @@ import cn.lili.common.utils.SnowFlake;
|
||||
import cn.lili.modules.order.order.entity.dto.PriceDetailDTO;
|
||||
import cn.lili.modules.order.order.entity.enums.FlowTypeEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderPromotionTypeEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.ProfitSharingStatusEnum;
|
||||
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
||||
import cn.lili.mybatis.BaseIdEntity;
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
@@ -141,6 +143,24 @@ public class StoreFlow extends BaseIdEntity {
|
||||
@ApiModelProperty(value = "创建时间", hidden = true)
|
||||
private Date createTime;
|
||||
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@ApiModelProperty(value = "结算时间", hidden = true)
|
||||
private Date billTime;
|
||||
|
||||
@ApiModelProperty(value = "是否全部退款,true为全部退款")
|
||||
private Boolean fullRefund;
|
||||
|
||||
/**
|
||||
* @see ProfitSharingStatusEnum
|
||||
*/
|
||||
@ApiModelProperty(value = "分账状态")
|
||||
private String profitSharingStatus;
|
||||
|
||||
@ApiModelProperty(value = "实际分账金额DTO", hidden = true)
|
||||
private String profitSharing;
|
||||
|
||||
|
||||
public StoreFlow(Order order, OrderItem item, FlowTypeEnum flowTypeEnum) {
|
||||
//获取订单促销类型,如果为促销订单则获取促销商品并获取结算价
|
||||
@@ -196,6 +216,10 @@ public class StoreFlow extends BaseIdEntity {
|
||||
this.setPaymentName(order.getPaymentMethod());
|
||||
//添加第三方支付流水号
|
||||
this.setTransactionId(order.getReceivableNo());
|
||||
|
||||
//默认结算时间180天
|
||||
if (flowTypeEnum.equals(FlowTypeEnum.PAY)) {
|
||||
this.billTime = DateUtil.offsetDay(new Date(), 180);
|
||||
this.fullRefund = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package cn.lili.modules.order.order.entity.dto;
|
||||
|
||||
import cn.lili.modules.order.order.entity.enums.DeliverStatusEnum;
|
||||
import cn.lili.common.enums.ClientTypeEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderItemAfterSaleStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.PayStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderTypeEnum;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@@ -19,77 +20,71 @@ import java.util.Date;
|
||||
@Data
|
||||
public class OrderExportDTO {
|
||||
|
||||
@ApiModelProperty("订单编号")
|
||||
private String sn;
|
||||
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@ApiModelProperty(value = "用户名")
|
||||
private String memberName;
|
||||
|
||||
@ApiModelProperty(value = "收件人姓名")
|
||||
private String consigneeName;
|
||||
|
||||
@ApiModelProperty(value = "收件人手机")
|
||||
private String consigneeMobile;
|
||||
|
||||
@ApiModelProperty(value = "收件人地址")
|
||||
private String consigneeAddressPath;
|
||||
|
||||
@ApiModelProperty(value = "详细地址")
|
||||
private String consigneeDetail;
|
||||
|
||||
@ApiModelProperty(value = "支付方式")
|
||||
private String paymentMethod;
|
||||
|
||||
@ApiModelProperty(value = "物流公司名称")
|
||||
private String logisticsName;
|
||||
|
||||
@ApiModelProperty(value = "运费")
|
||||
private Double freightPrice;
|
||||
|
||||
@ApiModelProperty(value = "商品价格")
|
||||
private Double goodsPrice;
|
||||
|
||||
@ApiModelProperty(value = "优惠的金额")
|
||||
private Double discountPrice;
|
||||
|
||||
@ApiModelProperty(value = "总价格")
|
||||
private Double flowPrice;
|
||||
|
||||
@ApiModelProperty(value = "商品名称")
|
||||
@ApiModelProperty(value = "主订单编号")
|
||||
private String orderSn;
|
||||
@ApiModelProperty(value = "子订单编号")
|
||||
private String orderItemSn;
|
||||
@ApiModelProperty(value = "选购商品")
|
||||
private String goodsName;
|
||||
|
||||
@ApiModelProperty(value = "商品数量")
|
||||
private Integer num;
|
||||
|
||||
@ApiModelProperty(value = "买家订单备注")
|
||||
@ApiModelProperty(value = "商品ID")
|
||||
private String goodsId;
|
||||
@ApiModelProperty(value = "商品单价")
|
||||
private Double unitPrice;
|
||||
@ApiModelProperty(value = "订单应付金额")
|
||||
private Double flowPrice;
|
||||
@ApiModelProperty(value = "价格内容")
|
||||
private String priceDetail;
|
||||
@ApiModelProperty(value = "支付方式")
|
||||
private String paymentMethod;
|
||||
@ApiModelProperty(value = "收件人")
|
||||
private String consigneeName;
|
||||
@ApiModelProperty(value = "收件人手机")
|
||||
private String consigneeMobile;
|
||||
@ApiModelProperty(value = "收件人地址")
|
||||
private String consigneeAddressPath;
|
||||
@ApiModelProperty(value = "详细地址")
|
||||
private String consigneeDetail;
|
||||
@ApiModelProperty(value = "买家留言")
|
||||
private String remark;
|
||||
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ApiModelProperty(value = "订单提交时间")
|
||||
private Date createTime;
|
||||
@ApiModelProperty(value = "支付完成时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date paymentTime;
|
||||
/**
|
||||
* @see ClientTypeEnum
|
||||
*/
|
||||
@ApiModelProperty(value = "来源")
|
||||
private String clientType;
|
||||
/**
|
||||
* @see OrderStatusEnum
|
||||
*/
|
||||
@ApiModelProperty(value = "订单状态")
|
||||
private String orderStatus;
|
||||
|
||||
/**
|
||||
* @see PayStatusEnum
|
||||
* @see OrderTypeEnum
|
||||
*/
|
||||
@ApiModelProperty(value = "付款状态")
|
||||
private String payStatus;
|
||||
|
||||
@ApiModelProperty(value = "订单类型")
|
||||
private String orderType;
|
||||
/**
|
||||
* @see DeliverStatusEnum
|
||||
* @see OrderItemAfterSaleStatusEnum
|
||||
*/
|
||||
@ApiModelProperty(value = "货运状态")
|
||||
private String deliverStatus;
|
||||
|
||||
@ApiModelProperty(value = "是否需要发票")
|
||||
private Boolean needReceipt;
|
||||
|
||||
@ApiModelProperty(value = "店铺名称")
|
||||
@ApiModelProperty(value = "售后状态")
|
||||
private String afterSaleStatus;
|
||||
@ApiModelProperty(value = "取消原因")
|
||||
private String cancelReason;
|
||||
@ApiModelProperty(value = "发货时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date logisticsTime;
|
||||
@ApiModelProperty(value = "完成时间")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date completeTime;
|
||||
@ApiModelProperty(value = "店铺")
|
||||
private String storeName;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package cn.lili.modules.order.order.entity.dto;
|
||||
|
||||
import cn.lili.common.enums.ClientTypeEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderItemAfterSaleStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderTypeEnum;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 订单导出DTO
|
||||
* @author Bulbasaur
|
||||
* @since 2021/6/3 6:36 下午
|
||||
*
|
||||
*/
|
||||
@Data
|
||||
public class OrderExportDetailDTO {
|
||||
|
||||
@ApiModelProperty(value = "主订单编号")
|
||||
private String orderSn;
|
||||
@ApiModelProperty(value = "子订单编号")
|
||||
private String orderItemSn;
|
||||
@ApiModelProperty(value = "选购商品")
|
||||
private String goodsName;
|
||||
@ApiModelProperty(value = "商品数量")
|
||||
private Integer num;
|
||||
@ApiModelProperty(value = "商品ID")
|
||||
private String goodsId;
|
||||
@ApiModelProperty(value = "商品单价")
|
||||
private Double unitPrice;
|
||||
@ApiModelProperty(value = "订单应付金额")
|
||||
private Double flowPrice;
|
||||
@ApiModelProperty(value = "运费")
|
||||
private Double freightPrice;
|
||||
@ApiModelProperty(value = "优惠总金额")
|
||||
private Double discountPrice;
|
||||
@ApiModelProperty(value = "平台")
|
||||
private Double siteMarketingCost;
|
||||
@ApiModelProperty(value = "商家优惠")
|
||||
private Double storeMarketingCost;
|
||||
@ApiModelProperty(value = "商家改价")
|
||||
private Double updatePrice;
|
||||
@ApiModelProperty(value = "支付方式")
|
||||
private String paymentMethod;
|
||||
@ApiModelProperty(value = "收件人")
|
||||
private String consigneeName;
|
||||
@ApiModelProperty(value = "收件人手机")
|
||||
private String consigneeMobile;
|
||||
@ApiModelProperty(value = "省")
|
||||
private String province;
|
||||
@ApiModelProperty(value = "市")
|
||||
private String city;
|
||||
@ApiModelProperty(value = "区")
|
||||
private String district;
|
||||
@ApiModelProperty(value = "街道")
|
||||
private String street;
|
||||
@ApiModelProperty(value = "详细地址")
|
||||
private String consigneeDetail;
|
||||
@ApiModelProperty(value = "买家留言")
|
||||
private String remark;
|
||||
@ApiModelProperty(value = "订单提交时间")
|
||||
private String createTime;
|
||||
@ApiModelProperty(value = "支付完成时间")
|
||||
private String paymentTime;
|
||||
/**
|
||||
* @see ClientTypeEnum
|
||||
*/
|
||||
@ApiModelProperty(value = "来源")
|
||||
private String clientType;
|
||||
/**
|
||||
* @see OrderStatusEnum
|
||||
*/
|
||||
@ApiModelProperty(value = "订单状态")
|
||||
private String orderStatus;
|
||||
/**
|
||||
* @see OrderTypeEnum
|
||||
*/
|
||||
@ApiModelProperty(value = "订单类型")
|
||||
private String orderType;
|
||||
/**
|
||||
* @see OrderItemAfterSaleStatusEnum
|
||||
*/
|
||||
@ApiModelProperty(value = "售后状态")
|
||||
private String afterSaleStatus;
|
||||
@ApiModelProperty(value = "取消原因")
|
||||
private String cancelReason;
|
||||
@ApiModelProperty(value = "发货时间")
|
||||
private String logisticsTime;
|
||||
@ApiModelProperty(value = "完成时间")
|
||||
private String completeTime;
|
||||
@ApiModelProperty(value = "店铺")
|
||||
private String storeName;
|
||||
}
|
||||
@@ -63,9 +63,6 @@ public class OrderSearchParams extends PageVO {
|
||||
@ApiModelProperty(value = "关键字 商品名称/买家名称/店铺名称")
|
||||
private String keywords;
|
||||
|
||||
@ApiModelProperty(value = "付款方式")
|
||||
private String paymentType;
|
||||
|
||||
/**
|
||||
* @see OrderTypeEnum
|
||||
* @see cn.lili.modules.order.order.entity.enums.OrderPromotionTypeEnum
|
||||
@@ -121,7 +118,11 @@ public class OrderSearchParams extends PageVO {
|
||||
|
||||
//关键字查询
|
||||
if (CharSequenceUtil.isNotEmpty(keywords)) {
|
||||
wrapper.and(keyWrapper -> keyWrapper.like("o.sn", keywords).or().like("oi.goods_name", keywords));
|
||||
wrapper.and(keyWrapper -> keyWrapper.like("o.sn", keywords).or()
|
||||
.like("oi.goods_name", keywords).or()
|
||||
.like("o.consignee_name", keywords).or()
|
||||
.like("o.consignee_mobile", keywords).or()
|
||||
.like("o.store_name", keywords));
|
||||
}
|
||||
if (currentUser != null) {
|
||||
//按卖家查询
|
||||
@@ -157,9 +158,6 @@ public class OrderSearchParams extends PageVO {
|
||||
//按商品名称查询
|
||||
wrapper.like(CharSequenceUtil.isNotEmpty(goodsName), "oi.goods_name", goodsName);
|
||||
|
||||
//付款方式
|
||||
wrapper.like(CharSequenceUtil.isNotEmpty(paymentType), "o.payment_type", paymentType);
|
||||
|
||||
//按支付方式
|
||||
wrapper.eq(CharSequenceUtil.isNotEmpty(paymentMethod), "o.payment_method", paymentMethod);
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package cn.lili.modules.order.order.entity.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 流水-实际分账DTO
|
||||
*/
|
||||
@Data
|
||||
public class StoreFlowProfitSharingDTO {
|
||||
//平台获取金额
|
||||
private Double platformPrice;
|
||||
//店铺获取金额
|
||||
private Double storePrice;
|
||||
//分销员获取金额
|
||||
private Double distributionPrice;
|
||||
//合计金额 --剩余金额
|
||||
private Double price;
|
||||
//补差金额
|
||||
private Double subsidies;
|
||||
}
|
||||
@@ -12,6 +12,7 @@ public enum DeliverStatusEnum {
|
||||
* 发货状态
|
||||
*/
|
||||
UNDELIVERED("未发货"),
|
||||
PARTS_DELIVERED("部分发货"),
|
||||
DELIVERED("已发货"),
|
||||
RECEIVED("已收货");
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package cn.lili.modules.order.order.entity.enums;
|
||||
|
||||
import cn.lili.common.utils.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* 订单促销类型枚举
|
||||
*
|
||||
@@ -27,6 +32,30 @@ public enum OrderPromotionTypeEnum {
|
||||
/**
|
||||
* 砍价订单
|
||||
*/
|
||||
KANJIA
|
||||
KANJIA;
|
||||
|
||||
/**
|
||||
* 判断促销类型是否有效
|
||||
* @param typeEnumValue
|
||||
* @return
|
||||
*/
|
||||
public static boolean isValid(String typeEnumValue) {
|
||||
if (StringUtils.isBlank(typeEnumValue)) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.stream(OrderPromotionTypeEnum.values()).anyMatch(c -> c.name().equals(typeEnumValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断订单类型是否可售后
|
||||
* GIFT\POINTS\KANJIA 三种促销类型的订单不可进行售后
|
||||
* @return true 可售后 false 不可售后
|
||||
*/
|
||||
public static boolean isCanAfterSale(String orderPromotionType) {
|
||||
if (!isValid(orderPromotionType)) {
|
||||
return true;
|
||||
}
|
||||
EnumSet<OrderPromotionTypeEnum> noAfterSale = EnumSet.of(OrderPromotionTypeEnum.GIFT, OrderPromotionTypeEnum.POINTS, OrderPromotionTypeEnum.KANJIA);
|
||||
return !noAfterSale.contains(OrderPromotionTypeEnum.valueOf(orderPromotionType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ public enum OrderStatusEnum {
|
||||
UNPAID("未付款"),
|
||||
PAID("已付款"),
|
||||
UNDELIVERED("待发货"),
|
||||
PARTS_DELIVERED("部分发货"),
|
||||
DELIVERED("已发货"),
|
||||
COMPLETED("已完成"),
|
||||
STAY_PICKED_UP("待自提"),
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.lili.modules.order.order.entity.enums;
|
||||
|
||||
/**
|
||||
* 分账状态 枚举
|
||||
*/
|
||||
public enum ProfitSharingStatusEnum {
|
||||
ORDER_CANCEL("订单取消"),
|
||||
WAIT_COMPLETE("待订单完成"),
|
||||
PROCESSING("处理中"),
|
||||
FINISHED("分账完成");
|
||||
// FAIL("分账失败"),
|
||||
// ARTIFICIAL("人工处理");
|
||||
private String description;
|
||||
|
||||
ProfitSharingStatusEnum(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
@@ -73,18 +73,18 @@ public class AllowOperation implements Serializable {
|
||||
|
||||
//可编辑订单收件人信息=实物订单 && 订单未发货 && 订单未取消 && 订单不是自提
|
||||
this.editConsignee = order.getOrderType().equals(OrderTypeEnum.NORMAL.name())
|
||||
&& order.getDeliverStatus().equals(DeliverStatusEnum.UNDELIVERED.name())
|
||||
&& (order.getDeliverStatus().equals(DeliverStatusEnum.UNDELIVERED.name()) || order.getDeliverStatus().equals(DeliverStatusEnum.PARTS_DELIVERED.name()))
|
||||
&& !status.equals(OrderStatusEnum.CANCELLED.name())
|
||||
&& !order.getDeliveryMethod().equals(DeliveryMethodEnum.SELF_PICK_UP.name());
|
||||
|
||||
//是否允许被发货
|
||||
this.ship = editConsignee && status.equals(OrderStatusEnum.UNDELIVERED.name());
|
||||
this.ship = editConsignee && (status.equals(OrderStatusEnum.UNDELIVERED.name()) || order.getDeliverStatus().equals(DeliverStatusEnum.PARTS_DELIVERED.name()));
|
||||
|
||||
//是否允许被收货
|
||||
this.rog = status.equals(OrderStatusEnum.DELIVERED.name());
|
||||
|
||||
//是否允许查看物流信息
|
||||
this.showLogistics = order.getDeliverStatus().equals(DeliverStatusEnum.DELIVERED.name()) && status.equals(OrderStatusEnum.DELIVERED.name());
|
||||
this.showLogistics = (order.getDeliverStatus().equals(DeliverStatusEnum.DELIVERED.name()) || order.getDeliverStatus().equals(DeliverStatusEnum.PARTS_DELIVERED.name())) && (status.equals(OrderStatusEnum.DELIVERED.name()) || status.equals(OrderStatusEnum.PARTS_DELIVERED.name()));
|
||||
|
||||
//虚拟订单 或 自提订单可以核销
|
||||
this.take =
|
||||
@@ -107,11 +107,8 @@ public class AllowOperation implements Serializable {
|
||||
}
|
||||
|
||||
//取消判定
|
||||
if (CharSequenceUtil.equalsAny(status, OrderStatusEnum.UNPAID.name(), OrderStatusEnum.PAID.name(), OrderStatusEnum.UNDELIVERED.name(),
|
||||
OrderStatusEnum.STAY_PICKED_UP.name(),
|
||||
OrderStatusEnum.TAKE.name())) {
|
||||
if (CharSequenceUtil.equalsAny(status, OrderStatusEnum.UNPAID.name(), OrderStatusEnum.PAID.name(), OrderStatusEnum.UNDELIVERED.name())) {
|
||||
this.cancel = true;
|
||||
|
||||
}
|
||||
//新订单,允许支付
|
||||
this.pay = status.equals(OrderStatusEnum.UNPAID.name());
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.lili.modules.order.order.entity.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class OrderNumVO {
|
||||
|
||||
@ApiModelProperty(value = "未付款订单数量")
|
||||
private Integer waitPayNum;
|
||||
@ApiModelProperty(value = "已付款订单数量")
|
||||
private Integer waitDeliveryNum;
|
||||
@ApiModelProperty(value = "待发货订单数量")
|
||||
private Integer waitShipNum;
|
||||
@ApiModelProperty(value = "部分发货订单数量")
|
||||
private Integer partsDeliveredNumNum;
|
||||
@ApiModelProperty(value = "待收货订单数量")
|
||||
private Integer deliveredNum;
|
||||
@ApiModelProperty(value = "待核验订单数量")
|
||||
private Integer waitCheckNum;
|
||||
@ApiModelProperty(value = "待自提订单数量")
|
||||
private Integer waitSelfPickNum;
|
||||
@ApiModelProperty(value = "已完成订单数量")
|
||||
private Integer finishNum;
|
||||
@ApiModelProperty(value = "已关闭订单数量")
|
||||
private Integer closeNum;
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.lili.common.enums.ClientTypeEnum;
|
||||
import cn.lili.common.security.sensitive.Sensitive;
|
||||
import cn.lili.common.security.sensitive.enums.SensitiveStrategy;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderItemAfterSaleStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderPromotionTypeEnum;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@@ -54,6 +56,9 @@ public class OrderSimpleVO {
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date paymentTime;
|
||||
|
||||
@ApiModelProperty(value = "用户ID")
|
||||
private String memberId;
|
||||
|
||||
@ApiModelProperty(value = "用户名")
|
||||
@Sensitive(strategy = SensitiveStrategy.PHONE)
|
||||
private String memberName;
|
||||
@@ -148,6 +153,9 @@ public class OrderSimpleVO {
|
||||
@ApiModelProperty(value = "退款金额")
|
||||
private String groupRefundPrice;
|
||||
|
||||
@ApiModelProperty(value = "卖家订单备注")
|
||||
private String sellerRemark;
|
||||
|
||||
public List<OrderItemVO> getOrderItems() {
|
||||
if (CharSequenceUtil.isEmpty(groupGoodsId)) {
|
||||
return new ArrayList<>();
|
||||
@@ -183,7 +191,11 @@ public class OrderSimpleVO {
|
||||
orderItemVO.setImage(groupImages.split(",")[i]);
|
||||
}
|
||||
if (CharSequenceUtil.isNotEmpty(groupAfterSaleStatus) && groupAfterSaleStatus.split(",").length == groupGoodsId.split(",").length) {
|
||||
orderItemVO.setAfterSaleStatus(groupAfterSaleStatus.split(",")[i]);
|
||||
if (!OrderPromotionTypeEnum.isCanAfterSale(this.orderPromotionType)) {
|
||||
orderItemVO.setAfterSaleStatus(OrderItemAfterSaleStatusEnum.EXPIRED.name());
|
||||
} else {
|
||||
orderItemVO.setAfterSaleStatus(groupAfterSaleStatus.split(",")[i]);
|
||||
}
|
||||
}
|
||||
if (CharSequenceUtil.isNotEmpty(groupComplainStatus) && groupComplainStatus.split(",").length == groupGoodsId.split(",").length) {
|
||||
orderItemVO.setComplainStatus(groupComplainStatus.split(",")[i]);
|
||||
@@ -211,5 +223,11 @@ public class OrderSimpleVO {
|
||||
return new AllowOperation(this);
|
||||
}
|
||||
|
||||
|
||||
public String getGroupAfterSaleStatus() {
|
||||
// 不可售后的订单类型集合
|
||||
if (!OrderPromotionTypeEnum.isCanAfterSale(this.orderPromotionType)) {
|
||||
return OrderItemAfterSaleStatusEnum.EXPIRED.name();
|
||||
}
|
||||
return groupAfterSaleStatus;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user