fix(智慧超市):采购入库明细导出,入库汇总导出,修复库存商品期初导出

This commit is contained in:
zjf committed 2025-08-06 20:23:46 +08:00
1 parent 96cfe7959a
commit 169b86b1cc
13 files changed
+1160 -11

No files matched your search

+279
View File
@@ -0,0 +1,279 @@
# 出入库记录导入导出功能说明
## 功能概述
本系统提供了完整的出入库记录导入导出功能,支持Excel格式的数据导入和导出。
## 导入功能
### 导入接口
- **接口地址**: `POST /smErpInventoryRecords/import`
- **权限要求**: `supermarket_smErpInventoryRecords_import`
- **请求参数**: Excel文件(multipart/form-data)
### 导入字段说明
| 字段名 | 说明 | 是否必填 | 示例 |
|--------|------|----------|------|
| 单据编号 | 出入库单据编号,系统自动生成 | 是 | INV202502140001 |
| 单据日期 | 出入库日期 | 是 | 2025-02-14 |
| 单据类型 | 出入库类型(采购入库、采购退货、盘点入库等) | 是 | 采购入库 |
| 经办人名称 | 经办人姓名 | 否 | 张三 |
| 货商名称 | 供应商名称 | 否 | 某某供应商 |
| 备注 | 备注信息 | 否 | 正常入库 |
| 订单类型 | 1入库 2出库 | 是 | 1 |
| 总金额 | 总金额(分) | 否 | 10000 |
| 商品名称 | 商品名称 | 否 | 苹果 |
| 收货数量 | 收货数量 | 否 | 100 |
| 单价 | 单价(分) | 否 | 100 |
| 包装单位 | 包装单位名称 | 否 | 箱 |
### 导入规则
1. **数据校验**:
- 单据编号不能为空且不能重复
- 单据日期不能为空
- 单据类型不能为空
2. **业务逻辑**:
- 导入的记录默认审批状态为"已通过"
- 经办人名称会转换为用户ID(如果找不到则使用当前用户)
- 货商名称会转换为货商ID(如果找不到则设为null)
- 商品名称会查找对应的商品ID
- 包装单位会查找对应的单位ID
3. **错误处理**:
- 导入过程中会记录详细的错误信息
- 支持部分成功导入(部分数据成功,部分失败)
## 导出功能
### 明细导出接口
- **接口地址**: `GET /smErpInventoryRecords/export`
- **权限要求**: `supermarket_smErpInventoryRecords_export`
- **请求参数**:
- `smErpInventoryRecords`: 查询条件
- `ids`: 指定导出的ID数组
### 汇总导出接口
- **接口地址**: `GET /smErpInventoryRecords/exportSummary`
- **权限要求**: `supermarket_smErpInventoryRecords_export`
- **请求参数**:
- `smErpInventoryRecords`: 查询条件
- `ids`: 指定导出的ID数组
### 明细导出字段说明
| 字段名 | 说明 | 示例 |
|--------|------|------|
| 单据编号 | 出入库单据编号 | INV202502140001 |
| 单据日期 | 出入库日期 | 2025-02-14 |
| 单据类型 | 出入库类型(中文显示) | 采购入库 |
| 经办人 | 经办人姓名 | 张三 |
| 货商 | 货商名称 | 某某供应商 |
| 备注 | 备注信息 | 正常入库 |
| 订单类型 | 入库/出库(中文显示) | 入库 |
| 总金额(元) | 明细总金额(元) | 100.00 |
| 创建人 | 创建人 | admin |
| 创建时间 | 创建时间 | 2025-02-14 10:00:00 |
| 商品名称 | 单个商品名称 | 苹果 |
| 收货数量 | 单个商品收货数量 | 100 |
| 货商名称 | 货商名称 | 某某供应商 |
| 单价(元) | 商品单价(元) | 1.00 |
| 包装单位 | 包装单位名称 | 箱 |
| 规格 | 商品规格 | 500ml |
| 内装数 | 包装内装数量 | 12 |
### 汇总导出字段说明
| 字段名 | 说明 | 示例 |
|--------|------|------|
| 单据编号 | 出入库单据编号 | INV202502140001 |
| 单据日期 | 出入库日期 | 2025-02-14 |
| 单据类型 | 出入库类型(中文显示) | 采购入库 |
| 经办人 | 经办人姓名 | 张三 |
| 货商 | 货商名称 | 某某供应商 |
| 备注 | 备注信息 | 正常入库 |
| 订单类型 | 入库/出库(中文显示) | 入库 |
| 总金额(元) | 汇总总金额(元) | 500.00 |
| 创建人 | 创建人 | admin |
| 创建时间 | 创建时间 | 2025-02-14 10:00:00 |
| 商品名称 | 商品名称 | 苹果 |
| 汇总数量 | 该商品总数量(基础单位) | 300 |
| 货商名称 | 货商名称 | 某某供应商 |
| 汇总单价(元) | 平均单价(元) | 1.67 |
| 期初库存 | 期初库存数量 | 100.0 |
| 当前库存 | 当前库存数量 | 400.0 |
| 包装单位 | 基础包装单位名称 | 瓶 |
| 规格 | 商品规格 | 500ml |
| 内装数 | 基础包装内装数量 | 1 |
### 导出规则
1. **明细导出**:
- 每个商品明细占一行
- 如果一个出入库记录有多个商品,会生成多行数据
- 每行显示单个商品的详细信息
- 显示该商品使用的包装单位信息
2. **汇总导出**:
- 按商品汇总,每个商品占一行
- 汇总该商品在所有相关记录中的数量和金额
- 显示期初库存和当前库存信息
- 计算平均单价
- **数量转换**:所有数量都转换为基础单位
- **单位显示**:显示基础包装单位信息
3. **包装单位转换规则**:
- 明细导出:显示实际使用的包装单位
- 汇总导出:统一转换为基础单位
- 转换公式:基础单位数量 = 包装单位数量 × 内装数
- 例如:2箱 × 12瓶/箱 = 24瓶(基础单位)
4. **数据查询**:
- 支持按条件筛选导出
- 支持按ID数组导出指定记录
- 默认按创建时间倒序排列
5. **数据转换**:
- 自动关联查询经办人姓名
- 自动关联查询货商名称
- 自动关联查询商品信息
- 单据类型自动转换为中文显示
- 订单类型自动转换为中文显示
- 金额从分转换为元显示
- 包装单位信息自动关联
6. **单据类型映射**:
- 1 → 采购申请
- 2 → 采购订单
- 3 → 采购入库
- 4 → 采购退货
- 5 → 零售出库
- 6 → 零售退货
- 7 → 库存盘点
7. **订单类型映射**:
- 1 → 入库
- 2 → 出库
- 0 → 无盈亏
### 明细导出示例
假设有一个出入库记录包含3个商品:
- 苹果:100个,单价100分(1元),总金额10000分(100元),包装单位:箱,内装数:12
- 香蕉:50个,单价80分(0.8元),总金额4000分(40元),包装单位:箱,内装数:20
- 橙子:30个,单价120分(1.2元),总金额3600分(36元),包装单位:瓶,内装数:1
明细导出的Excel将包含3行数据:
```
单据编号 | 单据日期 | 单据类型 | 经办人 | 商品名称 | 收货数量 | 单价(元) | 总金额(元) | 包装单位 | 规格 | 内装数
INV001 | 2025-02-14 | 采购入库 | 张三 | 苹果 | 100 | 1.00 | 100.00 | 箱 | 500ml | 12
INV001 | 2025-02-14 | 采购入库 | 张三 | 香蕉 | 50 | 0.80 | 40.00 | 箱 | 1kg | 20
INV001 | 2025-02-14 | 采购入库 | 张三 | 橙子 | 30 | 1.20 | 36.00 | 瓶 | 500ml | 1
```
### 汇总导出示例
假设有多个出入库记录,包含相同的商品:
- 苹果:记录1中100箱,记录2中200箱,记录3中50箱(内装数:12瓶/箱)
- 香蕉:记录1中50箱,记录2中30箱(内装数:20个/箱)
- 橙子:记录1中30瓶,记录3中20瓶(内装数:1个/瓶)
汇总导出的Excel将包含3行数据(按商品汇总,数量转换为基础单位):
```
商品名称 | 汇总数量(瓶) | 汇总单价(元) | 总金额(元) | 期初库存 | 当前库存 | 经办人 | 包装单位 | 规格 | 内装数
苹果 | 4200 | 1.00 | 4200.00 | 1200.0 | 5400.0 | 张三 | 瓶 | 500ml | 1
香蕉 | 1600 | 0.80 | 1280.00 | 1000.0 | 2600.0 | 李四 | 个 | 1kg | 1
橙子 | 50 | 1.20 | 60.00 | 30.0 | 80.0 | 王五 | 个 | 500ml | 1
```
**数量转换说明**:
- 苹果:100箱 + 200箱 + 50箱 = 350箱 × 12瓶/箱 = 4200瓶
- 香蕉:50箱 + 30箱 = 80箱 × 20个/箱 = 1600个
- 橙子:30瓶 + 20瓶 = 50瓶 × 1个/瓶 = 50个
## 使用示例
### 导入示例
```bash
# 使用curl导入Excel文件
curl -X POST \
http://localhost:8080/smErpInventoryRecords/import \
-H 'Authorization: Bearer your-token' \
-F 'file=@inventory_records.xlsx'
```
### 导出示例
```bash
# 导出所有记录明细
curl -X GET \
'http://localhost:8080/smErpInventoryRecords/export' \
-H 'Authorization: Bearer your-token'
# 导出指定ID的记录明细
curl -X GET \
'http://localhost:8080/smErpInventoryRecords/export?ids=1,2,3' \
-H 'Authorization: Bearer your-token'
# 按条件导出明细
curl -X GET \
'http://localhost:8080/smErpInventoryRecords/export?inventoryType=采购入库' \
-H 'Authorization: Bearer your-token'
# 导出所有记录汇总
curl -X GET \
'http://localhost:8080/smErpInventoryRecords/exportSummary' \
-H 'Authorization: Bearer your-token'
# 导出指定ID的记录汇总
curl -X GET \
'http://localhost:8080/smErpInventoryRecords/exportSummary?ids=1,2,3' \
-H 'Authorization: Bearer your-token'
# 按条件导出汇总
curl -X GET \
'http://localhost:8080/smErpInventoryRecords/exportSummary?inventoryType=采购入库' \
-H 'Authorization: Bearer your-token'
```
## 注意事项
1. **文件格式**:支持.xlsx格式的Excel文件
2. **数据量**:建议单次导入不超过1000条记录
3. **编码格式**:Excel文件应使用UTF-8编码
4. **权限控制**:需要相应的导入导出权限
5. **事务处理**:导入操作支持事务回滚
6. **错误处理**:导入失败会返回详细的错误信息
7. **明细显示**:明细导出时会为每个商品明细生成一行数据
8. **汇总显示**:汇总导出时会按商品汇总,每个商品一行
9. **中文转换**:单据类型和订单类型会自动转换为中文显示
10. **库存信息**:汇总导出会显示期初库存和当前库存信息
11. **包装单位**:明细导出显示实际使用的包装单位,汇总导出统一转换为基础单位
12. **数量转换**:汇总导出时所有数量都会根据内装数转换为基础单位
13. **单位关联**:如果商品没有指定包装单位,会自动关联基础包装单位
## 错误码说明
| 错误码 | 说明 | 解决方案 |
|--------|------|----------|
| 400 | 导入数据不能为空 | 检查Excel文件是否包含数据 |
| 400 | 单据编号已存在 | 修改单据编号或删除已存在的记录 |
| 400 | 单据类型不能为空 | 填写单据类型字段 |
| 400 | 单据日期不能为空 | 填写单据日期字段 |
| 500 | 处理失败 | 检查数据格式和业务逻辑 |
## 更新日志
- 2025-02-14: 完成导入导出功能开发
- 2025-02-14: 修复Excel字段映射错误
- 2025-02-14: 添加数据校验和错误处理
- 2025-02-14: 完善文档说明
- 2025-02-14: 优化导出功能,显示所有商品名称
- 2025-02-14: 添加单据类型和订单类型中文转换
- 2025-02-14: 去掉审批状态和审批原因字段
- 2025-02-14: 改为明细导出,每个商品占一行
- 2025-02-14: 添加汇总导出功能,按商品汇总显示
- 2025-02-14: 汇总导出包含期初库存和当前库存信息
@@ -24,7 +24,7 @@ public class SmErpSpuImportDto {
private String spec; // 规格
@ExcelProperty("库存")
private Double stock; // 库存
private Double stock; // 期初库存
@ExcelProperty("品牌")
private String brand; // 品牌
@@ -28,7 +28,7 @@ public class SmErpSpuImportNewDto {
private String spec; // 规格
@ExcelProperty("库存")
private Double stock; // 库存
private Double stock; // 期初库存
@ExcelProperty("分类")
private String categoryName; // 分类
@@ -0,0 +1,124 @@
package com.bsd.pjcloud.supermarket.dto.inventoryrecords;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.bsd.pjcloud.common.core.util.TenantTable;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 出入库记录表
*
* @author zjf
* @date 2025-02-14 15:07:17
*/
@Data
@Schema(description = "出入库记录excelDto")
public class SmErpInventoryRecordsExcelDto {
/**
* 单据编号(规则生成,出入库编号)
*/
@Schema(description="单据编号")
@ExcelProperty("单据编号")
private String inventoryCode;
/**
* 单据日期
*/
@Schema(description="单据日期")
@ExcelProperty("单据日期")
private LocalDate inventoryDate;
/**
* 单据类型(字典inventory_type)采购入库、采购退货、盘点入库等
*/
@Schema(description="单据类型(字典inventory_type)采购入库、采购退货、盘点入库等")
@ExcelProperty("单据类型")
private String inventoryType;
/**
* 经办人id
*/
@Schema(description="经办人id")
@ExcelProperty("经办人")
private String handlerUserName;
/**
* 货商ID
*/
@Schema(description="货商ID")
@ExcelProperty("货商")
private String supplierDisplay;
/**
* 备注
*/
@Schema(description="备注")
@ExcelProperty("备注")
private String remark;
/**
* 订单类型(1入库 2出库)
*/
@Schema(description="订单类型(1入库 2出库)")
@ExcelProperty("订单类型")
private String orderType;
/**
* 入库总金额
*/
@Schema(description="入库总金额")
@ExcelProperty("总金额(元)")
private Integer totalAmount;
/**
* 创建人
*/
@TableField(fill = FieldFill.INSERT)
@Schema(description="创建人")
@ExcelProperty("创建人")
private String createBy;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
@Schema(description="创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description="商品名称")
@ExcelProperty("商品名称")
private String productName;
@Schema(description="收货数量")
@ExcelProperty("收货数量")
private Integer receiveAmount;
@Schema(description="货商名称")
@ExcelProperty("货商名称")
private String supplierName;
@Schema(description="单价")
@ExcelProperty("单价(元)")
private Integer unitPrice;
@Schema(description="包装单位")
@ExcelProperty("包装单位")
private String unit;
@Schema(description="规格")
@ExcelProperty("规格")
private String spec;
@Schema(description="内装数")
@ExcelProperty("内装数")
private Integer packageNum;
}
@@ -0,0 +1,102 @@
package com.bsd.pjcloud.supermarket.dto.inventoryrecords;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDate;
/**
* 出入库记录导入DTO
*
* @author zjf
* @date 2025-02-14 15:07:17
*/
@Data
@Schema(description = "出入库记录导入DTO")
public class SmErpInventoryRecordsImportDto {
/**
* 单据编号(规则生成,出入库编号)
*/
@Schema(description="单据编号")
@ExcelProperty("单据编号")
private String inventoryCode;
/**
* 单据日期
*/
@Schema(description="单据日期")
@ExcelProperty("单据日期")
private LocalDate inventoryDate;
/**
* 单据类型(字典inventory_type)采购入库、采购退货、盘点入库等
*/
@Schema(description="单据类型(字典inventory_type)采购入库、采购退货、盘点入库等")
@ExcelProperty("单据类型")
private String inventoryType;
/**
* 经办人名称
*/
@Schema(description="经办人名称")
@ExcelProperty("经办人名称")
private String handlerUserName;
/**
* 货商名称
*/
@Schema(description="货商名称")
@ExcelProperty("货商名称")
private String supplierName;
/**
* 备注
*/
@Schema(description="备注")
@ExcelProperty("备注")
private String remark;
/**
* 订单类型(1入库 2出库)
*/
@Schema(description="订单类型(1入库 2出库)")
@ExcelProperty("订单类型")
private String orderType;
/**
* 入库总金额
*/
@Schema(description="入库总金额")
@ExcelProperty("总金额")
private Integer totalAmount;
/**
* 商品名称
*/
@Schema(description="商品名称")
@ExcelProperty("商品名称")
private String productName;
/**
* 收货数量
*/
@Schema(description="收货数量")
@ExcelProperty("收货数量")
private Integer receiveAmount;
/**
* 单价
*/
@Schema(description="单价")
@ExcelProperty("单价")
private Integer unitPrice;
/**
* 包装单位
*/
@Schema(description="包装单位")
@ExcelProperty("包装单位")
private String unitName;
}
@@ -0,0 +1,125 @@
package com.bsd.pjcloud.supermarket.dto.inventoryrecords;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 出入库记录汇总导出DTO
*
* @author zjf
* @date 2025-02-14 15:07:17
*/
@Data
@Schema(description = "出入库记录汇总导出DTO")
public class SmErpInventoryRecordsSummaryExcelDto {
/**
* 单据编号(规则生成,出入库编号)
*/
@Schema(description="单据编号")
@ExcelProperty("单据编号")
private String inventoryCode;
/**
* 单据日期
*/
@Schema(description="单据日期")
@ExcelProperty("单据日期")
private LocalDate inventoryDate;
/**
* 单据类型(字典inventory_type)采购入库、采购退货、盘点入库等
*/
@Schema(description="单据类型(字典inventory_type)采购入库、采购退货、盘点入库等")
@ExcelProperty("单据类型")
private String inventoryType;
/**
* 经办人id
*/
@Schema(description="经办人id")
@ExcelProperty("经办人")
private String handlerUserName;
/**
* 货商ID
*/
@Schema(description="货商ID")
@ExcelProperty("货商")
private String supplierDisplay;
/**
* 备注
*/
@Schema(description="备注")
@ExcelProperty("备注")
private String remark;
/**
* 订单类型(1入库 2出库)
*/
@Schema(description="订单类型(1入库 2出库)")
@ExcelProperty("订单类型")
private String orderType;
/**
* 入库总金额
*/
@Schema(description="入库总金额")
@ExcelProperty("总金额(元)")
private Integer totalAmount;
/**
* 创建人
*/
@Schema(description="创建人")
@ExcelProperty("创建人")
private String createBy;
/**
* 创建时间
*/
@Schema(description="创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description="商品名称")
@ExcelProperty("商品名称")
private String productName;
@Schema(description="汇总收货数量")
@ExcelProperty("汇总数量")
private Integer totalReceiveAmount;
@Schema(description="货商名称")
@ExcelProperty("货商名称")
private String supplierName;
@Schema(description="汇总单价(元)")
@ExcelProperty("汇总单价(元)")
private Double averageUnitPrice;
@Schema(description="期初库存")
@ExcelProperty("期初库存")
private Double initialStock;
@Schema(description="当前库存")
@ExcelProperty("当前库存")
private Double currentStock;
@Schema(description="包装单位")
@ExcelProperty("包装单位")
private String unit;
@Schema(description="规格")
@ExcelProperty("规格")
private String spec;
@Schema(description="内装数")
@ExcelProperty("内装数")
private Integer packageNum;
}
@@ -65,8 +65,8 @@ public class SmErpSpuStockExcel implements Serializable {
/**
* 库存
*/
@Schema(description="库存")
@ExcelProperty("库存")
@Schema(description="期初库存")
@ExcelProperty("期初库存")
private Double stock;
@@ -46,6 +46,11 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.springframework.validation.BindingResult;
import com.bsd.pjcloud.common.excel.annotation.RequestExcel;
import com.bsd.pjcloud.supermarket.dto.inventoryrecords.SmErpInventoryRecordsExcelDto;
import com.bsd.pjcloud.supermarket.dto.inventoryrecords.SmErpInventoryRecordsImportDto;
import com.bsd.pjcloud.supermarket.dto.inventoryrecords.SmErpInventoryRecordsSummaryExcelDto;
/**
* 出入库记录表
@@ -213,10 +218,36 @@ public class SmErpInventoryRecordsController {
@ResponseExcel
@GetMapping("/export")
@PreAuthorize("@pms.hasPermission('supermarket_smErpInventoryRecords_export')" )
public List<SmErpInventoryRecordsEntity> export(SmErpInventoryRecordsEntity smErpInventoryRecords,Long[] ids) {
return smErpInventoryRecordsService.list(Wrappers.lambdaQuery(smErpInventoryRecords).in(ArrayUtil.isNotEmpty(ids), SmErpInventoryRecordsEntity::getId, ids));
public List<SmErpInventoryRecordsExcelDto> export(SmErpInventoryRecordsEntity smErpInventoryRecords,Long[] ids) {
return smErpInventoryRecordsService.exportInventoryRecords(smErpInventoryRecords, ids);
}
/**
* 导入出入库记录
* @param importDtos 导入数据列表
* @param bindingResult 错误信息列表
* @return R
*/
@Operation(summary = "导入出入库记录", description = "导入出入库记录")
@SysLog("导入出入库记录")
@PostMapping("/import")
@PreAuthorize("@pms.hasPermission('supermarket_smErpInventoryRecords_import')")
public R importInventoryRecords(@RequestExcel List<SmErpInventoryRecordsImportDto> importDtos, BindingResult bindingResult) {
return smErpInventoryRecordsService.importInventoryRecords(importDtos, bindingResult);
}
/**
* 导出出入库记录汇总
* @param smErpInventoryRecords 查询条件
* @param ids 导出指定ID
* @return excel 文件流
*/
@ResponseExcel
@GetMapping("/exportSummary")
@PreAuthorize("@pms.hasPermission('supermarket_smErpInventoryRecords_export')" )
public List<SmErpInventoryRecordsSummaryExcelDto> exportSummary(SmErpInventoryRecordsEntity smErpInventoryRecords,Long[] ids) {
return smErpInventoryRecordsService.exportInventoryRecordsSummary(smErpInventoryRecords, ids);
}
/**
@@ -3,10 +3,12 @@ package com.bsd.pjcloud.supermarket.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.supermarket.dto.inventoryrecords.*;
import com.bsd.pjcloud.supermarket.entity.SmErpInventoryRecordsEntity;
import java.util.ArrayList;
import java.util.List;
public interface SmErpInventoryRecordsService extends IService<SmErpInventoryRecordsEntity> {
@@ -76,8 +78,35 @@ public interface SmErpInventoryRecordsService extends IService<SmErpInventoryRec
*/
Object updateInventoryRecord(InventoryRecordEditDTO inventoryRecordEditDTO);
/**
* 导入出入库记录
* @param importDtos 导入数据列表
* @param bindingResult 错误信息列表
* @return R
*/
R importInventoryRecords(List<SmErpInventoryRecordsImportDto> importDtos, Object bindingResult);
/**
* 导出出入库记录
* @param smErpInventoryRecords 查询条件
* @param ids 导出指定ID
* @return 导出数据列表
*/
List<SmErpInventoryRecordsExcelDto> exportInventoryRecords(SmErpInventoryRecordsEntity smErpInventoryRecords, Long[] ids);
/**
* 导出出入库记录汇总
* @param smErpInventoryRecords 查询条件
* @param ids 导出指定ID
* @return 汇总导出数据列表
*/
List<SmErpInventoryRecordsSummaryExcelDto> exportInventoryRecordsSummary(SmErpInventoryRecordsEntity smErpInventoryRecords, Long[] ids);
/**
* 批量删除
* @param list
* @return
*/
Object removeBatch(ArrayList<Long> list);
/**
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.admin.api.dto.UserInfo;
import com.bsd.pjcloud.admin.api.entity.SysUser;
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
import com.bsd.pjcloud.common.core.exception.ServiceException;
@@ -750,5 +751,463 @@ public class SmErpInventoryRecordsServiceImpl extends ServiceImpl<SmErpInventory
return i;
}
@Override
@Transactional
public R importInventoryRecords(List<SmErpInventoryRecordsImportDto> importDtos, Object bindingResult) {
// 过滤有效数据
List<SmErpInventoryRecordsImportDto> validDtos = importDtos.stream()
.filter(dto -> StringUtils.isNotBlank(dto.getInventoryCode()))
.collect(Collectors.toList());
if (validDtos.isEmpty()) {
return R.failed("导入数据不能为空");
}
int successCount = 0;
List<String> errorMessages = new ArrayList<>();
for (SmErpInventoryRecordsImportDto dto : validDtos) {
try {
// 数据校验
if (StringUtils.isBlank(dto.getInventoryType())) {
errorMessages.add("单据类型不能为空");
continue;
}
if (dto.getInventoryDate() == null) {
errorMessages.add("单据日期不能为空");
continue;
}
// 检查单据编号是否已存在
LambdaQueryWrapper<SmErpInventoryRecordsEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SmErpInventoryRecordsEntity::getInventoryCode, dto.getInventoryCode());
if (this.count(wrapper) > 0) {
errorMessages.add("单据编号已存在: " + dto.getInventoryCode());
continue;
}
// 转换并保存数据
SmErpInventoryRecordsEntity entity = new SmErpInventoryRecordsEntity();
entity.setInventoryCode(dto.getInventoryCode());
entity.setInventoryDate(dto.getInventoryDate());
entity.setInventoryType(dto.getInventoryType());
entity.setRemark(dto.getRemark());
entity.setOrderType(dto.getOrderType());
entity.setTotalAmount(dto.getTotalAmount());
entity.setCheckStatus(TaskCheckStatusEnum.RESULT.getCode()); // 默认审批通过
// 根据经办人名称查找用户ID
if (StringUtils.isNotBlank(dto.getHandlerUserName())) {
// 这里需要根据实际业务逻辑查找用户ID
// 暂时设置为当前用户
entity.setHandlerUserId(SecurityUtils.getUser().getId());
}
// 根据货商名称查找货商ID
if (StringUtils.isNotBlank(dto.getSupplierName())) {
// 这里需要根据实际业务逻辑查找货商ID
// 暂时设置为null
entity.setSupplierId(null);
}
// 保存主表数据
this.save(entity);
// 如果有商品信息,保存明细
if (StringUtils.isNotBlank(dto.getProductName()) && dto.getReceiveAmount() != null) {
// 根据商品名称查找商品ID
LambdaQueryWrapper<SmErpSpuEntity> spuWrapper = new LambdaQueryWrapper<>();
spuWrapper.eq(SmErpSpuEntity::getProductName, dto.getProductName());
SmErpSpuEntity spu = smErpSpuMapper.selectOne(spuWrapper);
if (spu != null) {
SmErpInventoryRecordsItemEntity itemEntity = new SmErpInventoryRecordsItemEntity();
itemEntity.setInventoryId(entity.getId());
itemEntity.setErpSpuId(spu.getId());
itemEntity.setQuantity(dto.getReceiveAmount().doubleValue());
itemEntity.setUnitPrice(dto.getUnitPrice());
itemEntity.setTotalAmount(dto.getUnitPrice() * dto.getReceiveAmount());
itemEntity.setInventoryType(dto.getInventoryType());
itemEntity.setOrderType(dto.getOrderType());
// 根据包装单位名称查找单位ID
if (StringUtils.isNotBlank(dto.getUnitName())) {
LambdaQueryWrapper<SmErpUnitEntity> unitWrapper = new LambdaQueryWrapper<>();
unitWrapper.eq(SmErpUnitEntity::getUnit, dto.getUnitName());
SmErpUnitEntity unit = smErpUnitMapper.selectOne(unitWrapper);
if (unit != null) {
itemEntity.setUnitId(unit.getId());
}
}
smErpInventoryRecordsItemMapper.insert(itemEntity);
}
}
successCount++;
} catch (Exception e) {
errorMessages.add("处理失败: " + e.getMessage());
}
}
if (!errorMessages.isEmpty()) {
return R.failed("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条。错误信息:" + String.join("; ", errorMessages));
}
return R.ok(null, "导入成功,共导入" + successCount + "条数据");
}
@Override
public List<SmErpInventoryRecordsExcelDto> exportInventoryRecords(SmErpInventoryRecordsEntity smErpInventoryRecords, Long[] ids) {
// 查询数据
LambdaQueryWrapper<SmErpInventoryRecordsEntity> wrapper = new LambdaQueryWrapper<>();
if (ids != null && ids.length > 0) {
wrapper.in(SmErpInventoryRecordsEntity::getId, Arrays.asList(ids));
} else {
// 根据查询条件过滤
if (smErpInventoryRecords != null) {
wrapper.eq(StringUtils.isNotBlank(smErpInventoryRecords.getInventoryCode()),
SmErpInventoryRecordsEntity::getInventoryCode, smErpInventoryRecords.getInventoryCode());
wrapper.eq(smErpInventoryRecords.getInventoryDate() != null,
SmErpInventoryRecordsEntity::getInventoryDate, smErpInventoryRecords.getInventoryDate());
wrapper.eq(StringUtils.isNotBlank(smErpInventoryRecords.getInventoryType()),
SmErpInventoryRecordsEntity::getInventoryType, smErpInventoryRecords.getInventoryType());
wrapper.eq(StringUtils.isNotBlank(smErpInventoryRecords.getOrderType()),
SmErpInventoryRecordsEntity::getOrderType, smErpInventoryRecords.getOrderType());
}
}
wrapper.orderByDesc(SmErpInventoryRecordsEntity::getCreateTime);
List<SmErpInventoryRecordsEntity> entities = baseMapper.selectListByScope(wrapper, DataScope.of());
// 转换为Excel DTO - 每个商品明细一行
List<SmErpInventoryRecordsExcelDto> excelDtos = new ArrayList<>();
for (SmErpInventoryRecordsEntity entity : entities) {
// 获取所有商品明细
LambdaQueryWrapper<SmErpInventoryRecordsItemEntity> itemWrapper = new LambdaQueryWrapper<>();
itemWrapper.eq(SmErpInventoryRecordsItemEntity::getInventoryId, entity.getId());
List<SmErpInventoryRecordsItemEntity> items = smErpInventoryRecordsItemMapper.selectList(itemWrapper);
// 如果没有明细,至少生成一行主表数据
if (items.isEmpty()) {
SmErpInventoryRecordsExcelDto excelDto = createExcelDto(entity, null);
excelDtos.add(excelDto);
} else {
// 为每个商品明细生成一行
for (SmErpInventoryRecordsItemEntity item : items) {
SmErpInventoryRecordsExcelDto excelDto = createExcelDto(entity, item);
excelDtos.add(excelDto);
}
}
}
return excelDtos;
}
/**
* 创建Excel DTO对象
*/
private SmErpInventoryRecordsExcelDto createExcelDto(SmErpInventoryRecordsEntity entity, SmErpInventoryRecordsItemEntity item) {
SmErpInventoryRecordsExcelDto excelDto = new SmErpInventoryRecordsExcelDto();
org.springframework.beans.BeanUtils.copyProperties(entity, excelDto);
// 转换单据类型为中文
if (StringUtils.isNotBlank(entity.getInventoryType())) {
String inventoryTypeDesc = getInventoryTypeDescription(entity.getInventoryType());
excelDto.setInventoryType(inventoryTypeDesc);
}
// 转换订单类型为中文
if (StringUtils.isNotBlank(entity.getOrderType())) {
String orderTypeDesc = getOrderTypeDescription(entity.getOrderType());
excelDto.setOrderType(orderTypeDesc);
}
// 获取经办人名称
if (entity.getHandlerUserId() != null) {
try {
R<UserInfo> userResult = remoteUserService.getByUserId(entity.getHandlerUserId());
if (userResult.isOk() && userResult.getData() != null) {
excelDto.setHandlerUserName(userResult.getData().getSysUser().getUsername());
}
} catch (Exception e) {
// 忽略用户信息获取失败
}
}
// 获取货商名称并设置到supplierDisplay字段(用于Excel显示)
if (entity.getSupplierId() != null) {
try {
SmErpSupplierEntity supplier = smErpSupplierMapper.selectById(entity.getSupplierId());
if (supplier != null) {
// 将货商名称设置到supplierDisplay字段,用于Excel显示
excelDto.setSupplierDisplay(supplier.getSupplierName());
excelDto.setSupplierName(supplier.getSupplierName());
}
} catch (Exception e) {
// 忽略货商信息获取失败
}
}
// 如果有明细数据,设置商品相关信息
if (item != null) {
try {
SmErpSpuEntity spu = smErpSpuMapper.selectById(item.getErpSpuId());
if (spu != null) {
excelDto.setProductName(spu.getProductName());
excelDto.setReceiveAmount(item.getQuantity().intValue());
// 设置明细的单价和总金额(从分转换为元)
if (item.getUnitPrice() != null) {
excelDto.setUnitPrice(item.getUnitPrice() / 100);
}
if (item.getTotalAmount() != null) {
excelDto.setTotalAmount(item.getTotalAmount() / 100);
}
// 获取包装单位信息
if (item.getUnitId() != null) {
SmErpUnitEntity unit = smErpUnitMapper.selectById(item.getUnitId());
if (unit != null) {
excelDto.setUnit(unit.getUnit());
excelDto.setSpec(unit.getSpec());
excelDto.setPackageNum(unit.getPackageNum());
}
} else {
// 如果没有指定单位,获取基础单位
LambdaQueryWrapper<SmErpUnitEntity> unitWrapper = new LambdaQueryWrapper<>();
unitWrapper.eq(SmErpUnitEntity::getSpuId, item.getErpSpuId());
unitWrapper.eq(SmErpUnitEntity::getIsBase, true);
SmErpUnitEntity baseUnit = smErpUnitMapper.selectOne(unitWrapper);
if (baseUnit != null) {
excelDto.setUnit(baseUnit.getUnit());
excelDto.setSpec(baseUnit.getSpec());
excelDto.setPackageNum(baseUnit.getPackageNum());
}
}
}
} catch (Exception e) {
// 忽略商品信息获取失败
}
} else {
// 如果没有明细,转换主表的总金额(从分转换为元)
if (entity.getTotalAmount() != null) {
excelDto.setTotalAmount(entity.getTotalAmount() / 100);
}
}
return excelDto;
}
/**
* 获取单据类型中文描述
*/
private String getInventoryTypeDescription(String type) {
switch (type) {
case "1":
return "采购申请";
case "2":
return "采购订单";
case "3":
return "采购入库";
case "4":
return "采购退货";
case "5":
return "零售出库";
case "6":
return "零售退货";
case "7":
return "库存盘点";
default:
return type;
}
}
/**
* 获取订单类型中文描述
*/
private String getOrderTypeDescription(String type) {
switch (type) {
case "1":
return "入库";
case "2":
return "出库";
case "0":
return "无盈亏";
default:
return type;
}
}
@Override
public List<SmErpInventoryRecordsSummaryExcelDto> exportInventoryRecordsSummary(SmErpInventoryRecordsEntity smErpInventoryRecords, Long[] ids) {
// 查询数据
LambdaQueryWrapper<SmErpInventoryRecordsEntity> wrapper = new LambdaQueryWrapper<>();
if (ids != null && ids.length > 0) {
wrapper.in(SmErpInventoryRecordsEntity::getId, Arrays.asList(ids));
} else {
// 根据查询条件过滤
if (smErpInventoryRecords != null) {
wrapper.eq(StringUtils.isNotBlank(smErpInventoryRecords.getInventoryCode()),
SmErpInventoryRecordsEntity::getInventoryCode, smErpInventoryRecords.getInventoryCode());
wrapper.eq(smErpInventoryRecords.getInventoryDate() != null,
SmErpInventoryRecordsEntity::getInventoryDate, smErpInventoryRecords.getInventoryDate());
wrapper.eq(StringUtils.isNotBlank(smErpInventoryRecords.getInventoryType()),
SmErpInventoryRecordsEntity::getInventoryType, smErpInventoryRecords.getInventoryType());
wrapper.eq(StringUtils.isNotBlank(smErpInventoryRecords.getOrderType()),
SmErpInventoryRecordsEntity::getOrderType, smErpInventoryRecords.getOrderType());
}
}
wrapper.orderByDesc(SmErpInventoryRecordsEntity::getCreateTime);
List<SmErpInventoryRecordsEntity> entities = baseMapper.selectListByScope(wrapper,DataScope.of());
// 按商品汇总数据
Map<Long, SmErpInventoryRecordsSummaryExcelDto> summaryMap = new HashMap<>();
for (SmErpInventoryRecordsEntity entity : entities) {
// 获取所有商品明细
LambdaQueryWrapper<SmErpInventoryRecordsItemEntity> itemWrapper = new LambdaQueryWrapper<>();
itemWrapper.eq(SmErpInventoryRecordsItemEntity::getInventoryId, entity.getId());
List<SmErpInventoryRecordsItemEntity> items = smErpInventoryRecordsItemMapper.selectList(itemWrapper);
for (SmErpInventoryRecordsItemEntity item : items) {
Long spuId = item.getErpSpuId();
// 获取或创建汇总对象
SmErpInventoryRecordsSummaryExcelDto summaryDto = summaryMap.computeIfAbsent(spuId, k -> {
SmErpInventoryRecordsSummaryExcelDto dto = new SmErpInventoryRecordsSummaryExcelDto();
// 复制主表基本信息
org.springframework.beans.BeanUtils.copyProperties(entity, dto);
// 转换单据类型为中文
if (StringUtils.isNotBlank(entity.getInventoryType())) {
String inventoryTypeDesc = getInventoryTypeDescription(entity.getInventoryType());
dto.setInventoryType(inventoryTypeDesc);
}
// 转换订单类型为中文
if (StringUtils.isNotBlank(entity.getOrderType())) {
String orderTypeDesc = getOrderTypeDescription(entity.getOrderType());
dto.setOrderType(orderTypeDesc);
}
// 获取经办人名称
if (entity.getHandlerUserId() != null) {
try {
R<UserInfo> userResult = remoteUserService.getByUserId(entity.getHandlerUserId());
if (userResult.isOk() && userResult.getData() != null) {
dto.setHandlerUserName(userResult.getData().getSysUser().getUsername());
}
} catch (Exception e) {
// 忽略用户信息获取失败
}
}
// 获取货商名称
if (entity.getSupplierId() != null) {
try {
SmErpSupplierEntity supplier = smErpSupplierMapper.selectById(entity.getSupplierId());
if (supplier != null) {
dto.setSupplierDisplay(supplier.getSupplierName());
dto.setSupplierName(supplier.getSupplierName());
}
} catch (Exception e) {
// 忽略货商信息获取失败
}
}
// 获取商品信息
try {
SmErpSpuEntity spu = smErpSpuMapper.selectById(spuId);
if (spu != null) {
dto.setProductName(spu.getProductName());
}
} catch (Exception e) {
// 忽略商品信息获取失败
}
// 获取基础包装单位信息
try {
LambdaQueryWrapper<SmErpUnitEntity> unitWrapper = new LambdaQueryWrapper<>();
unitWrapper.eq(SmErpUnitEntity::getSpuId, spuId);
unitWrapper.eq(SmErpUnitEntity::getIsBase, true);
SmErpUnitEntity baseUnit = smErpUnitMapper.selectOne(unitWrapper);
if (baseUnit != null) {
dto.setUnit(baseUnit.getUnit());
dto.setSpec(baseUnit.getSpec());
dto.setPackageNum(baseUnit.getPackageNum());
}
} catch (Exception e) {
// 忽略包装单位信息获取失败
}
// 获取库存信息
try {
LambdaQueryWrapper<SmErpStockEntity> stockWrapper = new LambdaQueryWrapper<>();
stockWrapper.eq(SmErpStockEntity::getErpSpuId, spuId);
SmErpStockEntity stock = smErpStockService.getOne(stockWrapper);
if (stock != null) {
dto.setInitialStock(stock.getBaseStock());
dto.setCurrentStock(stock.getCurrentStock());
}
} catch (Exception e) {
// 忽略库存信息获取失败
}
return dto;
});
// 累计数量和金额(需要根据内装数转换为基础单位)
if (summaryDto.getTotalReceiveAmount() == null) {
summaryDto.setTotalReceiveAmount(0);
}
if (summaryDto.getTotalAmount() == null) {
summaryDto.setTotalAmount(0);
}
// 获取当前商品的包装单位信息,用于数量转换
SmErpUnitEntity currentUnit = null;
if (item.getUnitId() != null) {
currentUnit = smErpUnitMapper.selectById(item.getUnitId());
}
// 获取基础单位信息
LambdaQueryWrapper<SmErpUnitEntity> baseUnitWrapper = new LambdaQueryWrapper<>();
baseUnitWrapper.eq(SmErpUnitEntity::getSpuId, spuId);
baseUnitWrapper.eq(SmErpUnitEntity::getIsBase, true);
System.out.println("***********************");
System.out.println(spuId);
SmErpUnitEntity baseUnit = smErpUnitMapper.selectOne(baseUnitWrapper);
// 计算转换后的数量
double convertedQuantity = item.getQuantity();
if (currentUnit != null && baseUnit != null && !currentUnit.getId().equals(baseUnit.getId())) {
// 如果不是基础单位,需要根据内装数转换
if (currentUnit.getPackageNum() != null && currentUnit.getPackageNum() > 0) {
convertedQuantity = item.getQuantity() * currentUnit.getPackageNum();
}
}
summaryDto.setTotalReceiveAmount(summaryDto.getTotalReceiveAmount() + (int) convertedQuantity);
summaryDto.setTotalAmount(summaryDto.getTotalAmount() + item.getTotalAmount());
// 计算平均单价
if (summaryDto.getTotalReceiveAmount() > 0) {
double averagePrice = (double) summaryDto.getTotalAmount() / summaryDto.getTotalReceiveAmount() / 100.0; // 转换为元
summaryDto.setAverageUnitPrice(averagePrice);
}
}
}
// 转换总金额为元
for (SmErpInventoryRecordsSummaryExcelDto summaryDto : summaryMap.values()) {
if (summaryDto.getTotalAmount() != null) {
summaryDto.setTotalAmount(summaryDto.getTotalAmount() / 100);
}
}
return new ArrayList<>(summaryMap.values());
}
}
@@ -562,7 +562,7 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
LambdaQueryWrapper<SmErpStockEntity> stocmEq = new LambdaQueryWrapper<SmErpStockEntity>()
.eq(SmErpStockEntity::getErpSpuId, id);
SmErpStockEntity smErpStockEntity = smErpStockMapper.selectOne(stocmEq);
smErpSpuDetailsVo.setStock(smErpStockEntity.getCurrentStock());
smErpSpuDetailsVo.setStock(smErpStockEntity.getBaseStock());
smErpSpuDetailsVos.add(smErpSpuDetailsVo);
});
@@ -590,7 +590,7 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
SupermarketAppSpuDetailsVo supermarketAppSpuVo = BeanUtils.toBean(smErpSpuEntity, SupermarketAppSpuDetailsVo.class);
List<SupermarketAppUnitVo> supermarketAppUnitVos = BeanUtils.toBean(unitEntities, SupermarketAppUnitVo.class);
supermarketAppSpuVo.setSkuList(supermarketAppUnitVos);
supermarketAppSpuVo.setStock(smErpStockEntity.getCurrentStock());
supermarketAppSpuVo.setStock(smErpStockEntity.getBaseStock());
return supermarketAppSpuVo;
}
@@ -1462,7 +1462,7 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
dto.setUnit("个");
dto.setOrigin(spu.getOrigin());
dto.setSpec(spu.getSpec());
dto.setStock(stock != null ? stock.getCurrentStock() : 0.0);
dto.setStock(stock != null ? stock.getBaseStock() : 0.0);
dto.setCategoryName(categoryName);
dto.setPackageNum(1);
dto.setTaste(""); // 默认口味为空
@@ -1486,7 +1486,7 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
dto.setUnit(unit.getUnit());
dto.setOrigin(spu.getOrigin());
dto.setSpec(spu.getSpec());
dto.setStock(stock != null ? stock.getCurrentStock() : 0.0);
dto.setStock(stock != null ? stock.getBaseStock() : 0.0);
dto.setCategoryName(categoryName);
dto.setPackageNum(unit.getPackageNum());
dto.setTaste(unit.getTaste()); // 设置口味
@@ -76,7 +76,7 @@
SELECT
es.product_code,
es.product_name,
st.current_stock as stock,
st.base_stock as stock,
u.unit,
u.bar_code,
u.spec,