Commit 835ab1b5 by wangchunyang

统计相关功能

parent bdfed8f5
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',
......@@ -65,7 +74,7 @@ export function listInventoryByMaterialId(params) {
url: '/inventory/inventory/listByMaterialId',
method: 'post',
// 改为data传递JSON对象,适配后端实体类接收
data: params
data: params
// 若后端仍要求用params(URL参数)传递,保留下面这行,注释上面的data
// params: params
})
......
......@@ -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" />
......@@ -200,7 +199,7 @@ export default {
params.endDate = params.dateRange[1]
}
delete params.dateRange
listInboundOutboundStatistics(params).then(response => {
this.statisticsList = response.rows || []
this.total = response.total || 0
......@@ -295,7 +294,7 @@ export default {
delete params.dateRange
delete params.pageNum
delete params.pageSize
this.download('inventory/statistics/inboundOutbound/export', {
...params
}, `出入库统计数据_${new Date().getTime()}.xlsx`)
......
......@@ -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) }}
{{ (scope.row.totalQuantity || 0) - (scope.row.totalLockedQuantity || 0) }}
</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">
<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,
......@@ -558,8 +491,8 @@ export default {
pageNum: 1,
pageSize: 10000 // 设置一个很大的值,不分页
}
listInventory(params).then(response => {
listInventoryDetail(params).then(response => {
this.detailList = response.rows || []
this.detailLoading = false
}).catch(() => {
......@@ -571,10 +504,14 @@ export default {
const params = { ...this.queryParams }
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;
......@@ -112,243 +116,60 @@ public class Inventory extends BaseEntity
/** 预警类型 */
private String alertType;
public String getWarehousesId() {
return warehousesId;
}
public void setWarehousesId(String warehousesId) {
this.warehousesId = warehousesId;
}
public void setId(String id)
{
this.id = id;
}
public String getId()
{
return id;
}
public void setInventoryType(Long inventoryType)
{
this.inventoryType = inventoryType;
}
public Long getInventoryType()
{
return inventoryType;
}
public void setOrderId(String orderId)
{
this.orderId = orderId;
}
public String getOrderId()
{
return orderId;
}
public void setMaterialId(String materialId)
{
this.materialId = materialId;
}
public String getMaterialId()
{
return materialId;
}
public void setBatchId(String batchId)
{
this.batchId = batchId;
}
public String getBatchId()
{
return batchId;
}
public void setLocationId(String locationId)
{
this.locationId = locationId;
}
public String getLocationId()
{
return locationId;
}
public void setOwnerId(String ownerId)
{
this.ownerId = ownerId;
}
public String getOwnerId()
{
return ownerId;
}
public void setQuantity(Long quantity)
{
this.quantity = quantity;
}
public Long getQuantity()
{
return quantity;
}
public void setLockedQuantity(Long lockedQuantity)
{
this.lockedQuantity = lockedQuantity;
}
public Long getLockedQuantity()
{
return lockedQuantity;
}
public void setUnitWeight(Long unitWeight)
{
this.unitWeight = unitWeight;
}
/** 物料名称 */
@ExcelProperty(value = "物料名称", index = 1)
private String materialName;
public Long getUnitWeight()
{
return unitWeight;
}
/** 最低库存 */
private Long minStockLevel;
/** 最高库存 */
private Long maxStockLevel;
public void setTotalWeight(Long totalWeight)
{
this.totalWeight = totalWeight;
}
/** SAP物料号 */
@Excel(name = "SAP物料号")
private String sapNo;
public Long getTotalWeight()
{
return totalWeight;
}
/** TS Code */
@Excel(name = "TS Code")
private String tsCode;
public void setTotalVolume(Long totalVolume)
{
this.totalVolume = totalVolume;
}
/** 危险类别 */
private String hazardId;
public Long getTotalVolume()
{
return totalVolume;
}
/** 危险类别 */
@Excel(name = "危险类别")
private String hazard;
public void setProductionDate(Date productionDate)
{
this.productionDate = productionDate;
}
/** 规格型号 */
@Excel(name = "规格型号")
private String specification;
public Date getProductionDate()
{
return productionDate;
}
/** 计量单位 */
@Excel(name = "计量单位")
private String materialUnit;
public void setExpirationDate(Date expirationDate)
{
this.expirationDate = expirationDate;
}
/** 包装重量 */
// @Excel(name = "包装重量")
private Double packageWeight;
public Date getExpirationDate()
{
return expirationDate;
}
/** 体积 */
private Double volume;
public void setInventoryStatus(Long inventoryStatus)
{
this.inventoryStatus = inventoryStatus;
}
/** 保质期天数 */
private Integer shelfLifeDays;
public Long getInventoryStatus()
{
return inventoryStatus;
}
public void setLastInboundTime(Date lastInboundTime)
{
this.lastInboundTime = lastInboundTime;
}
public Date getLastInboundTime()
{
return lastInboundTime;
}
/** 存储温度要求 */
// @Excel(name = "存储温度要求")
private String storageTemperature;
public void setLastOutboundTime(Date lastOutboundTime)
{
this.lastOutboundTime = lastOutboundTime;
}
/** 特殊存储要求 */
// @Excel(name = "特殊存储要求")
private String specialRequirements;
public Date getLastOutboundTime()
{
return lastOutboundTime;
}
private String warehousesName;
private String locationName;
private String ownerName;
public void setIsUsed(Long isUsed)
{
this.isUsed = isUsed;
}
public Long getIsUsed()
{
return isUsed;
}
public void setSortNo(Long sortNo)
{
this.sortNo = sortNo;
}
public Long getSortNo()
{
return sortNo;
}
public void setCreateUserCode(String createUserCode)
{
this.createUserCode = createUserCode;
}
public String getCreateUserCode()
{
return createUserCode;
}
public void setUpdateUserCode(String updateUserCode)
{
this.updateUserCode = updateUserCode;
}
public String getUpdateUserCode()
{
return updateUserCode;
}
public void setWarehousesCode(String warehousesCode)
{
this.warehousesCode = warehousesCode;
}
public String getWarehousesCode()
{
return warehousesCode;
}
public void setAlertType(String alertType)
{
this.alertType = alertType;
}
public String getAlertType()
{
return alertType;
}
@Override
public String 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);
}
......@@ -97,4 +97,13 @@ public interface StorageLocationsMapper
* @return 库位集合
*/
List<StorageLocations> getStorageLocationsList(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);
}
......@@ -11,6 +11,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;
......@@ -268,6 +269,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);
}
}
......@@ -30,6 +30,71 @@ 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="materialName" column="material_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="alterType" column="alterType" />
<result property="warehousesName" column="warehouses_name" />
<result property="locationName" column="location_name" />
<result property="ownerName" column="owner_name" />
</resultMap>
<resultMap type="com.ruoyi.inventory.domain.vo.InventoryVo" id="InventoryVoResult">
<result property="id" column="id" />
<result property="inventoryType" column="inventory_type" />
<result property="orderId" column="order_id" />
<result property="materialId" column="material_id" />
<result property="batchId" column="batch_id" />
<result property="warehousesCode" column="warehouses_code" />
<result property="locationId" column="location_id" />
<result property="ownerId" column="owner_id" />
<result property="quantity" column="quantity" />
<result property="lockedQuantity" column="locked_quantity" />
<result property="unitWeight" column="unit_weight" />
<result property="totalWeight" column="total_weight" />
<result property="totalVolume" column="total_volume" />
<result property="productionDate" column="production_date" />
<result property="expirationDate" column="expiration_date" />
<result property="inventoryStatus" column="inventory_status" />
<result property="lastInboundTime" column="last_inbound_time" />
<result property="lastOutboundTime" column="last_outbound_time" />
<result property="isUsed" column="is_used" />
<result property="sortNo" column="sort_no" />
<result property="createTime" column="create_time" />
<result property="createUserCode" column="create_user_code" />
<result property="updateTime" column="update_time" />
<result property="updateUserCode" column="update_user_code" />
<result property="warehousesId" column="warehouses_id" />
<result property="materialName" column="material_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="alterType" column="alterType" />
<result property="warehousesName" column="warehouses_name" />
<result property="locationName" column="location_name" />
<result property="ownerName" column="owner_name" />
</resultMap>
<resultMap type="com.ruoyi.inventory.domain.TO.StocktakeItemsTo" id="StocktakeItemsResult">
......@@ -66,27 +131,31 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="inventoryId" column="inventory_id" />
<result property="unitPrice" column="unit_price" />
</resultMap>
<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">
......@@ -117,59 +186,171 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<!-- 按物料汇总统计库存 -->
<sql id="selectInventoryCount">
select
i.material_id,
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
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="selectInventorySummaryList" parameterType="Inventory" resultMap="InventorySummaryResult">
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,
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
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 owners o on i.owner_id = o.owner_code
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">
......
<?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>
......@@ -107,6 +107,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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论