Commit b9c85d55 by yubin

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/Inventory.java
#	ruoyi-inventory/src/main/java/com/ruoyi/inventory/mapper/StorageLocationsMapper.java
#	ruoyi-inventory/src/main/resources/mapper/inventory/InventoryMapper.xml
parents 19bd4ddb 835ab1b5
import request from '@/utils/request'
// 查询库存列表
export function listInventoryCount(query) {
return request({
url: '/inventory/inventory/listCount',
method: 'get',
params: query
})
}
// 查询库存列表
export function listInventory(query) {
return request({
url: '/inventory/inventory/list',
......
......@@ -83,7 +83,6 @@
<div class="table-container">
<el-table v-loading="loading" :data="statisticsList" border height="100%">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="物料ID" align="center" prop="materialId" width="150" />
<el-table-column label="物料名称" align="center" prop="materialName" min-width="150" show-overflow-tooltip />
<el-table-column label="入库次数" align="center" prop="inboundCount" width="100" />
<el-table-column label="出库次数" align="center" prop="outboundCount" width="100" />
......
......@@ -3,6 +3,14 @@
<!-- 标题栏 + 操作按钮 -->
<PageTitle>
<template #buttons>
<!-- <el-button
type="info"
plain
icon="el-icon-upload2"
size="medium"
@click="handleImport"
v-hasPermi="['inventory:inventory:import']"
>导入</el-button> -->
<el-button
type="warning"
plain
......@@ -10,7 +18,7 @@
size="medium"
@click="handleExport"
v-hasPermi="['inventory:inventory:export']"
>导出Excel</el-button>
>导出</el-button>
</template>
</PageTitle>
......@@ -18,7 +26,7 @@
<div class="page-container">
<!-- 查询表单 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="仓库" prop="warehousesCode">
<el-form-item label="仓库" prop="warehousesId">
<el-input
v-model="queryWarehouseName"
placeholder="请选择仓库"
......@@ -53,10 +61,10 @@
</template>
</el-input>
</el-form-item>
<el-form-item label="物料" prop="materialId">
<el-form-item label="SAP物料号" prop="materialId">
<el-input
v-model="queryParams.materialId"
placeholder="请输入物料ID或编码"
placeholder="请输入物料编码"
clearable
@keyup.enter.native="handleQuery"
/>
......@@ -78,7 +86,7 @@
</template>
</el-input>
</el-form-item>
<el-form-item label="库存类别" prop="inventoryType">
<!-- <el-form-item label="库存类别" prop="inventoryType">
<el-select v-model="queryParams.inventoryType" placeholder="请选择库存类别" clearable>
<el-option
v-for="item in inventoryTypeOptions"
......@@ -87,7 +95,7 @@
:value="item.value"
/>
</el-select>
</el-form-item>
</el-form-item> -->
<el-form-item label="入库批次号" prop="batchId">
<el-input
v-model="queryParams.batchId"
......@@ -106,7 +114,7 @@
/>
</el-select>
</el-form-item>
<el-form-item label="库存状态" prop="inventoryStatus">
<!-- <el-form-item label="库存状态" prop="inventoryStatus">
<el-select v-model="queryParams.inventoryStatus" placeholder="请选择库存状态" clearable>
<el-option
v-for="item in inventoryStatusOptions"
......@@ -115,7 +123,7 @@
:value="item.value"
/>
</el-select>
</el-form-item>
</el-form-item> -->
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">检索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
......@@ -127,77 +135,36 @@
<div class="table-container">
<el-table v-loading="loading" :data="inventoryList" border height="100%">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="库存编号" align="center" prop="id" width="150" />
<el-table-column label="库存类别" align="center" prop="inventoryType" width="100">
<el-table-column label="物料名称" align="center" prop="materialName" width="150" />
<el-table-column label="SAP物料号" align="center" prop="sapNo" width="120" />
<el-table-column label="TS Code" align="center" prop="tsCode" width="120" />
<el-table-column label="危险类别" align="center" prop="hazard" width="120" />
<el-table-column label="规格型号" align="center" prop="specification" width="120" />
<el-table-column label="计量单位" align="center" prop="materialUnit" width="120" />
<el-table-column label="单位重量" align="center" prop="unitWeight" width="120" >
<template slot-scope="scope">
<el-tag :type="scope.row.inventoryType === 1 ? 'primary' : 'warning'" size="small">
{{ getInventoryTypeName(scope.row.inventoryType) }}
</el-tag>
{{ formatAmount(scope.row.unitWeight || 0) }}
</template>
</el-table-column>
<el-table-column label="入库单号" align="center" prop="orderId" width="150" />
<el-table-column label="物料ID" align="center" prop="materialId" width="150" />
<el-table-column label="批次ID" align="center" prop="batchId" width="120" />
<el-table-column label="仓库编码" align="center" prop="warehousesCode" width="120" />
<el-table-column label="库位ID" align="center" prop="locationId" width="120" />
<el-table-column label="货主ID" align="center" prop="ownerId" width="120" />
<el-table-column label="库存数量" align="center" prop="quantity" width="100" />
<el-table-column label="锁定数量" align="center" prop="lockedQuantity" width="100" />
<el-table-column label="库存数量" align="center" prop="totalQuantity" width="100" />
<el-table-column label="锁定数量" align="center" prop="totalLockedQuantity" width="100" />
<el-table-column label="可用数量" align="center" width="100">
<template slot-scope="scope">
{{ (scope.row.quantity || 0) - (scope.row.lockedQuantity || 0) }}
</template>
</el-table-column>
<el-table-column label="单位重量" align="center" prop="unitWeight" width="100">
<template slot-scope="scope">
{{ formatWeight(scope.row.unitWeight) }}
</template>
</el-table-column>
<el-table-column label="总重量" align="center" prop="totalWeight" width="100">
<template slot-scope="scope">
{{ formatWeight(scope.row.totalWeight) }}
</template>
</el-table-column>
<el-table-column label="总体积" align="center" prop="totalVolume" width="100">
<template slot-scope="scope">
{{ formatVolume(scope.row.totalVolume) }}
</template>
</el-table-column>
<el-table-column label="生产日期" align="center" prop="productionDate" width="120">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.productionDate, '{y}-{m}-{d}') }}</span>
{{ (scope.row.totalQuantity || 0) - (scope.row.totalLockedQuantity || 0) }}
</template>
</el-table-column>
<el-table-column label="失效日期" align="center" prop="expirationDate" width="120">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.expirationDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="库存状态" align="center" prop="inventoryStatus" width="100">
<el-table-column label="最低库存" align="center" prop="minStockLevel" width="100" />
<el-table-column label="最高库存" align="center" prop="maxStockLevel" width="100" />
<el-table-column label="预警状态" align="center" prop="alterType" width="100">
<template slot-scope="scope">
<el-tag
:type="getStatusType(scope.row.inventoryStatus)"
:type="getWarnStatusType(scope.row.alterType)"
size="small"
>
{{ getStatusName(scope.row.inventoryStatus) }}
{{ getWarnStatusName(scope.row.alterType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="最后入库时间" align="center" prop="lastInboundTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.lastInboundTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="最后出库时间" align="center" prop="lastOutboundTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.lastOutboundTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100" fixed="right">
<template slot-scope="scope">
<el-button
......@@ -237,6 +204,14 @@
:warehousesId="queryParams.warehouseId"
@selected="handleLocationSelected"
/>
<ImportExcel
ref="import"
title="库存导入"
import-url="/inventory/inventory/import"
template-url="inventory/inventory/export"
template-name="inventory_importTemplate"
@success="getList"
/>
<!-- 物料明细弹窗 -->
<el-dialog
......@@ -254,20 +229,16 @@
max-height="600"
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="库存编号" align="center" prop="id" width="150" />
<el-table-column label="库存类别" align="center" prop="inventoryType" width="100">
<template slot-scope="scope">
<el-tag :type="scope.row.inventoryType === 1 ? 'primary' : 'warning'" size="small">
{{ getInventoryTypeName(scope.row.inventoryType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="入库单号" align="center" prop="orderId" width="150" />
<el-table-column label="物料ID" align="center" prop="materialId" width="150" />
<el-table-column label="批次ID" align="center" prop="batchId" width="120" />
<el-table-column label="仓库编码" align="center" prop="warehousesCode" width="120" />
<el-table-column label="库位ID" align="center" prop="locationId" width="120" />
<el-table-column label="货主ID" align="center" prop="ownerId" width="120" />
<el-table-column label="物料名称" align="center" prop="materialName" width="150" />
<el-table-column label="SAP物料号" align="center" prop="sapNo" width="120" />
<el-table-column label="TS Code" align="center" prop="tsCode" width="120" />
<el-table-column label="危险类别" align="center" prop="hazard" width="120" />
<!-- <el-table-column label="规格型号" align="center" prop="specification" width="120" /> -->
<!-- <el-table-column label="入库单号" align="center" prop="orderId" width="150" /> -->
<el-table-column label="批次" align="center" prop="batchId" width="120" />
<el-table-column label="仓库" align="center" prop="warehousesName" width="120" />
<el-table-column label="库位" align="center" prop="locationName" width="120" />
<el-table-column label="货主" align="center" prop="ownerName" width="120" />
<el-table-column label="库存数量" align="center" prop="quantity" width="100" />
<el-table-column label="锁定数量" align="center" prop="lockedQuantity" width="100" />
<el-table-column label="可用数量" align="center" width="100">
......@@ -275,63 +246,6 @@
{{ (scope.row.quantity || 0) - (scope.row.lockedQuantity || 0) }}
</template>
</el-table-column>
<el-table-column label="单位重量" align="center" prop="unitWeight" width="100">
<template slot-scope="scope">
{{ formatWeight(scope.row.unitWeight) }}
</template>
</el-table-column>
<el-table-column label="总重量" align="center" prop="totalWeight" width="100">
<template slot-scope="scope">
{{ formatWeight(scope.row.totalWeight) }}
</template>
</el-table-column>
<el-table-column label="总体积" align="center" prop="totalVolume" width="100">
<template slot-scope="scope">
{{ formatVolume(scope.row.totalVolume) }}
</template>
</el-table-column>
<el-table-column label="生产日期" align="center" prop="productionDate" width="120">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.productionDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="失效日期" align="center" prop="expirationDate" width="120">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.expirationDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="库存状态" align="center" prop="inventoryStatus" width="100">
<template slot-scope="scope">
<el-tag
:type="getStatusType(scope.row.inventoryStatus)"
size="small"
>
{{ getStatusName(scope.row.inventoryStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="最后入库时间" align="center" prop="lastInboundTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.lastInboundTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="最后出库时间" align="center" prop="lastOutboundTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.lastOutboundTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建人代码" align="center" prop="createUserCode" width="120" />
<el-table-column label="更新时间" align="center" prop="updateTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.updateTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="更新人代码" align="center" prop="updateUserCode" width="120" />
</el-table>
<div slot="footer" class="dialog-footer">
<el-button @click="detailDialogVisible = false">关闭</el-button>
......@@ -341,12 +255,13 @@
</template>
<script>
import { listInventory, exportInventory } from "@/api/inventory/inventory"
import { listInventoryCount, listInventoryDetail, exportInventory } from "@/api/inventory/inventory"
import RightToolbar from "@/components/RightToolbar"
import PageTitle from "@/components/PageTitle"
import OwnerSelector from "@/views/compononents/OwnerSelector.vue"
import WarehouseSelector from "@/views/compononents/WarehouseSelector.vue"
import LocationSelector from "@/views/compononents/LocationSelector.vue"
import ImportExcel from "@/components/ImportExcel"
export default {
name: "InventoryDetail",
......@@ -355,7 +270,8 @@ export default {
PageTitle,
OwnerSelector,
WarehouseSelector,
LocationSelector
LocationSelector,
ImportExcel
},
data() {
return {
......@@ -374,13 +290,13 @@ export default {
],
// 预警类型选项
alertTypeOptions: [
{ value: 'all', label: '全部预警' },
{ value: 'over', label: '超量预警' },
{ value: 'under', label: '不足预警' }
{ value: '0', label: '全部预警' },
{ value: '1', label: '超量预警' },
{ value: '2', label: '不足预警' }
],
// 库存状态选项(0-已出库 1-正常)
inventoryStatusOptions: [
{ value: 0, label: '出库' },
{ value: 0, label: '出库' },
{ value: 1, label: '正常' }
],
// 查询参数
......@@ -420,7 +336,7 @@ export default {
/** 查询库存明细列表 */
getList() {
this.loading = true
listInventory(this.queryParams).then(response => {
listInventoryCount(this.queryParams).then(response => {
this.inventoryList = response.rows || []
this.total = response.total || 0
this.loading = false
......@@ -523,6 +439,16 @@ export default {
const item = this.inventoryStatusOptions.find(item => item.value === status)
return item ? item.label : '未知'
},
/** 获取预警样式类型 */
getWarnStatusType(status) {
const item = this.alertTypeOptions.find(item => item.value === status)
return item ? (status === 3 ? 'info' : 'warning') : 'info'
},
/** 获取预警状态名称 */
getWarnStatusName(status) {
const item = this.alertTypeOptions.find(item => item.value === status)
return item ? item.label : '正常'
},
/** 格式化重量 */
formatWeight(weight) {
if (weight === null || weight === undefined || isNaN(weight)) {
......@@ -537,6 +463,13 @@ export default {
}
return parseFloat(volume).toFixed(2)
},
/** 格式化金额,保留2位小数 */
formatAmount(amount) {
if (amount === null || amount === undefined || isNaN(amount)) {
return '0'
}
return parseFloat(amount).toFixed(2)
},
/** 查看明细 */
handleViewDetail(row) {
this.currentDetailRow = row
......@@ -549,7 +482,7 @@ export default {
// 根据当前行的物料ID、仓库、库位、货主等信息查询明细
const params = {
materialId: row.materialId,
warehousesCode: row.warehousesCode,
warehousesId: row.warehousesId,
locationId: row.locationId,
ownerId: row.ownerId,
batchId: row.batchId,
......@@ -559,7 +492,7 @@ export default {
pageSize: 10000 // 设置一个很大的值,不分页
}
listInventory(params).then(response => {
listInventoryDetail(params).then(response => {
this.detailList = response.rows || []
this.detailLoading = false
}).catch(() => {
......@@ -572,9 +505,13 @@ export default {
delete params.pageNum
delete params.pageSize
this.download('inventory/inventory/export', {
this.download('inventory/inventory/exportExcel', {
...params
}, `库存明细数据_${new Date().getTime()}.xlsx`)
},
/** 导入库存数据 */
handleImport() {
this.$refs.import && this.$refs.import.show()
}
}
}
......
package com.ruoyi.inventory.controller;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.vo.InventoryExceedWarnVO;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.alibaba.excel.EasyExcel;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.Materials;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.inventory.domain.Inventory;
import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.StorageLocations;
import com.ruoyi.inventory.domain.Warehouses;
import com.ruoyi.inventory.domain.vo.InventoryExceedWarnVO;
import com.ruoyi.inventory.domain.vo.InventorySummaryVO;
import com.ruoyi.inventory.domain.vo.InventoryVo;
import com.ruoyi.inventory.mapper.MaterialsMapper;
import com.ruoyi.inventory.mapper.StorageLocationsMapper;
import com.ruoyi.inventory.mapper.WarehousesMapper;
import com.ruoyi.inventory.service.IInventoryService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* 库存Controller
*
......@@ -36,6 +45,15 @@ public class InventoryController extends BaseController
@Autowired
private IInventoryService inventoryService;
@Autowired
private MaterialsMapper materialsMapper;
@Autowired
private WarehousesMapper warehousesMapper;
@Autowired
private StorageLocationsMapper storageLocationsMapper;
/**
* 查询库存列表
*/
......@@ -101,18 +119,21 @@ public class InventoryController extends BaseController
@PostMapping("/exportExcel")
public void exportExcel(HttpServletResponse response, Inventory inventory)
{
try {
List<InventorySummaryVO> list = inventoryService.selectInventorySummaryList(inventory);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = "库存明细数据_" + System.currentTimeMillis() + ".xlsx";
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + java.net.URLEncoder.encode(fileName, "UTF-8"));
EasyExcel.write(response.getOutputStream(), InventorySummaryVO.class)
.sheet("库存明细")
.doWrite(list);
} catch (Exception e) {
e.printStackTrace();
}
List<InventoryVo> list = inventoryService.selectInventoryVoList(inventory);
ExcelUtil<InventoryVo> util = new ExcelUtil<InventoryVo>(InventoryVo.class);
util.exportExcel(response, list, "库存数据");
// try {
// List<InventorySummaryVO> list = inventoryService.selectInventorySummaryList(inventory);
// response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
// response.setCharacterEncoding("utf-8");
// String fileName = "库存明细数据_" + System.currentTimeMillis() + ".xlsx";
// response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + java.net.URLEncoder.encode(fileName, "UTF-8"));
// EasyExcel.write(response.getOutputStream(), InventorySummaryVO.class)
// .sheet("库存明细")
// .doWrite(list);
// } catch (Exception e) {
// e.printStackTrace();
// }
}
/**
......@@ -171,6 +192,137 @@ public class InventoryController extends BaseController
}
/**
* Excel 导入库存(表头占第1行,从第2行开始数据)
* 表头:日期、SAPNo、物料名称、TS Code、批号、计划数量、件重、约数、件数、件重、库位、仓库
* 规则:
* - SAPNo 查物料表取 material_id
* - 仓库名称查仓库表取 warehouses_code、id
* - 库位名称+仓库ID 查库位表取 location_id
* - 计划数量 -> quantity,件重(首个) -> unit_weight,第二个件重 -> total_weight(若存在)
* - 日期 -> last_inbound_time
*/
@PreAuthorize("@ss.hasPermi('inventory:inventory:import')")
@Log(title = "库存导入", businessType = BusinessType.IMPORT)
@PostMapping("/import")
public AjaxResult importInventory(@RequestParam("file") MultipartFile file) {
if (file == null || file.isEmpty()) {
return error("上传文件为空");
}
try {
List<Map<Integer, String>> rows = EasyExcel.read(file.getInputStream())
.headRowNumber(1)
.sheet()
.doReadSync();
if (rows == null || rows.isEmpty()) {
return error("未读取到数据");
}
List<Inventory> toInsert = new ArrayList<>();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
for (int i = 0; i < rows.size(); i++) {
Map<Integer, String> row = rows.get(i);
// 基础字段取值
String dateStr = row.get(0);
String sapNo = row.get(1);
String batchId = row.get(4);
String planQtyStr = row.get(5);
String unitWeightStr = row.get(6);
String secondWeightStr = row.get(9);
String locationName = row.get(10);
String warehouseName = row.get(11);
if (StringUtils.isEmpty(sapNo)) {
return error("第" + (i + 2) + "行SAPNo为空");
}
List<Materials> materialsList = materialsMapper.selectMaterialsBySapNo(sapNo);
if (materialsList == null || materialsList.isEmpty()) {
return error("第" + (i + 2) + "行SAPNo未找到物料:" + sapNo);
}
Materials materials = materialsList.get(0);
if (StringUtils.isEmpty(warehouseName)) {
return error("第" + (i + 2) + "行仓库名称为空");
}
Warehouses warehouses = warehousesMapper.selectWarehousesByName(warehouseName);
if (warehouses == null) {
return error("第" + (i + 2) + "行仓库未找到:" + warehouseName);
}
if (StringUtils.isEmpty(locationName)) {
return error("第" + (i + 2) + "行库位名称为空");
}
StorageLocations location = storageLocationsMapper.selectStorageLocationsByNameAndWarehouse(locationName, warehouses.getId());
if (location == null) {
return error("第" + (i + 2) + "行库位未找到:" + locationName + "(仓库:" + warehouseName + ")");
}
Integer qty = parseInteger(planQtyStr, "计划数量", i);
Double unitWeight = parseDouble(unitWeightStr);
Double totalWeight = parseDouble(secondWeightStr);
Inventory inventory = new Inventory();
inventory.setId(UUID.randomUUID().toString());
inventory.setInventoryType(1L);
inventory.setOrderId(null);
inventory.setMaterialId(materials.getId());
inventory.setBatchId(batchId);
inventory.setWarehousesCode(warehouses.getWarehousesCode());
inventory.setLocationId(location.getId());
inventory.setQuantity(qty == null ? 0 : qty.longValue());
inventory.setLockedQuantity(0L);
inventory.setUnitWeight(unitWeight == null ? null : Math.round(unitWeight));
inventory.setTotalWeight(totalWeight == null ? null : Math.round(totalWeight));
inventory.setInventoryStatus(1L);
inventory.setIsUsed(1L);
inventory.setCreateTime(new Date());
inventory.setLastInboundTime(parseDate(sdf, dateStr));
toInsert.add(inventory);
}
int count = inventoryService.insertInventoryList(toInsert);
return success("导入成功,新增记录数:" + count);
} catch (IOException e) {
return error("读取文件失败:" + e.getMessage());
}
}
private Integer parseInteger(String val, String field, int rowIndex) {
if (StringUtils.isEmpty(val)) {
return null;
}
try {
return (int) Double.parseDouble(val);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("第" + (rowIndex + 2) + "行" + field + "格式错误:" + val);
}
}
private Double parseDouble(String val) {
if (StringUtils.isEmpty(val)) {
return null;
}
try {
return Double.parseDouble(val);
} catch (NumberFormatException e) {
return null;
}
}
private Date parseDate(SimpleDateFormat sdf, String val) {
if (StringUtils.isEmpty(val)) {
return null;
}
try {
return sdf.parse(val);
} catch (ParseException e) {
return null;
}
}
/**
* 统计库存物料超出预警值
*/
@GetMapping("/exceed")
......
package com.ruoyi.inventory.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.inventory.domain.vo.InboundOutboundStatisticsVO;
import com.ruoyi.inventory.service.IInventoryStatisticsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 出入库统计
*/
@RestController
@RequestMapping("/inventory/statistics")
public class InventoryStatisticsController extends BaseController {
@Autowired
private IInventoryStatisticsService inventoryStatisticsService;
/**
* 出入库统计列表
*/
@PreAuthorize("@ss.hasPermi('inventory:statistics:list')")
@GetMapping("/inboundOutbound")
public TableDataInfo list(InboundOutboundStatisticsVO query) {
startPage();
List<InboundOutboundStatisticsVO> list = inventoryStatisticsService.selectInboundOutboundStatistics(query);
return getDataTable(list);
}
/**
* 导出出入库统计
*/
@PreAuthorize("@ss.hasPermi('inventory:statistics:export')")
@Log(title = "出入库统计", businessType = BusinessType.EXPORT)
@PostMapping("/inboundOutbound/export")
public void export(HttpServletResponse response, InboundOutboundStatisticsVO query) {
List<InboundOutboundStatisticsVO> list = inventoryStatisticsService.selectInboundOutboundStatistics(query);
ExcelUtil<InboundOutboundStatisticsVO> util = new ExcelUtil<>(InboundOutboundStatisticsVO.class);
util.exportExcel(response, list, "出入库统计数据");
}
}
package com.ruoyi.inventory.domain;
import java.util.Date;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.annotation.Excel;
......@@ -13,6 +16,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
* @author ruoyi
* @date 2025-12-03
*/
@Data
public class Inventory extends BaseEntity
{
private static final long serialVersionUID = 1L;
......@@ -121,54 +125,6 @@ public class Inventory extends BaseEntity
/** 预警类型 */
private String alertType;
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public String getMaterialName() {
return materialName;
}
public void setMaterialName(String materialName) {
this.materialName = materialName;
}
public String getWarehousesName() {
return warehousesName;
}
public void setWarehousesName(String warehousesName) {
this.warehousesName = warehousesName;
}
public String getLocationName() {
return locationName;
}
public void setLocationName(String locationName) {
this.locationName = locationName;
}
public String getWarehousesCode() {
return warehousesCode;
}
public void setWarehousesCode(String warehousesCode) {
this.warehousesCode = warehousesCode;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
public String getWarehousesId() {
return warehousesId;
}
......@@ -177,70 +133,55 @@ public class Inventory extends BaseEntity
this.warehousesId = warehousesId;
}
public void setId(String id)
{
this.id = id;
}
/** 最低库存 */
private Long minStockLevel;
/** 最高库存 */
private Long maxStockLevel;
public String getId()
{
return id;
}
/** SAP物料号 */
@Excel(name = "SAP物料号")
private String sapNo;
public void setInventoryType(Long inventoryType)
{
this.inventoryType = inventoryType;
}
/** TS Code */
@Excel(name = "TS Code")
private String tsCode;
public Long getInventoryType()
{
return inventoryType;
}
/** 危险类别 */
private String hazardId;
public void setOrderId(String orderId)
{
this.orderId = orderId;
}
/** 危险类别 */
@Excel(name = "危险类别")
private String hazard;
public String getOrderId()
{
return orderId;
}
/** 规格型号 */
@Excel(name = "规格型号")
private String specification;
public void setMaterialId(String materialId)
{
this.materialId = materialId;
}
/** 计量单位 */
@Excel(name = "计量单位")
private String materialUnit;
public String getMaterialId()
{
return materialId;
}
/** 包装重量 */
// @Excel(name = "包装重量")
private Double packageWeight;
public void setBatchId(String batchId)
{
this.batchId = batchId;
}
/** 体积 */
private Double volume;
public String getBatchId()
{
return batchId;
}
/** 保质期天数 */
private Integer shelfLifeDays;
public void setLocationId(String locationId)
{
this.locationId = locationId;
}
/** 存储温度要求 */
// @Excel(name = "存储温度要求")
private String storageTemperature;
public String getLocationId()
{
return locationId;
}
/** 特殊存储要求 */
// @Excel(name = "特殊存储要求")
private String specialRequirements;
public void setOwnerId(String ownerId)
{
this.ownerId = ownerId;
}
private String warehousesName;
private String locationName;
private String ownerName;
public String getOwnerId()
{
......@@ -387,6 +328,16 @@ public class Inventory extends BaseEntity
return updateUserCode;
}
public void setWarehousesCode(String warehousesCode)
{
this.warehousesCode = warehousesCode;
}
public String getWarehousesCode()
{
return warehousesCode;
}
public void setAlertType(String alertType)
{
this.alertType = alertType;
......@@ -403,17 +354,10 @@ public class Inventory extends BaseEntity
.append("id", getId())
.append("inventoryType", getInventoryType())
.append("orderId", getOrderId())
.append("orderName", getOrderName())
.append("materialId", getMaterialId())
.append("materialName", getMaterialName())
.append("batchId", getBatchId())
.append("warehousesId", getWarehousesId())
.append("warehousesName", getWarehousesName())
.append("warehousesCode", getWarehousesCode())
.append("locationId", getLocationId())
.append("locationName", getLocationName())
.append("ownerId", getOwnerId())
.append("ownerName", getOwnerName())
.append("quantity", getQuantity())
.append("lockedQuantity", getLockedQuantity())
.append("unitWeight", getUnitWeight())
......@@ -430,7 +374,6 @@ public class Inventory extends BaseEntity
.append("createUserCode", getCreateUserCode())
.append("updateTime", getUpdateTime())
.append("updateUserCode", getUpdateUserCode())
.append("alertType", getAlertType())
.toString();
}
}
package com.ruoyi.inventory.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* 出入库统计视图对象
* 按物料汇总入库/出库次数、数量及金额
*/
@Data
public class InboundOutboundStatisticsVO extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 物料ID */
// @Excel(name = "物料ID")
private String materialId;
/** 物料名称 */
@Excel(name = "物料名称")
private String materialName;
/** 入库次数 */
@Excel(name = "入库次数")
private Integer inboundCount;
/** 出库次数 */
@Excel(name = "出库次数")
private Integer outboundCount;
/** 入库数量 */
@Excel(name = "入库数量")
private BigDecimal inboundQuantity;
/** 出库数量 */
@Excel(name = "出库数量")
private BigDecimal outboundQuantity;
/** 入库总额 */
@Excel(name = "入库总额")
private BigDecimal inboundAmount;
/** 出库总额 */
@Excel(name = "出库总额")
private BigDecimal outboundAmount;
/** 金额差(入库-出库) */
@Excel(name = "总额差")
private BigDecimal amountDiff;
/** 开始日期(主表日期过滤) */
@JsonFormat(pattern = "yyyy-MM-dd")
private Date startDate;
/** 结束日期(主表日期过滤) */
@JsonFormat(pattern = "yyyy-MM-dd")
private Date endDate;
/** 仓库ID */
private String warehouseId;
/** 仓库编码(支持模糊) */
private String warehousesCode;
/** 库位ID */
private String locationId;
/** 物料编码/ID查询 */
private String materialCode;
}
......@@ -5,6 +5,7 @@ import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import com.alibaba.excel.enums.poi.FillPatternTypeEnum;
import com.ruoyi.common.annotation.Excel;
import lombok.Data;
//import org.apache.poi.ss.usermodel.FillPatternType;
......@@ -32,176 +33,72 @@ public class InventorySummaryVO implements Serializable
@ExcelProperty(value = "物料名称", index = 1)
private String materialName;
/** 库存类别 */
@ExcelProperty(value = "库存类别", index = 2)
private String inventoryTypeName;
/** 最低库存 */
private Long minStockLevel;
/** 最高库存 */
private Long maxStockLevel;
/** 仓库编码 */
@ExcelProperty(value = "仓库编码", index = 3)
private String warehousesCode;
/** SAP物料号 */
@Excel(name = "SAP物料号")
private String sapNo;
/** 仓库名称 */
@ExcelProperty(value = "仓库名称", index = 4)
private String warehouseName;
/** TS Code */
@Excel(name = "TS Code")
private String tsCode;
/** 库位ID */
@ExcelProperty(value = "库位ID", index = 5)
private String locationId;
/** 危险类别 */
private String hazardId;
/** 库位名称 */
@ExcelProperty(value = "库位名称", index = 6)
private String locationName;
/** 危险类别 */
@Excel(name = "危险类别")
private String hazard;
/** 货主ID */
@ExcelProperty(value = "货主ID", index = 7)
private String ownerId;
/** 规格型号 */
@Excel(name = "规格型号")
private String specification;
/** 货主名称 */
@ExcelProperty(value = "货主名称", index = 8)
private String ownerName;
/** 计量单位 */
@Excel(name = "计量单位")
private String materialUnit;
/** 总库存数量 */
@ExcelProperty(value = "总库存数量", index = 9)
private Long totalQuantity;
/** 单位重量 */
@Excel(name = "单位重量")
private Double unitWeight;
/** 总锁定数量 */
@ExcelProperty(value = "总锁定数量", index = 10)
private Long totalLockedQuantity;
/** 总可用数量 */
@ExcelProperty(value = "总可用数量", index = 11)
private Long totalAvailableQuantity;
/** 包装重量 */
// @Excel(name = "包装重量")
private Double packageWeight;
/** 总重量 */
@ExcelProperty(value = "总重量", index = 12)
private Double totalWeight;
/** 总体积 */
@ExcelProperty(value = "总体积", index = 13)
private Double totalVolume;
/** 库存状态 */
@ExcelProperty(value = "库存状态", index = 14)
private String inventoryStatusName;
public String getMaterialId() {
return materialId;
}
public void setMaterialId(String materialId) {
this.materialId = materialId;
}
public String getMaterialName() {
return materialName;
}
public void setMaterialName(String materialName) {
this.materialName = materialName;
}
public String getInventoryTypeName() {
return inventoryTypeName;
}
public void setInventoryTypeName(String inventoryTypeName) {
this.inventoryTypeName = inventoryTypeName;
}
public String getWarehousesCode() {
return warehousesCode;
}
public void setWarehousesCode(String warehousesCode) {
this.warehousesCode = warehousesCode;
}
public String getWarehouseName() {
return warehouseName;
}
public void setWarehouseName(String warehouseName) {
this.warehouseName = warehouseName;
}
/** 体积 */
private Double volume;
public String getLocationId() {
return locationId;
}
/** 保质期天数 */
private Integer shelfLifeDays;
public void setLocationId(String locationId) {
this.locationId = locationId;
}
/** 存储温度要求 */
// @Excel(name = "存储温度要求")
private String storageTemperature;
public String getLocationName() {
return locationName;
}
/** 特殊存储要求 */
// @Excel(name = "特殊存储要求")
private String specialRequirements;
public void setLocationName(String locationName) {
this.locationName = locationName;
}
public String getOwnerId() {
return ownerId;
}
public void setOwnerId(String ownerId) {
this.ownerId = ownerId;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
public Long getTotalQuantity() {
return totalQuantity;
}
public void setTotalQuantity(Long totalQuantity) {
this.totalQuantity = totalQuantity;
}
public Long getTotalLockedQuantity() {
return totalLockedQuantity;
}
public void setTotalLockedQuantity(Long totalLockedQuantity) {
this.totalLockedQuantity = totalLockedQuantity;
}
public Long getTotalAvailableQuantity() {
return totalAvailableQuantity;
}
public void setTotalAvailableQuantity(Long totalAvailableQuantity) {
this.totalAvailableQuantity = totalAvailableQuantity;
}
public Double getTotalWeight() {
return totalWeight;
}
public void setTotalWeight(Double totalWeight) {
this.totalWeight = totalWeight;
}
/** 总库存数量 */
@ExcelProperty(value = "总库存数量", index = 9)
private Long totalQuantity;
public Double getTotalVolume() {
return totalVolume;
}
/** 总锁定数量 */
@ExcelProperty(value = "总锁定数量", index = 10)
private Long totalLockedQuantity;
public void setTotalVolume(Double totalVolume) {
this.totalVolume = totalVolume;
}
/** 总可用数量 */
@ExcelProperty(value = "总可用数量", index = 11)
private Long totalAvailableQuantity;
public String getInventoryStatusName() {
return inventoryStatusName;
}
private String alterType;
public void setInventoryStatusName(String inventoryStatusName) {
this.inventoryStatusName = inventoryStatusName;
}
}
package com.ruoyi.inventory.domain.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.Date;
/**
* 库存对象 inventory
*
* @author cy
* @date 2025-12-03
*/
@Data
public class InventoryVo extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 编号 */
private String id;
/** 库存类别1普通2退库 */
// @Excel(name = "库存类别")
private Long inventoryType;
/** 入库单号 */
// @Excel(name = "入库单号")
private String orderId;
/** 物料ID 检索条件 */
// @Excel(name = "物料ID 检索条件")
private String materialId;
/** SAP物料号 */
@Excel(name = "SAP物料号")
private String sapNo;
/** TS Code */
@Excel(name = "TS Code")
private String tsCode;
/** 物料名称 */
@Excel(name = "物料名称")
private String materialName;
/** 批次ID 检索条件 */
@Excel(name = "批次")
private String batchId;
/** 批次ID 检索条件 */
// @Excel(name = "仓库ID ")
private String warehousesId;
/** 仓库编码 检索条件 */
private String warehousesCode;
@Excel(name = "仓库 ")
private String warehousesName;
/** 库位ID 检索条件 */
private String locationId;
@Excel(name = "库位")
private String locationName;
@Excel(name = "货主")
private String ownerName;
/** 货主ID 检索条件 */
private String ownerId;
/** 库存数量 */
@Excel(name = "库存数量")
private Long quantity;
/** 锁定数量 */
@Excel(name = "锁定数量")
private Long lockedQuantity;
/** 单位重量 */
// @Excel(name = "单位重量")
private Long unitWeight;
/** 总重量 暂无用 */
// @Excel(name = "总重量")
private Long totalWeight;
/** 总体积 暂无用 */
// @Excel(name = "总体积")
private Long totalVolume;
/** 生产日期 暂无用 */
// @JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "生产日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date productionDate;
/** 失效日期 */
// @JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "失效日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date expirationDate;
/** 库存状态 0-已出库 1-正常 字典,检索条件 */
// @Excel(name = "库存状态 0-已出库 1-正常 字典,检索条件")
private Long inventoryStatus;
/** 最后入库时间 */
// @JsonFormat(pattern = "yyyy-MM-dd")
// @Excel(name = "最后入库时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date lastInboundTime;
/** 最后出库时间 */
// @JsonFormat(pattern = "yyyy-MM-dd")
// @Excel(name = "最后出库时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date lastOutboundTime;
/** 应用数据1使用0删除 删除用 */
private Long isUsed;
/** 排序 */
private Long sortNo;
/** 创建日期 */
private String createUserCode;
/** 排序号 */
private String updateUserCode;
/** 预警类型 */
private String alertType;
/** 最低库存 */
private Long minStockLevel;
/** 最高库存 */
private Long maxStockLevel;
/** 危险类别 */
private String hazardId;
/** 危险类别 */
// @Excel(name = "危险类别")
private String hazard;
/** 规格型号 */
// @Excel(name = "规格型号")
private String specification;
/** 计量单位 */
// @Excel(name = "计量单位")
private String materialUnit;
/** 包装重量 */
// @Excel(name = "包装重量")
private Double packageWeight;
/** 体积 */
private Double volume;
/** 保质期天数 */
private Integer shelfLifeDays;
/** 存储温度要求 */
// @Excel(name = "存储温度要求")
private String storageTemperature;
/** 特殊存储要求 */
// @Excel(name = "特殊存储要求")
private String specialRequirements;
}
package com.ruoyi.inventory.mapper;
import java.util.List;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.inventory.domain.Inventory;
import com.ruoyi.inventory.domain.StocktakeItems;
import com.ruoyi.inventory.domain.TO.StocktakeItemsTo;
import com.ruoyi.inventory.domain.vo.InventoryExceedWarnVO;
import com.ruoyi.inventory.domain.vo.InventoryVo;
import java.util.List;
/**
* 库存Mapper接口
......@@ -100,6 +100,14 @@ public interface InventoryMapper
public List<Inventory> selectInventoryDetailList(Inventory inventory);
/**
* 查询库存明细列表(根据物料标识及检索条件)
*
* @param inventory 库存查询条件
* @return 库存明细集合
*/
public List<InventoryVo> selectInventoryVoList(Inventory inventory);
/**
* 统计物料库存超出预警库存数量
*
* @return 超出预警值物料信息集合
......
package com.ruoyi.inventory.mapper;
import com.ruoyi.inventory.domain.vo.InboundOutboundStatisticsVO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 出入库统计Mapper
*/
@Mapper
public interface InventoryStatisticsMapper {
/**
* 按物料汇总出入库统计
*
* @param query 查询条件
* @return 汇总结果
*/
List<InboundOutboundStatisticsVO> selectInboundOutboundStatistics(InboundOutboundStatisticsVO query);
}
......@@ -100,4 +100,13 @@ public interface StorageLocationsMapper
int batchInsertStorageLocations(List<StorageLocations> storageLocations);
/**
* 根据库位名称和仓库ID精确查询(is_used=1)
* @param locationName 库位名
* @param warehouseId 仓库ID
* @return 库位
*/
StorageLocations selectStorageLocationsByNameAndWarehouse(@Param("locationName") String locationName,
@Param("warehouseId") String warehouseId);
}
......@@ -79,4 +79,11 @@ public interface WarehousesMapper
*/
public List<Map<String, Object>> getMapList();
/**
* 根据仓库名称精确查询(仅is_used=1)
* @param name 仓库名称
* @return 仓库
*/
Warehouses selectWarehousesByName(String name);
}
......@@ -10,6 +10,7 @@ import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.StocktakeItems;
import com.ruoyi.inventory.domain.TO.StocktakeItemsTo;
import com.ruoyi.inventory.domain.vo.InventoryExceedWarnVO;
import com.ruoyi.inventory.domain.vo.InventoryVo;
/**
* 库存Service接口
......@@ -109,6 +110,7 @@ public interface IInventoryService
*/
public List<Inventory> selectInventoryDetailList(Inventory inventory);
public List<InventoryVo> selectInventoryVoList(Inventory inventory);
/**
* 统计库存物料超出预警值
......
package com.ruoyi.inventory.service;
import com.ruoyi.inventory.domain.vo.InboundOutboundStatisticsVO;
import java.util.List;
/**
* 出入库统计 Service
*/
public interface IInventoryStatisticsService {
/**
* 按物料汇总出入库统计
*
* @param query 查询条件
* @return 统计列表
*/
List<InboundOutboundStatisticsVO> selectInboundOutboundStatistics(InboundOutboundStatisticsVO query);
}
......@@ -12,6 +12,7 @@ import com.ruoyi.inventory.domain.OutboundOrderLog;
import com.ruoyi.inventory.domain.TO.StocktakeItemsTo;
import com.ruoyi.inventory.domain.vo.InventoryExceedWarnVO;
import com.ruoyi.inventory.domain.vo.InventorySummaryVO;
import com.ruoyi.inventory.domain.vo.InventoryVo;
import com.ruoyi.inventory.mapper.OutboundOrderItemsMapper;
import com.ruoyi.inventory.mapper.OutboundOrderLogMapper;
import org.apache.commons.collections4.CollectionUtils;
......@@ -274,6 +275,12 @@ public class InventoryServiceImpl implements IInventoryService
}
@Override
public List<InventoryVo> selectInventoryVoList(Inventory inventory)
{
return inventoryMapper.selectInventoryVoList(inventory);
}
@Override
public List<InventoryExceedWarnVO> selectInventoryExceedWarnList() {
return inventoryMapper.selectInventoryExceedWarnList();
}
......
package com.ruoyi.inventory.service.impl;
import com.ruoyi.inventory.domain.vo.InboundOutboundStatisticsVO;
import com.ruoyi.inventory.mapper.InventoryStatisticsMapper;
import com.ruoyi.inventory.service.IInventoryStatisticsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 出入库统计 Service实现
*/
@Service
public class InventoryStatisticsServiceImpl implements IInventoryStatisticsService {
@Autowired
private InventoryStatisticsMapper inventoryStatisticsMapper;
@Override
public List<InboundOutboundStatisticsVO> selectInboundOutboundStatistics(InboundOutboundStatisticsVO query) {
return inventoryStatisticsMapper.selectInboundOutboundStatistics(query);
}
}
......@@ -33,7 +33,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="updateTime" column="update_time" />
<result property="updateUserCode" column="update_user_code" />
<result property="warehousesId" column="warehouses_id" />
<result property="oderCode" column="order_code" />
</resultMap>
<resultMap type="com.ruoyi.inventory.domain.TO.StocktakeItemsTo" id="StocktakeItemsResult">
......@@ -74,23 +73,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<resultMap type="com.ruoyi.inventory.domain.vo.InventorySummaryVO" id="InventorySummaryResult">
<result property="materialId" column="material_id" />
<result property="materialName" column="material_name" />
<result property="inventoryTypeName" column="inventory_type_name" />
<result property="warehousesCode" column="warehouses_code" />
<result property="warehouseName" column="warehouse_name" />
<result property="locationId" column="location_id" />
<result property="locationName" column="location_name" />
<result property="ownerId" column="owner_id" />
<result property="ownerName" column="owner_name" />
<result property="minStockLevel" column="min_stock_level" jdbcType="BIGINT"/>
<result property="maxStockLevel" column="max_stock_level" jdbcType="BIGINT"/>
<result property="sapNo" column="sap_no" />
<result property="tsCode" column="ts_code" />
<result property="hazardId" column="hazard_id" />
<result property="specification" column="specification" />
<result property="materialUnit" column="material_unit" />
<result property="unitWeight" column="unit_weight" />
<result property="packageWeight" column="package_weight" />
<result property="totalWeight" column="total_weight" />
<result property="volume" column="volume" />
<result property="shelfLifeDays" column="shelf_life_days" />
<result property="storageTemperature" column="storage_temperature" />
<result property="specialRequirements" column="special_requirements" />
<result property="totalQuantity" column="total_quantity" />
<result property="totalLockedQuantity" column="total_locked_quantity" />
<result property="totalAvailableQuantity" column="total_available_quantity" />
<result property="totalWeight" column="total_weight" />
<result property="totalVolume" column="total_volume" />
<result property="inventoryStatusName" column="inventory_status_name" />
<result property="alterType" column="alterType" />
</resultMap>
<sql id="selectInventoryVo">
select id, inventory_type,warehouses_id, order_id, material_id, batch_id, location_id, owner_id, quantity, locked_quantity, unit_weight, total_weight, total_volume, production_date, expiration_date, inventory_status, last_inbound_time, last_outbound_time, is_used, sort_no, create_time, create_user_code, update_time, update_user_code from inventory
select id, inventory_type,warehouses_id, volume, material_id, batch_id, location_id, owner_id, quantity, locked_quantity, unit_weight, total_weight, total_volume, production_date, expiration_date, inventory_status, last_inbound_time, last_outbound_time, is_used, sort_no, create_time, create_user_code, update_time, update_user_code from inventory
</sql>
<select id="selectInventoryList" parameterType="Inventory" resultMap="InventoryResult">
......@@ -121,59 +125,171 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<!-- 按物料汇总统计库存 -->
<select id="selectInventorySummaryList" parameterType="Inventory" resultMap="InventorySummaryResult">
<sql id="selectInventoryCount">
select
i.material_id,
m.material_name,
case i.inventory_type when 1 then '普通' when 2 then '退库' else '未知' end as inventory_type_name,
i.warehouses_code,
w.warehouses_name as warehouse_name,
i.location_id,
sl.location_name,
i.owner_id,
o.owner_name,
m.material_name,m.sap_no,
m.min_stock_level,
m.max_stock_level,
m.ts_code,
m.hazard_id,
m.specification,
m.material_unit,
m.unit_weight,
m.package_weight,
m.total_weight,
m.volume,
m.shelf_life_days,
m.storage_temperature,
m.special_requirements,
sum(i.quantity) as total_quantity,
sum(i.locked_quantity) as total_locked_quantity,
sum(i.quantity - ifnull(i.locked_quantity, 0)) as total_available_quantity,
sum(ifnull(i.total_weight, 0)) as total_weight,
sum(ifnull(i.total_volume, 0)) as total_volume,
case max(i.inventory_status) when 0 then '已出库' when 1 then '正常' else '未知' end as inventory_status_name
sum(i.quantity - ifnull(i.locked_quantity, 0)) as total_available_quantity
from inventory i
left join materials m on i.material_id = m.material_code
left join warehouses w on i.warehouses_code = w.warehouses_code
left join storage_locations sl on i.location_id = sl.location_code
left join materials m on i.material_id = m.id
left join warehouses w on i.warehouses_id = w.id
left join storage_locations sl on i.location_id = sl.id
left join owners o on i.owner_id = o.owner_code
</sql>
<select id="selectInventorySummaryList" parameterType="Inventory" resultMap="InventorySummaryResult">
select tab.*, case when total_quantity &lt; min_stock_level then '2' when total_quantity &gt; max_stock_level then '1' else '3' end alterType from (
<include refid="selectInventoryCount"/>
<where>
and i.quantity > 0 and i.inventory_status = 1 and i.is_used = 1
<if test="inventoryType != null "> and i.inventory_type = #{inventoryType}</if>
<if test="materialId != null and materialId != ''"> and (i.material_id like concat('%', #{materialId}, '%') or m.material_code like concat('%', #{materialId}, '%'))</if>
<if test="batchId != null and batchId != ''"> and i.batch_id = #{batchId}</if>
<if test="warehousesCode != null and warehousesCode != ''"> and i.warehouses_code = #{warehousesCode}</if>
<if test="materialId != null and materialId != ''"> and m.material_code like concat('%', #{materialId}, '%')</if>
<if test="batchId != null and batchId != ''"> and i.batch_id like concat('%', #{batchId}, '%')</if>
<if test="warehousesId != null and warehousesId != ''"> and w.warehouses_id = #{warehousesId}</if>
<if test="locationId != null and locationId != ''"> and i.location_id = #{locationId}</if>
<if test="ownerId != null and ownerId != ''"> and i.owner_id = #{ownerId}</if>
<if test="inventoryStatus != null "> and i.inventory_status = #{inventoryStatus}</if>
<if test="isUsed != null "> and i.is_used = #{isUsed}</if>
<!-- 预警类型过滤(需要根据业务逻辑判断,这里暂时不实现) -->
</where>
group by i.material_id, i.warehouses_code, i.location_id, i.owner_id, i.inventory_type, i.inventory_status
order by i.material_id, i.warehouses_code, i.location_id
group by i.material_id, m.material_name, m.sap_no,
m.ts_code,
m.hazard_id,
m.specification,
m.material_unit,
m.unit_weight,
m.package_weight,
m.total_weight,
m.volume,
m.shelf_life_days,
m.storage_temperature,
m.special_requirements ) tab
<where>
<if test="alertType == '0'.toString()"> and total_quantity &lt; min_stock_level or total_quantity &gt; max_stock_level</if>
<if test="alertType == '1'.toString()"> and total_quantity &gt; max_stock_level</if>
<if test="alertType == '2'.toString()"> and total_quantity &lt; min_stock_level</if>
</where>
order by total_quantity desc,material_id
</select>
<select id="selectInventorySummaryList2" parameterType="Inventory" resultMap="InventorySummaryResult">
select * from (
<include refid="selectInventoryCount"/>
<where>
and i.quantity > 0 and i.inventory_status = 1 and i.is_used = 1
<if test="inventoryType != null "> and i.inventory_type = #{inventoryType}</if>
<if test="materialId != null and materialId != ''"> and m.material_code like concat('%', #{materialId}, '%')</if>
<if test="batchId != null and batchId != ''"> and i.batch_id like concat('%', #{batchId}, '%')</if>
<if test="warehousesId != null and warehousesId != ''"> and w.warehouses_id = #{warehousesId}</if>
<if test="locationId != null and locationId != ''"> and i.location_id = #{locationId}</if>
<if test="ownerId != null and ownerId != ''"> and i.owner_id = #{ownerId}</if>
<if test="inventoryStatus != null "> and i.inventory_status = #{inventoryStatus}</if>
<if test="isUsed != null "> and i.is_used = #{isUsed}</if>
</where>
i.material_id, m.material_name, m.sap_no,
m.ts_code,
m.hazard_id,
m.specification,
m.material_unit,
m.unit_weight,
m.package_weight,
m.total_weight,
m.volume,
m.shelf_life_days,
m.storage_temperature,
m.special_requirements) tab
<where>
<if test="alertType == '0' "> and total_quantity &lt; min_stock_level or total_quantity &gt; max_stock_level</if>
<if test="alertType == '1'.toString() "> and total_quantity &gt; max_stock_level</if>
<if test="alertType == '2'.toString() "> and total_quantity &lt; min_stock_level</if>
</where>
</select>
<!-- 查询库存明细列表(根据物料标识及检索条件) -->
<sql id="selectInventoryDetailVo">
select
i.id,
i.inventory_type,
i.warehouses_id,
i.material_id,
i.batch_id,
i.location_id,
i.owner_id,
i.quantity,
i.locked_quantity,
i.unit_weight,
i.total_weight,
i.total_volume,
i.production_date,
i.expiration_date,
i.inventory_status,
i.last_inbound_time,
i.last_outbound_time,
m.material_name,
m.sap_no,
m.min_stock_level,
m.max_stock_level,
m.ts_code,
m.hazard_id,
m.specification,
m.material_unit,
m.unit_weight,
m.package_weight,
m.total_weight,
m.volume,
m.shelf_life_days,
m.storage_temperature,
m.special_requirements,
w.warehouses_name,
sl.location_name,
o.owner_name
from
inventory i
left join materials m on i.material_id = m.id
left join warehouses w on i.warehouses_id = w.id
left join storage_locations sl on i.location_id = sl.id
left join owners o on i.owner_id = o.owner_code
</sql>
<select id="selectInventoryDetailList" parameterType="Inventory" resultMap="InventoryResult">
<include refid="selectInventoryVo"/>
<include refid="selectInventoryDetailVo"/>
<where>
<if test="inventoryType != null "> and inventory_type = #{inventoryType}</if>
<if test="orderId != null and orderId != ''"> and order_id = #{orderId}</if>
<if test="materialId != null and materialId != ''"> and material_id = #{materialId}</if>
<if test="batchId != null and batchId != ''"> and batch_id = #{batchId}</if>
<if test="warehousesCode != null and warehousesCode != ''"> and warehouses_code = #{warehousesCode}</if>
<if test="locationId != null and locationId != ''"> and location_id = #{locationId}</if>
<if test="ownerId != null and ownerId != ''"> and owner_id = #{ownerId}</if>
<if test="inventoryStatus != null "> and inventory_status = #{inventoryStatus}</if>
<if test="isUsed != null "> and is_used = #{isUsed}</if>
<if test="warehousesId != null "> and warehouses_id = #{warehousesId}</if>
and i.quantity > 0 and i.inventory_status = 1 and i.is_used = 1
<if test="inventoryType != null "> and i.inventory_type = #{inventoryType}</if>
<if test="materialId != null and materialId != ''"> and i.material_id = #{materialId}</if>
<if test="batchId != null and batchId != ''"> and i.batch_id like concat('%', #{batchId}, '%')</if>
<if test="warehousesId != null and warehousesId != ''"> and w.warehouses_id = #{warehousesId}</if>
<if test="locationId != null and locationId != ''"> and i.location_id = #{locationId}</if>
<if test="ownerId != null and ownerId != ''"> and i.owner_id = #{ownerId}</if>
<if test="inventoryStatus != null "> and i.inventory_status = #{inventoryStatus}</if>
</where>
order by w.warehouses_code, sl.location_code, material_id desc
</select>
<select id="selectInventoryVoList" parameterType="Inventory" resultMap="InventoryVoResult">
<include refid="selectInventoryDetailVo"/>
<where>
and i.inventory_status = 1 and i.is_used = 1
<if test="inventoryType != null "> and i.inventory_type = #{inventoryType}</if>
<if test="materialId != null and materialId != ''"> and i.material_id = #{materialId}</if>
<if test="batchId != null and batchId != ''"> and i.batch_id like concat('%', #{batchId}, '%')</if>
<if test="warehousesId != null and warehousesId != ''"> and w.warehouses_id = #{warehousesId}</if>
<if test="locationId != null and locationId != ''"> and i.location_id = #{locationId}</if>
<if test="ownerId != null and ownerId != ''"> and i.owner_id = #{ownerId}</if>
<if test="inventoryStatus != null "> and i.inventory_status = #{inventoryStatus}</if>
</where>
order by material_id, warehouses_code, location_id, create_time desc
order by w.warehouses_code, sl.location_code, material_id desc
</select>
<select id="selectInventory" parameterType="Inventory" resultMap="InventoryResult">
......@@ -250,12 +366,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
LEFT JOIN storage_locations sl ON i.location_id = sl.id AND sl.is_enabled = 1 AND sl.is_used = 1
WHERE 1=1
<if test="materialId != null and materialId.trim() != ''">
AND i.material_id = #{materialId}
and material_id = #{materialId}
</if>
<![CDATA[
AND i.inventory_status = '1'
]]>
ORDER BY i.expiration_date ASC
and inventory_status = '1'
]]>
</select>
<insert id="insertInventory" parameterType="Inventory">
insert into inventory
......
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.inventory.mapper.InventoryStatisticsMapper">
<resultMap id="InboundOutboundStatisticsResult" type="com.ruoyi.inventory.domain.vo.InboundOutboundStatisticsVO">
<result column="material_id" property="materialId"/>
<result column="material_name" property="materialName"/>
<result column="inbound_count" property="inboundCount"/>
<result column="outbound_count" property="outboundCount"/>
<result column="inbound_quantity" property="inboundQuantity"/>
<result column="outbound_quantity" property="outboundQuantity"/>
<result column="inbound_amount" property="inboundAmount"/>
<result column="outbound_amount" property="outboundAmount"/>
<result column="amount_diff" property="amountDiff"/>
</resultMap>
<select id="selectInboundOutboundStatistics"
parameterType="com.ruoyi.inventory.domain.vo.InboundOutboundStatisticsVO"
resultMap="InboundOutboundStatisticsResult">
SELECT
t.material_id,
IFNULL(m.material_name, t.material_id) AS material_name,
SUM(t.inbound_count) AS inbound_count,
SUM(t.outbound_count) AS outbound_count,
SUM(t.inbound_quantity) AS inbound_quantity,
SUM(t.outbound_quantity) AS outbound_quantity,
SUM(t.inbound_amount) AS inbound_amount,
SUM(t.outbound_amount) AS outbound_amount,
SUM(t.inbound_amount) - SUM(t.outbound_amount) AS amount_diff
FROM (
SELECT
i.material_id,
COUNT(DISTINCT o.id) AS inbound_count,
0 AS outbound_count,
IFNULL(SUM(IFNULL(i.actual_quantity, 0)),0) AS inbound_quantity,
0 AS outbound_quantity,
IFNULL(SUM(IFNULL(i.unit_price, 0) * IFNULL(i.actual_quantity, 0)),0) AS inbound_amount,
0 AS outbound_amount
FROM inbound_order_items i
LEFT JOIN inbound_orders o ON i.inbound_order_id = o.id
LEFT JOIN warehouses w ON w.id = i.warehouse_id
LEFT JOIN materials m1 ON m1.id = i.material_id
<where>
i.is_used = 1
<if test="warehouseId != null and warehouseId != ''">
AND i.warehouse_id = #{warehouseId}
</if>
<if test="locationId != null and locationId != ''">
AND i.location_id = #{locationId}
</if>
<if test="materialId != null and materialId != ''">
AND (i.material_id = #{materialId}
OR m1.material_code LIKE CONCAT('%', #{materialId}, '%')
OR m1.material_name LIKE CONCAT('%', #{materialId}, '%'))
</if>
<if test="warehousesCode != null and warehousesCode != ''">
AND w.warehouses_code LIKE CONCAT('%', #{warehousesCode}, '%')
</if>
<if test="startDate != null">
AND o.inbound_date &gt;= #{startDate}
</if>
<if test="endDate != null">
AND o.inbound_date &lt; DATE_ADD(#{endDate}, INTERVAL 1 DAY)
</if>
</where>
GROUP BY i.material_id
UNION ALL
SELECT
oi.material_id,
0 AS inbound_count,
COUNT(DISTINCT oo.id) AS outbound_count,
0 AS inbound_quantity,
IFNULL(SUM(IFNULL(oi.actual_quantity, 0)),0) AS outbound_quantity,
0 AS inbound_amount,
IFNULL(SUM(IFNULL(oi.unit_price, 0) * IFNULL(oi.actual_quantity, 0)),0) AS outbound_amount
FROM outbound_order_items oi
LEFT JOIN outbound_orders oo ON oi.outbound_order_id = oo.id
LEFT JOIN warehouses w2 ON w2.id = oi.warehouse_id
LEFT JOIN materials m2 ON m2.id = oi.material_id
<where>
oi.is_used = 1
<if test="warehouseId != null and warehouseId != ''">
AND oi.warehouse_id = #{warehouseId}
</if>
<if test="locationId != null and locationId != ''">
AND oi.location_id = #{locationId}
</if>
<if test="materialId != null and materialId != ''">
AND (oi.material_id = #{materialId}
OR m2.material_code LIKE CONCAT('%', #{materialId}, '%')
OR m2.material_name LIKE CONCAT('%', #{materialId}, '%'))
</if>
<if test="warehousesCode != null and warehousesCode != ''">
AND w2.warehouses_code LIKE CONCAT('%', #{warehousesCode}, '%')
</if>
<if test="startDate != null">
AND oo.inbound_date &gt;= #{startDate}
</if>
<if test="endDate != null">
AND oo.inbound_date &lt; DATE_ADD(#{endDate}, INTERVAL 1 DAY)
</if>
</where>
GROUP BY oi.material_id
) t
LEFT JOIN materials m ON t.material_id = m.id
GROUP BY t.material_id, m.material_name
ORDER BY m.material_name ASC
</select>
</mapper>
......@@ -146,6 +146,19 @@
where sl.id = #{id}
</select>
<select id="selectStorageLocationsByNameAndWarehouse" resultMap="StorageLocationsResult">
select sl.id, sl.location_code, sl.location_name, sl.warehouses_code, sl.location_type,
sl.zone_code, sl.row_code, sl.column_code, sl.layer_code, sl.capacity,
sl.volume_capacity, sl.allowed_hazard_levels, sl.allowed_category_ids,
sl.temperature_zone, sl.is_enabled, sl.is_used, sl.sort_no,
sl.create_time, sl.create_user_code, sl.update_time, sl.update_user_code, sl.warehouses_id
from storage_locations sl
where sl.is_used = 1
and sl.location_name = #{locationName}
and sl.warehouses_id = #{warehouseId}
limit 1
</select>
<!-- 关联仓库表的ID查询 -->
<select id="selectStorageLocationsByIdWithWarehouses" parameterType="String" resultMap="StorageLocationsWithWarehousesResult">
select sl.id, sl.location_code, sl.location_name, sl.warehouses_code, sl.location_type,
......
......@@ -50,6 +50,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectWarehousesVo"/>
where id = #{id}
</select>
<select id="selectWarehousesByName" parameterType="String" resultMap="WarehousesResult">
<include refid="selectWarehousesVo"/>
where warehouses_name = #{name} and is_used = 1
limit 1
</select>
<!-- 获取仓库 的 warehouses_code 仓库编码 warehouses_name 做成字典-->
<select id="getMapList" resultType="java.util.Map">
select id, IFNULL(warehouses_name, '') as warehouses_name from warehouses where is_used = 1;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论