fix:产品库存数据展示调整

dev_1.0.2
jiangpeng 2026-07-08 02:01:08 +08:00
parent 972d121580
commit 3d94027618
29 changed files with 998 additions and 31 deletions

View File

@ -85,3 +85,30 @@ export function getOuterLog(query) {
params: query
})
}
// 查询在途库存
export function getPurchaseStock(query) {
return request({
url: '/inventory/info/vue/purchase-stock',
method: 'get',
params: query
})
}
// 查询锁单
export function getBindOrder(query) {
return request({
url: '/inventory/info/vue/bind-order',
method: 'get',
params: query
})
}
// 查询在库现存
export function getInventoryInner(query) {
return request({
url: '/inventory/info/vue/inventory-inner',
method: 'get',
params: query
})
}

View File

@ -19,6 +19,15 @@ export function getInner(id) {
})
}
// 查询入库单产品信息列表
export function listInnerInventoryInfo(id, query) {
return request({
url: `${VUE_APP_API_URL}/${id}/inventory-info/list`,
method: 'get',
params: query
})
}
// 新增入库单信息
export function addInner(data) {
return request({

View File

@ -99,6 +99,7 @@
<span>{{ scope.row.approveNode || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="提交时间" align="center" prop="approveTime" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
@ -179,7 +180,7 @@ export default {
customerName: null,
dutyName: null,
approveNode: null,
orderByColumn:'t1.approve_time',
orderByColumn:'t1.approveTime desc, t1.id',
isAsc: 'desc'
},
};

View File

@ -181,6 +181,8 @@ export default {
customerName: null,
dutyName: null,
approveNode: null,
orderByColumn: 't2.id',
isAsc: 'desc',
},
};
},

View File

@ -52,14 +52,32 @@
<el-table-column label="产品型号" align="center" prop="model" show-overflow-tooltip />
<el-table-column label="产品名称" align="center" prop="productName" show-overflow-tooltip />
<el-table-column label="仓库" align="center" prop="warehouseName" />
<el-table-column label="实时库存" align="center" prop="availableCount" sortable="custom" >
<el-table-column label="在库现存" align="center" prop="inventoryNum">
<template slot-scope="scope">
<span :style="getStockColor(scope.row.availableCount)">{{ scope.row.availableCount || scope.row.inventoryCount || 0 }}</span>
<el-link v-if="scope.row.inventoryNum" type="primary" @click="handleInventoryInner(scope.row)">{{ scope.row.inventoryNum }}</el-link>
<span v-else>0</span>
</template>
</el-table-column>
<el-table-column label="累计发货" align="center" prop="cumulativeCount">
<el-table-column label="在途库存" align="center" prop="purchaseNum">
<template slot-scope="scope">
<el-link v-if="scope.row.purchaseNum" type="primary" @click="handlePurchaseStock(scope.row)">{{ scope.row.purchaseNum }}</el-link>
<span v-else>0</span>
</template>
</el-table-column>
<el-table-column label="可用量" align="center" prop="usableNum">
<template slot-scope="scope">
<span>{{ scope.row.usableNum || 0 }}</span>
</template>
</el-table-column>
<el-table-column label="锁单量" align="center" prop="bindNum">
<template slot-scope="scope">
<el-link v-if="scope.row.bindNum" type="primary" @click="handleBindOrder(scope.row)">{{ scope.row.bindNum }}</el-link>
<span v-else>0</span>
</template>
</el-table-column>
<el-table-column label="累计发货" align="center" prop="outerNum">
<template slot-scope="scope">
<span>{{ scope.row.cumulativeCount || 0 }}</span>
<span>{{ scope.row.outerNum || 0 }}</span>
</template>
</el-table-column>
<el-table-column label="制造商" align="center" prop="vendorName" show-overflow-tooltip/>
@ -205,19 +223,143 @@
<outer-log v-if="outerLogVisible" :product-code="currentLogProductCode" :warehouse-id="currentLogWarehouseId" />
</el-dialog>
<!-- 在库现存对话框 -->
<el-dialog :close-on-click-modal="false" title="在库现存" :visible.sync="inventoryInnerVisible" width="70%" append-to-body>
<div class="purchase-stock-summary">
<span>产品信息{{ currentInventoryInnerProductName || '-' }}{{ inventoryInnerQuery.productCode || '-' }}</span>
<span>在库现存总量{{ currentInventoryInnerTotal || 0 }}</span>
</div>
<el-table v-loading="inventoryInnerLoading" :data="inventoryInnerList">
<el-table-column label="序号" type="index" width="50" align="center" :index="inventoryInnerIndex" />
<el-table-column label="入库单号" align="center" prop="innerCode">
<template slot-scope="scope">
<el-link type="primary" @click="handleViewInventoryInner(scope.row)">{{ scope.row.innerCode }}</el-link>
</template>
</el-table-column>
<el-table-column label="入库数量" align="center" prop="innerNum" />
<el-table-column label="在库现存" align="center" prop="inventoryNum" />
<el-table-column label="锁单量" align="center" prop="bindNum" />
</el-table>
<pagination
v-show="inventoryInnerTotal > 0"
:total="inventoryInnerTotal"
:page.sync="inventoryInnerQuery.pageNum"
:limit.sync="inventoryInnerQuery.pageSize"
@pagination="getInventoryInnerList"
/>
</el-dialog>
<el-drawer :title="inventoryInnerDetailTitle" :visible.sync="inventoryInnerDetailOpen" direction="rtl" size="70%" append-to-body>
<component :is="inventoryInnerDetailComponent" :form="inventoryInnerDetailForm" @download-file="handleInventoryInnerDownloadFile" v-if="inventoryInnerDetailOpen" />
</el-drawer>
<!-- 在途库存对话框 -->
<el-dialog :close-on-click-modal="false" title="在途库存" :visible.sync="purchaseStockVisible" width="70%" append-to-body>
<div class="purchase-stock-summary">
<span>产品信息{{ currentPurchaseStockProductName || '-' }}{{ purchaseStockQuery.productCode || '-' }}</span>
<span>在途总量{{ currentPurchaseStockTotal || 0 }}</span>
</div>
<el-table v-loading="purchaseStockLoading" :data="purchaseStockList">
<el-table-column label="序号" type="index" width="50" align="center" :index="purchaseStockIndex" />
<el-table-column label="采购单号" align="center" prop="purchaseNo">
<template slot-scope="scope">
<el-link type="primary" @click="handleViewPurchaseOrder(scope.row)">{{ scope.row.purchaseNo }}</el-link>
</template>
</el-table-column>
<el-table-column label="在途库存" align="center" prop="purchaseNum" />
<el-table-column label="采购员" align="center" prop="purchaserName" />
</el-table>
<pagination
v-show="purchaseStockTotal > 0"
:total="purchaseStockTotal"
:page.sync="purchaseStockQuery.pageNum"
:limit.sync="purchaseStockQuery.pageSize"
@pagination="getPurchaseStockList"
/>
</el-dialog>
<el-drawer title="采购单详情" :visible.sync="purchaseOrderDetailOpen" direction="rtl" size="80%" append-to-body>
<ApproveLayout title="采购单详情" v-if="purchaseOrderDetailOpen">
<purchase-order-detail-view
ref="purchaseOrderDetailView"
:order-data="purchaseOrderDetailData"
:showHistory="true"
@close="purchaseOrderDetailOpen = false"
@view-history-detail="handleViewPurchaseOrderHistoryDetail"
/>
<template #footer>
<span>采购单编号: {{ currentDetailPurchaseNo }}</span>
</template>
</ApproveLayout>
</el-drawer>
<el-drawer title="历史订单详情" :visible.sync="purchaseOrderHistoryDetailOpen" direction="rtl" size="80%" append-to-body>
<ApproveLayout title="采购单历史详情" v-if="purchaseOrderHistoryDetailOpen">
<purchase-order-detail-view
ref="purchaseOrderHistoryDetailView"
:order-data="purchaseOrderHistoryDetailData"
@close="purchaseOrderHistoryDetailOpen = false"
/>
<template #footer>
<span>订单编号: {{ purchaseOrderHistoryDetailData ? purchaseOrderHistoryDetailData.purchaseNo : '' }}</span>
<span v-if="purchaseOrderHistoryDetailData"> | : {{ purchaseOrderHistoryDetailData.version }}</span>
</template>
</ApproveLayout>
</el-drawer>
<!-- 锁单对话框 -->
<el-dialog :close-on-click-modal="false" title="锁单量" :visible.sync="bindOrderVisible" width="70%" append-to-body>
<div class="purchase-stock-summary">
<span>产品信息{{ currentBindOrderProductName || '-' }}{{ bindOrderQuery.productCode || '-' }}</span>
<span>锁单总量{{ currentBindOrderTotal || 0 }}</span>
</div>
<el-table v-loading="bindOrderLoading" :data="bindOrderList">
<el-table-column label="序号" type="index" width="50" align="center" :index="bindOrderIndex" />
<el-table-column label="项目编号" align="center" prop="projectCode">
<template slot-scope="scope">
<a @click="handleViewProject(scope.row)" class="link-type">{{ scope.row.projectCode }}</a>
</template>
</el-table-column>
<el-table-column label="项目名称" align="center" prop="projectName" show-overflow-tooltip />
<el-table-column label="汇智负责人" align="center" prop="userName" />
<el-table-column label="锁单量" align="center" prop="bindNum" />
</el-table>
<pagination
v-show="bindOrderTotal > 0"
:total="bindOrderTotal"
:page.sync="bindOrderQuery.pageNum"
:limit.sync="bindOrderQuery.pageSize"
@pagination="getBindOrderList"
/>
</el-dialog>
<project-detail-drawer :visible.sync="projectDrawerVisible" :project-id="currentProjectId" :z-index="4000" />
</div>
</template>
<script>
import { listInfo, getInfo, addInfo, updateInfo, delInfo, listAllVendors, listAllWarehouses } from "@/api/inventory/info";
import { listInfo, getInfo, addInfo, updateInfo, delInfo, listAllVendors, listAllWarehouses, getPurchaseStock, getBindOrder, getInventoryInner } from "@/api/inventory/info";
import { getInner } from "@/api/inventory/inner";
import InnerLog from './innerLog';
import OuterLog from './outerLog';
import OrderDetail from "@/views/inventory/inner/components/OrderDetail.vue";
import ServiceDetail from "@/views/inventory/inner/components/ServiceDetail.vue";
import ProjectDetailDrawer from "@/views/project/info/ProjectDetailDrawer.vue";
import ApproveLayout from "@/views/approve/ApproveLayout.vue";
import PurchaseOrderDetailView from "@/views/purchaseorder/components/PurchaseOrderDetailView.vue";
import { getPurchaseorder, getPurchaseOrderHistoryDetail } from "@/api/sip/purchaseorder";
export default {
name: "InventoryInfo",
components: {
InnerLog,
OuterLog
OuterLog,
OrderDetail,
ServiceDetail,
ProjectDetailDrawer,
ApproveLayout,
PurchaseOrderDetailView
},
data() {
return {
@ -241,6 +383,8 @@ export default {
open: false,
//
drawerVisible: false,
projectDrawerVisible: false,
currentProjectId: null,
//
vendorOptions: [],
//
@ -248,6 +392,54 @@ export default {
//
innerLogVisible: false,
outerLogVisible: false,
inventoryInnerVisible: false,
inventoryInnerLoading: false,
inventoryInnerList: [],
inventoryInnerTotal: 0,
inventoryInnerIndexBase: 0,
inventoryInnerQuery: {
pageNum: 1,
pageSize: 10,
productCode: null,
warehouseId: null
},
currentInventoryInnerProductName: null,
currentInventoryInnerTotal: 0,
inventoryInnerDetailOpen: false,
inventoryInnerDetailTitle: "",
inventoryInnerDetailComponent: null,
inventoryInnerDetailForm: {},
purchaseStockVisible: false,
purchaseStockLoading: false,
purchaseStockList: [],
purchaseStockTotal: 0,
purchaseStockIndexBase: 0,
purchaseStockQuery: {
pageNum: 1,
pageSize: 10,
productCode: null,
warehouseId: null
},
currentPurchaseStockProductName: null,
currentPurchaseStockTotal: 0,
purchaseOrderDetailOpen: false,
purchaseOrderDetailData: null,
currentDetailPurchaseNo: null,
purchaseOrderHistoryDetailOpen: false,
purchaseOrderHistoryDetailData: null,
bindOrderVisible: false,
bindOrderLoading: false,
bindOrderList: [],
bindOrderTotal: 0,
bindOrderIndexBase: 0,
bindOrderQuery: {
pageNum: 1,
pageSize: 10,
productCode: null,
warehouseId: null
},
currentBindOrderProductName: null,
currentBindOrderTotal: 0,
currentLogProductCode: null,
currentLogWarehouseId: null,
//
@ -450,6 +642,130 @@ export default {
this.currentLogProductCode = row.productCode;
this.currentLogWarehouseId = row.warehouseId;
this.outerLogVisible = true;
},
inventoryInnerIndex(index) {
return this.inventoryInnerIndexBase + index + 1;
},
purchaseStockIndex(index) {
return this.purchaseStockIndexBase + index + 1;
},
bindOrderIndex(index) {
return this.bindOrderIndexBase + index + 1;
},
/** 处理在库现存 */
handleInventoryInner(row) {
if (!row.warehouseId) {
this.$modal.msgError("仓库信息不存在,无法查看在库现存");
return;
}
this.inventoryInnerQuery.pageNum = 1;
this.inventoryInnerQuery.productCode = row.productCode;
this.inventoryInnerQuery.warehouseId = row.warehouseId;
this.currentInventoryInnerProductName = row.productName;
this.currentInventoryInnerTotal = row.inventoryNum;
this.inventoryInnerVisible = true;
this.getInventoryInnerList();
},
/** 查询在库现存 */
getInventoryInnerList() {
this.inventoryInnerLoading = true;
getInventoryInner(this.inventoryInnerQuery).then(response => {
this.inventoryInnerList = response.rows;
this.inventoryInnerTotal = response.total;
this.inventoryInnerIndexBase = (this.inventoryInnerQuery.pageNum - 1) * this.inventoryInnerQuery.pageSize;
this.inventoryInnerLoading = false;
}).catch(() => {
this.inventoryInnerLoading = false;
});
},
handleViewInventoryInner(row) {
getInner(row.id).then(response => {
this.inventoryInnerDetailForm = response.data;
if (['3', '11', '22'].includes(this.inventoryInnerDetailForm.productType)) {
this.inventoryInnerDetailComponent = 'ServiceDetail';
} else {
this.inventoryInnerDetailComponent = 'OrderDetail';
}
this.inventoryInnerDetailOpen = true;
this.inventoryInnerDetailTitle = "查看入库单详情";
});
},
handleInventoryInnerDownloadFile() {
if (this.inventoryInnerDetailForm.fileId) {
window.location.href = process.env.VUE_APP_BASE_API + "/common/file/download?id=" + this.inventoryInnerDetailForm.fileId;
} else {
this.$modal.msgWarning("文件ID不存在无法下载");
}
},
/** 处理在途库存 */
handlePurchaseStock(row) {
if (!row.warehouseId) {
this.$modal.msgError("仓库信息不存在,无法查看在途库存");
return;
}
this.purchaseStockQuery.pageNum = 1;
this.purchaseStockQuery.productCode = row.productCode;
this.purchaseStockQuery.warehouseId = row.warehouseId;
this.currentPurchaseStockProductName = row.productName;
this.currentPurchaseStockTotal = row.purchaseNum;
this.purchaseStockVisible = true;
this.getPurchaseStockList();
},
/** 查询在途库存 */
getPurchaseStockList() {
this.purchaseStockLoading = true;
getPurchaseStock(this.purchaseStockQuery).then(response => {
this.purchaseStockList = response.rows;
this.purchaseStockTotal = response.total;
this.purchaseStockIndexBase = (this.purchaseStockQuery.pageNum - 1) * this.purchaseStockQuery.pageSize;
this.purchaseStockLoading = false;
}).catch(() => {
this.purchaseStockLoading = false;
});
},
handleViewPurchaseOrder(row) {
getPurchaseorder(row.id).then(response => {
this.purchaseOrderDetailData = response.data;
this.currentDetailPurchaseNo = row.purchaseNo;
this.purchaseOrderDetailOpen = true;
});
},
handleViewPurchaseOrderHistoryDetail(row) {
getPurchaseOrderHistoryDetail(row.id).then(response => {
this.purchaseOrderHistoryDetailData = response.data;
this.purchaseOrderHistoryDetailOpen = true;
this.purchaseOrderDetailOpen = false;
});
},
handleViewProject(row) {
this.currentProjectId = row.projectId;
this.projectDrawerVisible = true;
},
/** 处理锁单量 */
handleBindOrder(row) {
if (!row.warehouseId) {
this.$modal.msgError("仓库信息不存在,无法查看锁单量");
return;
}
this.bindOrderQuery.pageNum = 1;
this.bindOrderQuery.productCode = row.productCode;
this.bindOrderQuery.warehouseId = row.warehouseId;
this.currentBindOrderProductName = row.productName;
this.currentBindOrderTotal = row.bindNum;
this.bindOrderVisible = true;
this.getBindOrderList();
},
/** 查询锁单量 */
getBindOrderList() {
this.bindOrderLoading = true;
getBindOrder(this.bindOrderQuery).then(response => {
this.bindOrderList = response.rows;
this.bindOrderTotal = response.total;
this.bindOrderIndexBase = (this.bindOrderQuery.pageNum - 1) * this.bindOrderQuery.pageSize;
this.bindOrderLoading = false;
}).catch(() => {
this.bindOrderLoading = false;
});
}
}
};</script>
@ -458,4 +774,11 @@ export default {
.detail-container {
padding: 20px;
}
.purchase-stock-summary {
display: flex;
justify-content: space-between;
margin-bottom: 12px;
font-weight: 600;
}
</style>

View File

@ -1,7 +1,11 @@
<template>
<div>
<el-table v-loading="loading" :data="logList">
<el-table-column label="入库单号" align="center" prop="innerCode" width="150" />
<el-table-column label="入库单号" align="center" prop="innerCode" width="150">
<template slot-scope="scope">
<el-link type="primary" @click="handleView(scope.row)">{{ scope.row.innerCode }}</el-link>
</template>
</el-table-column>
<el-table-column label="产品编码" align="center" prop="productCode" width="150" />
<el-table-column label="产品型号" align="center" prop="model" />
<el-table-column label="入库数量" align="center" prop="quantity" width="100" />
@ -15,14 +19,25 @@
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="fetchLog" />
<el-drawer :title="title" :visible.sync="drawerOpen" direction="rtl" size="70%" append-to-body>
<component :is="detailComponent" :form="form" @download-file="handleDownloadFile" v-if="drawerOpen" />
</el-drawer>
</div>
</template>
<script>
import { getInnerLog } from "@/api/inventory/info";
import { getInner } from "@/api/inventory/inner";
import OrderDetail from "@/views/inventory/inner/components/OrderDetail.vue";
import ServiceDetail from "@/views/inventory/inner/components/ServiceDetail.vue";
export default {
name: "InnerLog",
components: {
OrderDetail,
ServiceDetail
},
props: {
productCode: {
type: String,
@ -38,6 +53,10 @@ export default {
loading: true,
logList: [],
total: 0,
title: "",
drawerOpen: false,
detailComponent: null,
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
@ -79,6 +98,25 @@ export default {
this.total = response.total;
this.loading = false;
});
},
handleView(row) {
getInner(row.id).then(response => {
this.form = response.data;
if (['3', '11', '22'].includes(this.form.productType)) {
this.detailComponent = 'ServiceDetail';
} else {
this.detailComponent = 'OrderDetail';
}
this.drawerOpen = true;
this.title = "查看入库单详情";
});
},
handleDownloadFile() {
if (this.form.fileId) {
window.location.href = process.env.VUE_APP_BASE_API + "/common/file/download?id=" + this.form.fileId;
} else {
this.$modal.msgWarning("文件ID不存在无法下载");
}
}
}
};

View File

@ -1,13 +1,17 @@
<template>
<div>
<el-table v-loading="loading" :data="logList">
<el-table-column label="出库单号" align="center" prop="outerCode" width="150" />
<el-table-column label="出库单号" align="center" prop="outerCode" width="150">
<template slot-scope="scope">
<el-link type="primary" @click="handleView(scope.row)">{{ scope.row.outerCode }}</el-link>
</template>
</el-table-column>
<el-table-column label="合同编号" align="center" prop="orderCode" />
<el-table-column label="项目名称" align="center" prop="projectName" show-overflow-tooltip />
<el-table-column label="数量" align="center" prop="quantity" width="100" />
<el-table-column label="出库状态" align="center" prop="outerStatus" width="120">
<template slot-scope="scope">
<dict-tag :options="outerStatusOptions" :value="scope.row.outerStatus"/>
<span>{{ formatOuterStatus(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column label="经办人" align="center" prop="createByName" width="120" />
@ -18,14 +22,17 @@
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="fetchLog" />
<outer-form ref="form" :view-only="true" @returnSuccess="fetchLog" @success="fetchLog" />
</div>
</template>
<script>
import { getOuterLog } from "@/api/inventory/info";
import OuterForm from "@/views/inventory/outer/components/OuterForm.vue";
export default {
name: "OuterLog",
components: { OuterForm },
props: {
productCode: {
type: String,
@ -41,7 +48,17 @@ export default {
loading: true,
logList: [],
total: 0,
outerStatusOptions: [],
outerStatusOptions: {
'1': '待确认',
'2': '已确认',
'3': '已接收',
'4': '已退回'
},
deliveryStatusOptions: {
'0': '未发货',
'1': '部分发货',
'2': '全部发货'
},
queryParams: {
pageNum: 1,
pageSize: 10,
@ -52,11 +69,6 @@ export default {
}
};
},
created() {
this.getDicts("outer_outer_status").then(response => {
this.outerStatusOptions = response.data;
});
},
watch: {
productCode: {
immediate: true,
@ -88,6 +100,16 @@ export default {
this.total = response.total;
this.loading = false;
});
},
handleView(row) {
this.$refs.form.open(row.id);
},
formatOuterStatus(row) {
if (String(row.outerStatus) === '3') {
const deliveryStatus = row.deliveryStatus == null || row.deliveryStatus === '' ? '0' : String(row.deliveryStatus);
return this.deliveryStatusOptions[deliveryStatus] || deliveryStatus;
}
return this.outerStatusOptions[String(row.outerStatus)] || row.outerStatus || '-';
}
}
};

View File

@ -63,7 +63,7 @@
<el-row>
<el-col :span="24"><h3>产品信息</h3></el-col>
</el-row>
<el-table :data="form.inventoryInfoList">
<el-table v-loading="inventoryInfoLoading" :data="inventoryInfoList">
<el-table-column label="SN码" prop="productSn" />
<el-table-column label="授权码" prop="licenseKey" />
<el-table-column label="产品编码" prop="productCode" />
@ -79,6 +79,13 @@
</template>
</el-table-column>
</el-table>
<pagination
v-show="inventoryInfoTotal > 0"
:total="inventoryInfoTotal"
:page.sync="inventoryInfoQuery.pageNum"
:limit.sync="inventoryInfoQuery.pageSize"
@pagination="fetchInventoryInfoList"
/>
<el-dialog
title="采购单详情"
:visible.sync="purchaseOrderDetailOpen"
@ -123,6 +130,7 @@
</template>
<script>
import { listInnerInventoryInfo } from "@/api/inventory/inner";
import { getPurchaseorder, getPurchaseOrderHistoryDetail, listPurchaseorder } from "@/api/sip/purchaseorder";
import ApproveLayout from "@/views/approve/ApproveLayout.vue";
import PurchaseOrderDetailView from "@/views/purchaseorder/components/PurchaseOrderDetailView.vue";
@ -144,10 +152,29 @@ export default {
purchaseOrderDetailOpen: false,
purchaseOrderDetailData: null,
historyDetailOpen: false,
historyDetailData: null
historyDetailData: null,
inventoryInfoLoading: false,
inventoryInfoList: [],
inventoryInfoTotal: 0,
inventoryInfoQuery: {
pageNum: 1,
pageSize: 10
}
};
},
watch: {
'form.id': {
immediate: true,
handler(val) {
this.inventoryInfoQuery.pageNum = 1;
if (val) {
this.fetchInventoryInfoList();
} else {
this.inventoryInfoList = [];
this.inventoryInfoTotal = 0;
}
}
},
purchaseOrderDetailOpen(val) {
if (!val) {
this.purchaseOrderDetailData = null;
@ -162,6 +189,19 @@ export default {
}
},
methods: {
fetchInventoryInfoList() {
if (!this.form.id) {
return;
}
this.inventoryInfoLoading = true;
listInnerInventoryInfo(this.form.id, this.inventoryInfoQuery).then(response => {
this.inventoryInfoList = response.rows;
this.inventoryInfoTotal = response.total;
this.inventoryInfoLoading = false;
}).catch(() => {
this.inventoryInfoLoading = false;
});
},
formatThousands(value) {
if (value === null || value === undefined || value === '') {
return 0;

View File

@ -41,7 +41,7 @@
<el-table-column label="已生成发货" prop="deliveryGenerateQuantity" />
<el-table-column label="实时库存" prop="availableCount" />
<el-table-column label="仓库" prop="warehouseName" />
<el-table-column label="操作" align="center">
<el-table-column v-if="!viewOnly" label="操作" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@ -82,7 +82,7 @@
<delivery-detail :delivery-id="deliveryId" :visible.sync="viewOpen" />
<div slot="footer" class="dialog-footer">
<el-button v-if="showReturn" type="danger" @click="handleStatusChange(form, '4')">退 </el-button>
<el-button v-if="showReturn && !viewOnly" type="danger" @click="handleStatusChange(form, '4')">退 </el-button>
<el-button @click="handleCancel"> </el-button>
</div>
</el-dialog>
@ -97,6 +97,12 @@ import DeliveryDetail from '@/views/inventory/delivery/Detail.vue';
export default {
name: "OuterForm",
components: { GenerateDeliveryForm, DeliveryDetail },
props: {
viewOnly: {
type: Boolean,
default: false
}
},
data() {
return {
visible: false,

View File

@ -74,4 +74,11 @@ public class DataProcessController extends BaseController {
return getDataTable(inventoryInfoService.selectInventoryInfoList(inventoryInfo));
}
//OMS历史商机反写CRM
@Anonymous
@GetMapping("/omsHistoryProjectPushCRM")
public AjaxResult omsHistoryProjectPushCRM() {
return dataProcessService.omsHistoryProjectPushCRM();
}
}

View File

@ -9,10 +9,15 @@ import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.sip.domain.InventoryInfo;
import com.ruoyi.sip.domain.OmsWarehouseInfo;
import com.ruoyi.sip.domain.ProductInfo;
import com.ruoyi.sip.dto.inventory.OmsPurchaseOrderItemDto;
import com.ruoyi.sip.dto.inventory.ProductBindOrderDTO;
import com.ruoyi.sip.dto.inventory.ProductInventoryInnerDTO;
import com.ruoyi.sip.dto.inventory.ProductInventoryQueryDTO;
import com.ruoyi.sip.service.IInventoryAuthService;
import com.ruoyi.sip.service.IInventoryInfoService;
import com.ruoyi.sip.service.IOmsWarehouseInfoService;
import com.ruoyi.sip.service.IProductInfoService;
import com.ruoyi.sip.service.IOmsPurchaseOrderService;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.sip.domain.OmsInventoryInner;
import com.ruoyi.sip.service.IOmsInventoryInnerService;
@ -54,6 +59,9 @@ public class VueInventoryInfoController extends BaseController {
@Autowired
private IInventoryOuterService inventoryOuterService;
@Autowired
private IOmsPurchaseOrderService omsPurchaseOrderService;
/**
*
*/
@ -193,4 +201,34 @@ public class VueInventoryInfoController extends BaseController {
List<InventoryOuter> list = inventoryOuterService.selectInventoryOuterList(inventoryOuter);
return getDataTable(list);
}
/**
*
*/
@GetMapping("/purchase-stock")
public TableDataInfo getPurchaseStock(ProductInventoryQueryDTO query) {
startPage();
List<OmsPurchaseOrderItemDto> list = omsPurchaseOrderService.listPurchaseStock(query);
return getDataTable(list);
}
/**
*
*/
@GetMapping("/bind-order")
public TableDataInfo getBindOrder(ProductInventoryQueryDTO query) {
startPage();
List<ProductBindOrderDTO> list = omsPurchaseOrderService.listBindOrder(query);
return getDataTable(list);
}
/**
*
*/
@GetMapping("/inventory-inner")
public TableDataInfo getInventoryInner(ProductInventoryQueryDTO query) {
startPage();
List<ProductInventoryInnerDTO> list = omsInventoryInnerService.listInventoryInner(query);
return getDataTable(list);
}
}

View File

@ -7,6 +7,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.sip.domain.InventoryInfo;
import com.ruoyi.sip.domain.OmsInventoryInner;
import com.ruoyi.sip.dto.warehouse.WarehouseInnerExcelDto;
import com.ruoyi.sip.service.IInventoryInfoService;
@ -50,7 +51,20 @@ public class VueOmsInventoryInnerController extends BaseController {
*/
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) {
return success(omsInventoryInnerService.selectOmsInventoryInnerById(id));
return success(omsInventoryInnerService.selectOmsInventoryInnerBaseById(id));
}
/**
*
*/
@GetMapping(value = "/{id}/inventory-info/list")
public TableDataInfo inventoryInfoList(@PathVariable("id") Long id) {
OmsInventoryInner omsInventoryInner = omsInventoryInnerService.selectOmsInventoryInnerBaseById(id);
startPage();
InventoryInfo queryParams = new InventoryInfo();
queryParams.setInnerCode(omsInventoryInner.getInnerCode());
List<InventoryInfo> list = inventoryInfoService.selectInventoryInfoList(queryParams);
return getDataTable(list);
}
/**

View File

@ -77,6 +77,16 @@ public class ProductInfo extends BaseEntity
private Long availableCount;
// 累计发货
private Long cumulativeCount;
/** 在库现存 */
private Long inventoryNum;
/** 累计发货 */
private Long outerNum;
/** 在途库存 */
private Long purchaseNum;
/** 锁单量 */
private Long bindNum;
/** 可用量 */
private Long usableNum;
private Long inventoryCount;
private Long warehouseId;
private String warehouseName;

View File

@ -30,6 +30,7 @@ public class OmsPurchaseOrderItemDto extends OmsPurchaseOrder {
/** 数量 */
private BigDecimal quantity;
private BigDecimal innerQuantity;
private BigDecimal purchaseNum;
private BigDecimal taxTotal;
private BigDecimal amountTotal;
private BigDecimal taxRate;

View File

@ -0,0 +1,30 @@
package com.ruoyi.sip.dto.inventory;
import lombok.Data;
/**
*
*/
@Data
public class ProductBindOrderDTO {
/** 订单ID */
private Long id;
/** 订单编号 */
private String orderCode;
/** 项目ID */
private Long projectId;
/** 项目编号 */
private String projectCode;
/** 锁单量 */
private Integer bindNum;
/** 项目名称 */
private String projectName;
/** 支撑人员 */
private String userName;
}

View File

@ -0,0 +1,24 @@
package com.ruoyi.sip.dto.inventory;
import lombok.Data;
/**
*
*/
@Data
public class ProductInventoryInnerDTO {
/** 入库单ID */
private Long id;
/** 入库单号 */
private String innerCode;
/** 入库数量 */
private Long innerNum;
/** 在库现存 */
private Long inventoryNum;
/** 锁单量 */
private Long bindNum;
}

View File

@ -0,0 +1,15 @@
package com.ruoyi.sip.dto.inventory;
import lombok.Data;
/**
*
*/
@Data
public class ProductInventoryQueryDTO {
/** 产品编码 */
private String productCode;
/** 仓库ID */
private Long warehouseId;
}

View File

@ -897,6 +897,7 @@ public class ProjectOrderInfoToolProvider extends AbstractMcpToolProvider {
metadata.put("requiredDeliveryDate", "要求到货时间");
metadata.put("contractCode", "合同编号");
metadata.put("projectName", "项目名称");
metadata.put("h3cSales", "新华三销售");
metadata.put("agentName", "代表处");
metadata.put("orderStatus", "订单状态");
metadata.put("orderStockingStatus", "备货状态");

View File

@ -2,6 +2,8 @@ package com.ruoyi.sip.mapper;
import java.util.List;
import com.ruoyi.sip.domain.OmsInventoryInner;
import com.ruoyi.sip.dto.inventory.ProductInventoryInnerDTO;
import com.ruoyi.sip.dto.inventory.ProductInventoryQueryDTO;
/**
* Mapper
@ -70,4 +72,6 @@ public interface OmsInventoryInnerMapper
List<OmsInventoryInner> selectOmsInventoryInnerByOrderCodeList(List<String> orderCodeList);
List<OmsInventoryInner> selectOmsInventoryInnerByInnerCodeList(List<String> innerCodeList);
List<ProductInventoryInnerDTO> listInventoryInner(ProductInventoryQueryDTO query);
}

View File

@ -4,6 +4,8 @@ import java.util.List;
import com.ruoyi.sip.domain.OmsPurchaseOrder;
import com.ruoyi.sip.domain.OmsPurchaseOrderItem;
import com.ruoyi.sip.dto.inventory.OmsPurchaseOrderItemDto;
import com.ruoyi.sip.dto.inventory.ProductBindOrderDTO;
import com.ruoyi.sip.dto.inventory.ProductInventoryQueryDTO;
import org.apache.ibatis.annotations.Param;
/**
@ -103,6 +105,10 @@ public interface OmsPurchaseOrderMapper
List<OmsPurchaseOrderItemDto> listItem(OmsPurchaseOrderItemDto omsPurchaseOrder);
List<OmsPurchaseOrderItemDto> listPurchaseStock(ProductInventoryQueryDTO query);
List<ProductBindOrderDTO> listBindOrder(ProductInventoryQueryDTO query);
List<OmsPurchaseOrderItem> listByItemId(Long itemId);
void updateOmsPurchaseOrderItem(OmsPurchaseOrderItem updateItem);

View File

@ -15,4 +15,6 @@ public interface IDataProcessService {
void generateVirtualPurchase(String type);
AjaxResult omsHistoryProjectPushCRM();
}

View File

@ -6,6 +6,8 @@ import java.util.Map;
import com.ruoyi.sip.domain.InventoryInfo;
import com.ruoyi.sip.domain.OmsInventoryInner;
import com.ruoyi.sip.dto.inventory.InventoryInfoExcelDto;
import com.ruoyi.sip.dto.inventory.ProductInventoryInnerDTO;
import com.ruoyi.sip.dto.inventory.ProductInventoryQueryDTO;
/**
* Service
@ -23,6 +25,14 @@ public interface IOmsInventoryInnerService
*/
public OmsInventoryInner selectOmsInventoryInnerById(Long id);
/**
*
*
* @param id
* @return
*/
public OmsInventoryInner selectOmsInventoryInnerBaseById(Long id);
/**
*
*
@ -67,4 +77,6 @@ public interface IOmsInventoryInnerService
void importByOuter(List<InventoryInfo> inventoryInfoList, String productCode, String purchaseNo,Long itemId);
Map<String,Object> getInventoryInfoList(List<InventoryInfoExcelDto> inventoryInfoExcelDtoList, String productCode, String orderType);
Map<String,Object> validateAndGetAssignDeliveryList(List<InventoryInfoExcelDto> inventoryInfoExcelDtoList, String productCode, String orderType, String purchaseNo);
List<ProductInventoryInnerDTO> listInventoryInner(ProductInventoryQueryDTO query);
}

View File

@ -7,6 +7,8 @@ import com.ruoyi.sip.domain.AddToNexRes;
import com.ruoyi.sip.domain.OmsPurchaseOrder;
import com.ruoyi.sip.domain.OmsPurchaseOrderItem;
import com.ruoyi.sip.dto.inventory.OmsPurchaseOrderItemDto;
import com.ruoyi.sip.dto.inventory.ProductBindOrderDTO;
import com.ruoyi.sip.dto.inventory.ProductInventoryQueryDTO;
import com.ruoyi.sip.flowable.domain.Todo;
/**
@ -95,6 +97,10 @@ public interface IOmsPurchaseOrderService
List<OmsPurchaseOrderItemDto> listItem(OmsPurchaseOrderItemDto omsPurchaseOrder);
List<OmsPurchaseOrderItemDto> listPurchaseStock(ProductInventoryQueryDTO query);
List<ProductBindOrderDTO> listBindOrder(ProductInventoryQueryDTO query);
void innerWarehouse(Long itemId, Long quantity);
void cancelInnerItem(List<OmsPurchaseOrderItem> omsPurchaseOrderItems);

View File

@ -14,6 +14,7 @@ import com.ruoyi.sip.dto.UnboundPurchaseOrderProductDto;
import com.ruoyi.sip.dto.inventory.OmsPurchaseOrderItemDto;
import com.ruoyi.sip.mapper.*;
import com.ruoyi.sip.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
@ -22,15 +23,25 @@ import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ThreadContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class DataProcessServiceImpl implements IDataProcessService {
@ -65,6 +76,9 @@ public class DataProcessServiceImpl implements IDataProcessService {
@Resource
private ProjectOrderInfoMapper projectOrderInfoMapper;
@Resource
private PartnerInfoMapper partnerInfoMapper;
@Autowired
private IInventoryDeliveryService inventoryDeliveryService;
@ -77,6 +91,17 @@ public class DataProcessServiceImpl implements IDataProcessService {
@Value("${oms.inventory.innerTax:0.13}")
private String defaultTax;
@Value("${opportunity.integration.base-url:http://localhost:8080}")
private String opportunityBaseUrl;
@Value("${opportunity.integration.oms-history-import-path:/api/opportunities/integration/oms-history/import}")
private String omsHistoryImportPath;
@Value("${opportunity.integration.secret:f0eb247f84db4e328fb27ce8ff6e7be96e73a53a7e9c4793395ad10d999e0d77}")
private String opportunitySecret;
private final RestTemplate restTemplate = new RestTemplate();
@Override
public void inventoryInnerGeneratePayableBill(Long innerId) {
if (innerId == null) {
@ -258,6 +283,199 @@ public class DataProcessServiceImpl implements IDataProcessService {
}
}
@Override
public AjaxResult omsHistoryProjectPushCRM() {
if (StringUtils.isEmpty(opportunitySecret)) {
log.warn("OMS历史商机反写CRM终止opportunity.integration.secret 未配置");
return AjaxResult.error("opportunity.integration.secret 未配置");
}
String requestUrl = buildOmsHistoryImportUrl();
ProjectInfo query = new ProjectInfo();
// query.setUpdateTimeEnd(DateUtils.parseDate("2026-07-07 00:00:00"));
// query.setProjectCode("VDI0010");
List<ProjectInfo> projectInfoList = projectInfoMapper.selectProjectInfoList(query);
log.info("开始OMS历史商机反写CRM, total:{}, url:{}", projectInfoList.size(), requestUrl);
int success = 0;
int fail = 0;
List<Map<String, String>> errors = new ArrayList<>();
for (ProjectInfo projectInfo : projectInfoList) {
Map<String, Object> item = buildOmsHistoryOpportunityItem(projectInfo);
if (item == null) {
fail++;
String msg = "项目编号、项目名称";
errors.add(buildError(projectInfo, msg));
log.warn("OMS历史商机反写CRM跳过, projectId:{}, projectCode:{}, msg:{}", projectInfo == null ? null : projectInfo.getId(), projectInfo == null ? null : projectInfo.getProjectCode(), msg);
continue;
}
try {
log.info("调用OMS历史商机反写CRM接口, projectId:{}, projectCode:{}", projectInfo.getId(), projectInfo.getProjectCode());
log.info("OMS历史商机反写CRM请求体, projectId:{}, projectCode:{}, body:{}", projectInfo.getId(), projectInfo.getProjectCode(), item);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("X-Internal-Secret", opportunitySecret);
ResponseEntity<Map> responseEntity = restTemplate.exchange(requestUrl, HttpMethod.POST, new HttpEntity<>(item, headers), Map.class);
Map responseBody = responseEntity.getBody();
if (responseBody == null || !"0".equals(String.valueOf(responseBody.get("code")))) {
fail++;
String msg = responseBody == null ? "响应为空" : String.valueOf(responseBody.get("msg"));
errors.add(buildError(projectInfo, msg));
log.warn("OMS历史商机反写CRM失败并停止, projectId:{}, projectCode:{}, msg:{}, response:{}", projectInfo.getId(), projectInfo.getProjectCode(), msg, responseBody);
break;
}
success++;
log.info("OMS历史商机反写CRM成功, projectId:{}, projectCode:{}, response:{}", projectInfo.getId(), projectInfo.getProjectCode(), responseBody);
} catch (HttpStatusCodeException e) {
fail++;
String msg = "HTTP " + e.getRawStatusCode() + " " + e.getStatusText() + ", 响应: " + e.getResponseBodyAsString();
errors.add(buildError(projectInfo, msg));
log.error("OMS历史商机反写CRM异常并停止, projectId:{}, projectCode:{}, msg:{}", projectInfo.getId(), projectInfo.getProjectCode(), msg, e);
break;
} catch (RestClientException e) {
fail++;
errors.add(buildError(projectInfo, e.getMessage()));
log.error("OMS历史商机反写CRM异常并停止, projectId:{}, projectCode:{}", projectInfo.getId(), projectInfo.getProjectCode(), e);
break;
}
}
Map<String, Object> result = new LinkedHashMap<>();
result.put("total", projectInfoList.size());
result.put("success", success);
result.put("fail", fail);
result.put("errors", errors);
log.info("完成OMS历史商机反写CRM, total:{}, success:{}, fail:{}", projectInfoList.size(), success, fail);
return AjaxResult.success(result);
}
private Map<String, Object> buildOmsHistoryOpportunityItem(ProjectInfo projectInfo) {
if (projectInfo == null
|| StringUtils.isEmpty(projectInfo.getProjectCode())
|| StringUtils.isEmpty(projectInfo.getProjectName())) {
return null;
}
Map<String, Object> item = new LinkedHashMap<>();
item.put("opportunityCode", projectInfo.getProjectCode());
item.put("opportunityName", projectInfo.getProjectName());
item.put("customerName", projectInfo.getCustomerName());
putIfNotEmpty(item, "projectLocation", projectInfo.getAgentName());
putIfNotEmpty(item, "projectOwnershipLocation", projectInfo.getAgentName());
putIfNotEmpty(item, "operatorName", projectInfo.getOperateInstitution());
putIfNotNull(item, "amount", projectInfo.getEstimatedAmount());
BigDecimal actualSignedAmount = getActualSignedAmount(projectInfo.getId());
putIfNotNull(item, "actualSignedAmount", actualSignedAmount);
item.put("isPoc", StringUtils.equals("1", projectInfo.getPoc()));
putIfNotEmpty(item, "expectedCloseDate", formatDate(projectInfo.getEstimatedOrderTime()));
putIfNotEmpty(item, "confidencePct", projectInfo.getProjectGraspDegree());
putIfNotEmpty(item, "stage", projectInfo.getProjectStage());
putIfNotEmpty(item, "opportunityType", projectInfo.getConstructionType());
item.put("productType", "VDI云桌面");
item.put("source", "OMS历史导入");
putIfNotNull(item, "preSalesId", parseLong(projectInfo.getHzSupportUser()));
putIfNotEmpty(item, "preSalesName", projectInfo.getHzSupportUserName());
putIfNotEmpty(item, "competitorName", projectInfo.getCompetitor());
putIfNotEmpty(item, "description", projectInfo.getProjectDesc());
item.put("archived", actualSignedAmount != null);
item.put("pushedToOms", true);
item.put("omsPushTime", DateUtils.getTime());
Map<String, Object> salesExpansion = new LinkedHashMap<>();
putIfNotEmpty(salesExpansion, "mobile", projectInfo.getH3cPhone());
putIfNotEmpty(salesExpansion, "candidateName", projectInfo.getH3cPerson());
putIfNotEmpty(salesExpansion, "officeName", projectInfo.getAgentName());
putIfNotEmpty(salesExpansion, "industry", projectInfo.getIndustryType());
putIfNotEmpty(salesExpansion, "stage", projectInfo.getProjectStage());
salesExpansion.put("remark", "OMS历史导入销售拓展人员");
if (StringUtils.isNotEmpty(projectInfo.getH3cPhone())) {
item.put("salesExpansion", salesExpansion);
}
PartnerInfo partnerInfo = getPartnerInfo(projectInfo.getPartnerCode());
if (partnerInfo != null) {
Map<String, Object> channelExpansion = new LinkedHashMap<>();
putIfNotEmpty(channelExpansion, "channelCode", partnerInfo.getPartnerCode());
putIfNotEmpty(channelExpansion, "channelName", partnerInfo.getPartnerName());
putIfNotEmpty(channelExpansion, "officeAddress", partnerInfo.getAddress());
putIfNotEmpty(channelExpansion, "channelIndustry", projectInfo.getIndustryType());
putIfNotEmpty(channelExpansion, "contactName", partnerInfo.getContactPerson());
putIfNotEmpty(channelExpansion, "contactMobile", partnerInfo.getContactPhone());
putIfNotEmpty(channelExpansion, "province", partnerInfo.getProvince());
putIfNotEmpty(channelExpansion, "city", partnerInfo.getCity());
putIfNotEmpty(channelExpansion, "certificationLevel", partnerInfo.getLevel());
channelExpansion.put("remark", "OMS历史导入渠道");
item.put("channelExpansion", channelExpansion);
}
return item;
}
private PartnerInfo getPartnerInfo(String partnerCode) {
if (StringUtils.isEmpty(partnerCode)) {
return null;
}
List<PartnerInfo> partnerInfoList = partnerInfoMapper.selectPartnerInfoByCode(Collections.singletonList(partnerCode));
if (partnerInfoList == null || partnerInfoList.isEmpty()) {
log.warn("OMS历史商机反写CRM未找到渠道信息, partnerCode:{}", partnerCode);
return null;
}
return partnerInfoList.get(0);
}
private BigDecimal getActualSignedAmount(Long projectId) {
if (projectId == null) {
return null;
}
List<ProjectOrderInfo> orderInfoList = projectOrderInfoMapper.selectProjectOrderInfoByProjectId(Collections.singletonList(projectId));
if (orderInfoList == null || orderInfoList.isEmpty()) {
return null;
}
ProjectOrderInfo firstOrder = orderInfoList.get(0);
return firstOrder.getActualPurchaseAmount() != null ? firstOrder.getActualPurchaseAmount() : firstOrder.getShipmentAmount();
}
private String buildOmsHistoryImportUrl() {
String baseUrl = opportunityBaseUrl.endsWith("/") ? opportunityBaseUrl.substring(0, opportunityBaseUrl.length() - 1) : opportunityBaseUrl;
String path = omsHistoryImportPath.startsWith("/") ? omsHistoryImportPath : "/" + omsHistoryImportPath;
return baseUrl + path;
}
private String formatDate(Date date) {
if (date == null) {
return null;
}
return new SimpleDateFormat(DateUtils.YYYY_MM_DD).format(date);
}
private Long parseLong(String value) {
if (StringUtils.isEmpty(value)) {
return null;
}
try {
return Long.valueOf(value);
} catch (NumberFormatException e) {
return null;
}
}
private void putIfNotEmpty(Map<String, Object> map, String key, String value) {
if (StringUtils.isNotEmpty(value)) {
map.put(key, value);
}
}
private void putIfNotNull(Map<String, Object> map, String key, Object value) {
if (value != null) {
map.put(key, value);
}
}
private Map<String, String> buildError(ProjectInfo projectInfo, String msg) {
Map<String, String> error = new LinkedHashMap<>();
if (projectInfo != null) {
error.put("projectId", String.valueOf(projectInfo.getId()));
error.put("projectCode", projectInfo.getProjectCode());
}
error.put("msg", msg);
return error;
}
/**
*
*

View File

@ -15,6 +15,8 @@ import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.sip.domain.*;
import com.ruoyi.sip.dto.inventory.InventoryInfoExcelDto;
import com.ruoyi.sip.dto.inventory.OmsPurchaseOrderItemDto;
import com.ruoyi.sip.dto.inventory.ProductInventoryInnerDTO;
import com.ruoyi.sip.dto.inventory.ProductInventoryQueryDTO;
import com.ruoyi.sip.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -63,12 +65,25 @@ public class OmsInventoryInnerServiceImpl implements IOmsInventoryInnerService {
*/
@Override
public OmsInventoryInner selectOmsInventoryInnerById(Long id) {
OmsInventoryInner omsInventoryInner = omsInventoryInnerMapper.selectOmsInventoryInnerById(id);
OmsInventoryInner omsInventoryInner = selectOmsInventoryInnerBaseById(id);
if (omsInventoryInner != null && StringUtils.isNotEmpty(omsInventoryInner.getInnerCode())) {
InventoryInfo queryParams = new InventoryInfo();
queryParams.setInnerCode(omsInventoryInner.getInnerCode());
List<InventoryInfo> inventoryInfos = inventoryInfoService.selectInventoryInfoList(queryParams);
omsInventoryInner.setInventoryInfoList(inventoryInfos);
}
return omsInventoryInner;
}
@Override
public List<ProductInventoryInnerDTO> listInventoryInner(ProductInventoryQueryDTO query) {
return omsInventoryInnerMapper.listInventoryInner(query);
}
@Override
public OmsInventoryInner selectOmsInventoryInnerBaseById(Long id) {
OmsInventoryInner omsInventoryInner = omsInventoryInnerMapper.selectOmsInventoryInnerById(id);
if (omsInventoryInner != null && StringUtils.isNotEmpty(omsInventoryInner.getInnerCode())) {
OmsInventoryInner inventoryInfoSummary = omsInventoryInnerMapper.selectInventoryInfoSummaryByInnerCode(omsInventoryInner.getInnerCode());
if (inventoryInfoSummary != null) {
omsInventoryInner.setSumInnerPrice(inventoryInfoSummary.getSumInnerPrice());

View File

@ -16,6 +16,8 @@ import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.mail.TemplateMailUtil;
import com.ruoyi.sip.domain.*;
import com.ruoyi.sip.dto.inventory.OmsPurchaseOrderItemDto;
import com.ruoyi.sip.dto.inventory.ProductBindOrderDTO;
import com.ruoyi.sip.dto.inventory.ProductInventoryQueryDTO;
import com.ruoyi.sip.flowable.domain.Todo;
import com.ruoyi.sip.flowable.service.DeleteFlowableProcessInstanceCmd;
import com.ruoyi.sip.flowable.service.TodoCommonTemplate;
@ -361,6 +363,16 @@ public class OmsPurchaseOrderServiceImpl implements IOmsPurchaseOrderService, To
return omsPurchaseOrderMapper.listItem(omsPurchaseOrder);
}
@Override
public List<OmsPurchaseOrderItemDto> listPurchaseStock(ProductInventoryQueryDTO query) {
return omsPurchaseOrderMapper.listPurchaseStock(query);
}
@Override
public List<ProductBindOrderDTO> listBindOrder(ProductInventoryQueryDTO query) {
return omsPurchaseOrderMapper.listBindOrder(query);
}
@Override
public void innerWarehouse(Long itemId, Long quantity) {
List<OmsPurchaseOrderItem> omsPurchaseOrderItems = omsPurchaseOrderMapper.listByItemId(itemId);

View File

@ -89,6 +89,27 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
from oms_inventory_info
where inner_code = #{innerCode}
</select>
<select id="listInventoryInner" resultType="com.ruoyi.sip.dto.inventory.ProductInventoryInnerDTO">
select
t1.id,
t1.inner_code,
count(1) as inner_num,
sum(if(t2.inventory_status = 0, 1, 0)) as inventory_num,
(
select sum(tt2.bind_num)
from oms_purchase_order as tt1
inner join oms_purchase_order_map as tt2 on tt1.id = tt2.purchase_id
where tt1.purchase_no = t1.purchase_no and tt2.product_code = t2.product_code
) as bind_num
from oms_inventory_inner as t1
inner join oms_inventory_info as t2 on t1.inner_code = t2.inner_code
<where>
<if test="productCode != null and productCode != ''">and t2.product_code = #{productCode}</if>
<if test="warehouseId != null">and t2.warehouse_id = #{warehouseId}</if>
</where>
group by t1.id
order by t1.create_time desc
</select>
<select id="selectMaxOrderCode" resultType="java.lang.Integer">
select ifnull( max(SUBSTR( inner_code FROM LENGTH(#{code})+1 FOR 3 )), 0 )
from oms_inventory_inner

View File

@ -249,6 +249,44 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
order by t2.create_time desc
</select>
<select id="listPurchaseStock" resultType="com.ruoyi.sip.dto.inventory.OmsPurchaseOrderItemDto">
select
t1.id,
t1.purchase_no,
t2.product_code,
t1.warehouse_id,
t2.quantity - t2.inner_quantity as purchase_num,
t1.purchaser_name
from oms_purchase_order as t1
inner join oms_purchase_order_item as t2 on t1.id = t2.purchase_id
<where>
<if test="productCode != null and productCode != ''">and t2.product_code = #{productCode}</if>
<if test="warehouseId != null">and t1.warehouse_id = #{warehouseId}</if>
and t2.quantity - t2.inner_quantity &gt; 0
</where>
order by t1.create_time desc
</select>
<select id="listBindOrder" resultType="com.ruoyi.sip.dto.inventory.ProductBindOrderDTO">
select
t1.id,
t1.order_code,
t4.id as project_id,
t4.project_code,
sum(t2.bind_num) as bind_num,
t4.project_name,
t5.user_name
from project_order_info as t1
inner join oms_purchase_order_map as t2 on t1.id = t2.order_id
inner join oms_purchase_order as t3 on t2.purchase_id = t3.id
inner join project_info as t4 on t1.project_id = t4.id
inner join sys_user as t5 on t4.hz_support_user = t5.user_id
<where>
<if test="productCode != null and productCode != ''">and t2.product_code = #{productCode}</if>
<if test="warehouseId != null">and t3.warehouse_id = #{warehouseId}</if>
</where>
group by t1.id
order by t1.create_time desc
</select>
<select id="listByItemId" resultType="com.ruoyi.sip.domain.OmsPurchaseOrderItem">
<include refid="selectOmsPurchaseOrderItemVo"/>
inner JOIN oms_purchase_order_item opoi ON t1.purchase_id = opoi.purchase_id

View File

@ -22,6 +22,11 @@
<result property="localization" column="localization" />
<result property="cpuBrand" column="cpu_brand" />
<result property="cpuArchitecture" column="cpu_architecture" />
<result property="inventoryNum" column="inventory_num" />
<result property="outerNum" column="outer_num" />
<result property="purchaseNum" column="purchase_num" />
<result property="bindNum" column="bind_num" />
<result property="usableNum" column="usable_num" />
</resultMap>
<sql id="selectProductInfoVo">
@ -125,16 +130,36 @@
</where>
</select>
<select id="listInventory" resultType="com.ruoyi.sip.domain.ProductInfo">
SELECT t4.warehouse_name,
ifnull(t2.warehouse_id, t3.warehouse_id) as warehouse_id,
t3.vendor_name,
t1.*,
t2.inventory_count
SELECT
t4.warehouse_name,
ifnull(t2.warehouse_id, t3.warehouse_id) as warehouse_id,
t3.vendor_name,
t1.*,
t2.inventory_num,
t2.outer_num,
t2.purchase_num,
t2.bind_num,
ifnull(t2.inventory_num,0) + ifnull(t2.purchase_num,0) as usable_num
FROM product_info t1
LEFT JOIN (SELECT product_code, warehouse_id, count(1) as inventory_count
FROM oms_inventory_info
WHERE inventory_status = 0
GROUP BY product_code, warehouse_id) t2 ON t1.product_code = t2.product_code
LEFT JOIN (
SELECT product_code, warehouse_id,
sum((case when inventory_status = 0 then 1 else 0 end)) as inventory_num,
sum((case when inventory_status = 1 then 1 else 0 end)) as outer_num,
(
select sum(tt2.quantity) - sum(tt2.inner_quantity)
from oms_purchase_order_item as tt2
inner join oms_purchase_order as tt3 on tt2.purchase_id = tt3.id
where tt1.product_code = tt2.product_code and tt3.warehouse_id = tt1.warehouse_id
) as purchase_num,
(
select sum(bind_num) from oms_purchase_order as tt2
inner join oms_purchase_order_map as tt3 on tt2.id = tt3.purchase_id
where tt1.product_code = tt3.product_code
and tt1.warehouse_id = tt2.warehouse_id
) as bind_num
FROM oms_inventory_info as tt1
GROUP BY product_code, warehouse_id
) t2 ON t1.product_code = t2.product_code
left join oms_vendor_info t3 on t1.vendor_code = t3.vendor_code
left join oms_warehouse_info t4 on t4.id = ifnull(t2.warehouse_id, t3.warehouse_id)
<where>