feat(customer): 客户编码自动生成并优化相关功能

-客户编码改为自动生成,无需手动输入
- 添加生成客户编码的逻辑和接口
- 修改客户信息保存逻辑,支持自动生成编码
- 优化客户信息编辑界面,使编码字段只读
dev_1.0.0
chenhao 2025-08-20 14:46:24 +08:00
parent 5bf1250714
commit f85e557d1c
20 changed files with 358 additions and 116 deletions

View File

@ -519,7 +519,7 @@
formatter: function (value, row, index) {
var actions = [];
let disabled = Number(row.quantity) <= Number(row.generatedQuantity) + Number(row.confirmQuantity)
actions.push(`<a class="btn btn-default btn-sm " href="javascript:void(0)" ${disabled?'disabled':''}
actions.push(`<a class="btn btn-success btn-sm " href="javascript:void(0)" ${disabled?'disabled':''}
onclick="checkOut(\'${row.productCode}\',\'${row.model}\',\'${row.vendorName}\',\'${row.quantity}\',\'${row.generatedQuantity}\',\'${row.confirmQuantity}\',\'[[${projectOrderInfo.id}]]\')">出库</a>`);
return actions.join('');
}
@ -555,7 +555,7 @@ function initWarehouseTable(data) {
},
{
field: 'availableCount',
title: '实时库存'
title: '实时库存'
},
{
field: 'confirmQuantity',
@ -762,12 +762,12 @@ function initWarehouseTable(data) {
var actions = [];
if (row.outerStatus === '1' || row.outerStatus === '4') {
actions.push(`<a class="btn btn-danger btn-sm " style="margin:0px 5px" href="javascript:void(0)" onclick="deleteOuter('${row.id}','${row.orderCode}')">撤销</a>`);
actions.push(`<a class="btn btn-default btn-sm " href="javascript:void(0)" onclick="updateStatus('${row.id}','${row.orderCode}')">确认出库</a>`);
actions.push(`<a class="btn btn-default btn-sm " href="javascript:void(0)" onclick="updateStatus('${row.id}','${row.orderCode}')">确认出库</a>`);
} else {
// actions.push('<a class="btn btn-default btn-xs " href="javascript:void(0)" onclick="viewOuter(' + row.id + ')">查看详情</a>');
actions.push(`<a class="btn btn-default btn-sm " href="javascript:void(0)" onclick="$.modal.popupRight( '订单执行跟踪详情', outerPrefix+'/view/${row.id}');">查看详情</a>`);
actions.push(`<a class="btn btn-success btn-sm " href="javascript:void(0)" onclick="$.modal.popupRight( '订单执行跟踪详情', outerPrefix+'/view/${row.id}');">查看详情</a>`);
}
return actions.join('');
}

View File

@ -110,6 +110,7 @@
</div>
<form class="form-horizontal m" id="generateDeliveryForm">
<div class="col-xs-12">
<input type="hidden" id="deliveryQuantity">
<table>
<tr>
<td><label class="control-label is-required">物流单号:</label></td>
@ -172,6 +173,75 @@
var productPrefix = ctx + "inventory/info";
var deliveryPrefix = ctx + "inventory/delivery";
const showReturnFlag = [[${deliveryList}]] && [[${deliveryList.size()}]]>0;
let productSnData = [];
let productSnOptions = {
id: 'bootstrap-table',
url: productPrefix + "/list",
modalName: "出库单",
onCheck: (row, $ele) => {
updateTotal()
},
onUncheck: (row, $ele) => {
if (productSnData.length > 0) {
$('#bootstrap-table').bootstrapTable('checkAll');
$.modal.msgError("导入数据不允许取消勾选")
return
}
updateTotal()
},
onCheckAll: (rowsAfter, rowsBefore) => {
updateTotal()
},
onUncheckAll: (rowsAfter, rowsBefore) => {
if (productSnData.length > 0) {
$('#bootstrap-table').bootstrapTable('checkAll');
$.modal.msgError("导入数据不允许取消勾选")
return
}
updateTotal()
},
onLoadSuccess: (data) => {
$('#bootstrap-table').bootstrapTable('checkAll');
},
showSearch: false,
showRefresh: false,
showToggle: false,
showColumns: false,
rememberSelected: true,
formId: "query-product-sn",
columns: [{
field: 'state',
checkbox: true
},
{
field: 'id',
title: '',
visible: false
},
{
field: 'productSn',
title: 'SN码'
},
{
field: 'productCode',
title: '产品编码'
},
{
field: 'model',
title: '产品型号'
},
{
field: 'productDesc',
title: '描述'
},
{
field: 'warehouseName',
title: '仓库'
}]
};
$("#form-outer-edit").validate({
focusCleanup: true
});
@ -197,6 +267,7 @@
let data = new FormData()
data.append('file', file)
data.append('productCode', $('[name="productCode"]').val())
data.append('quantity', Number($('#deliveryQuantity').val()))
var xhr = new XMLHttpRequest(); // 创建XMLHttpRequest对象
xhr.open('POST', prefix + '/importData', true); // 设置请求类型和URL
// 当请求完成时执行的回调函数
@ -204,7 +275,17 @@
let data = JSON.parse(res.currentTarget.response)
if (data.code === 0) {
$.modal.msgSuccess('上传成功');
$.table.search('query-product-sn', 'bootstrap-table')
productSnData = data.data;
$.table.refreshOptions($.extend(productSnOptions, {
url: '',
data: productSnData,
pagination: false
}), 'bootstrap-table')
setTimeout(() => {
$('#bootstrap-table').bootstrapTable('checkAll');
}, 200);
$('#bootstrap-table').before(`<div ><span>已选:</span><span id="table-select-count">${productSnData.length}</span><span>(台)</span></div>`);
// $.table.search('query-product-sn', 'bootstrap-table')
} else {
top.layer.alert(data.msg || '导入失败', {
icon: 2,
@ -272,61 +353,10 @@
}
}
function initProductSnTable() {
var options = {
id: 'bootstrap-table',
url: productPrefix + "/list",
modalName: "出库单",
onCheck: (row, $ele) => {
updateTotal()
},
onUncheck: (row, $ele) => {
updateTotal()
},
onCheckAll: (rowsAfter, rowsBefore) => {
updateTotal()
},
onUncheckAll: (rowsAfter, rowsBefore) => {
updateTotal()
},
showSearch: false,
showRefresh: false,
showToggle: false,
showColumns: false,
rememberSelected: true,
formId: "query-product-sn",
columns: [{
field: 'state',
checkbox: true
},
{
field: 'id',
title: '',
visible: false
},
{
field: 'productSn',
title: 'SN码'
},
{
field: 'productCode',
title: '产品编码'
},
{
field: 'model',
title: '产品型号'
},
{
field: 'productDesc',
title: '描述'
},
{
field: 'warehouseName',
title: '仓库'
}]
};
$.table.init(options);
function initProductSnTable() {
$.table.init(productSnOptions);
$('#bootstrap-table').before('<div ><span>已选:</span><span id="table-select-count">0</span><span>(台)</span></div>');
}
@ -335,7 +365,7 @@
if ($tableCount.length > 0) {
// 延迟100毫秒等待表格渲染完成
setTimeout(function () {
$tableCount.text($.table.selectColumns("productSn").length);
$tableCount.text(productSnData.length > 0 ? productSnData.length : $.table.selectColumns("productSn").length);
}, 100)
}
}
@ -398,7 +428,7 @@
formatter: function (value, row, index) {
var actions = [];
let disabled = Number(row.quantity) <= Number(row.deliveryGenerateQuantity) + Number(row.deliveryConfirmQuantity)
actions.push(`<span class="btn btn-default btn-sm " href="javascript:void(0)" ${disabled ? 'style="pointer-events: none;" disabled' : ''} onclick="checkDelivery(\'${row.quantity}\',\'${row.warehouseId}\','${row.productCode}')">发货</span>`);
actions.push(`<span class="btn btn-success btn-sm " href="javascript:void(0)" ${disabled ? 'style="pointer-events: none;" disabled' : ''} onclick="checkDelivery(\'${row.quantity}\',\'${row.warehouseId}\','${row.productCode}')">发货</span>`);
return actions.join('');
}
}]
@ -412,12 +442,18 @@
let width = 1000, height = 700
parent.$('.layui-layer-btn').css('display', 'none')
parent.$('.layui-layer-setwin').css('display', 'none')
$('#deliveryQuantity').val(quantity)
$('[name="warehouseId"]').val(warehouseId)
$('[name="productCode"]').val(productCode)
$('[name="inventoryStatus"]').val(0)
$('#query-product-sn [name="outerCode"]').val('')
$.table.search('query-product-sn', 'bootstrap-table')
productSnData = []
$.table.refreshOptions($.extend(productSnOptions, {
url: productPrefix + "/list",
pagination: true,
pageSize: quantity
}), 'bootstrap-table')
$('#bootstrap-table').before('<div ><span>已选:</span><span id="table-select-count">0</span><span>(台)</span></div>');
$('#table-select-count').text(0);
let index = layer.open({
id: 'generate_delivery',
@ -432,15 +468,25 @@
$.modal.msgError('物流单号必填')
return;
}
var arrays = $.table.selectColumns("productSn");
if (arrays.length != quantity) {
$.modal.msgError(`产品选中数量应与发货数量一致,应发货数量为[${quantity}]`)
return
let arrays = []
if (productSnData.length <= 0) {
arrays = $.table.selectColumns("productSn");
if (arrays.length != quantity) {
$.modal.msgError(`产品选中数量应与发货数量一致,应发货数量为[${quantity}]`)
return
}
} else {
if (productSnData.length != quantity) {
$.modal.msgError(`产品选中数量应与发货数量一致,应发货数量为[${quantity}]`)
return
}
}
//保存数据
let data = {
productSnList: arrays,
logisticsCode: $('#logisticsCode').val(),
productCode: productCode,
quantity: quantity,
warehouseId: warehouseId,
logisticsCompany: $('#logisticsCompany').val(),
@ -448,6 +494,7 @@
deliveryTime: $('#deliveryTime').val(),
deliveryTimeType: $('#deliveryTimeType').val(),
outerCode: $('[name="outerCode"]').val(),
productSnDataList: productSnData,
}
var config = {
url: deliveryPrefix + "/add",
@ -460,18 +507,22 @@
$.modal.disable();
},
success: function (result) {
if (result.code != 0) {
$.modal.closeLoading();
$.modal.enable();
$.modal.msgError(result.msg)
return
}
if (typeof callback == "function") {
callback(result);
}
refreshTable()
$.modal.closeLoading();
$.modal.enable();
layer.close(index);
}
};
$.ajax(config)
layer.close(index);
},
end: function () {
parent.$('.layui-layer-btn').css('display', '')

View File

@ -129,7 +129,7 @@
actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.editFull(\'' + row.id + '\')"><i class="fa fa-edit"></i>编辑</a> ');
} else {
actions.push('<a class="btn btn-default btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="refundable(\'' + row.id + '\',\''+row.orderCode+'\')">退回</a> ');
actions.push('<a class="btn btn-default btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="received(\'' + row.id + '\')">确认接收</a>');
actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="received(\'' + row.id + '\')">确认接收</a>');
}
return actions.join('');
}
@ -140,11 +140,11 @@
function received(id) {
$.modal.confirm("确认要确认接收吗?", function () {
// $.modal.confirm("确认要确认接收吗?", function () {
$.operate.post(prefix + "/status", {"id": id, "outerStatus": '3'},()=>{
// $.table.refresh()
});
})
// })
}
function refundable(id,orderCode) {

View File

@ -9,9 +9,9 @@
<form class="form-horizontal m" id="form-info-add">
<div class="col-xs-6">
<div class="form-group">
<label class="col-sm-5 control-label is-required">客户编码:</label>
<label class="col-sm-5 control-label ">客户编码:</label>
<div class="col-sm-7">
<input name="customerCode" class="form-control" type="text" required>
<input name="customerCode" class="form-control" type="text" readonly placeholder="自动生成">
</div>
</div>
</div>

View File

@ -12,7 +12,7 @@
<div class="form-group">
<label class="col-sm-5 control-label is-required">客户编码:</label>
<div class="col-sm-7">
<input name="customerCode" th:field="*{customerCode}" class="form-control" type="text" required>
<input name="customerCode" th:field="*{customerCode}" class="form-control" type="text" readonly required>
</div>
</div>
</div>

View File

@ -171,7 +171,7 @@ public class InventoryOuterController extends BaseController
@PostMapping("/importData")
@ResponseBody
public AjaxResult importTemplate(@RequestPart("file") MultipartFile file, @RequestParam(value = "productCode") String productCode) {
public AjaxResult importTemplate(@RequestPart("file") MultipartFile file, @RequestParam(value = "productCode") String productCode,@RequestParam(value = "quantity") Long quantity) {
ExcelUtil<InventoryInfoExcelDto> util = new ExcelUtil<InventoryInfoExcelDto>(InventoryInfoExcelDto.class);
try (InputStream inputStream = file.getInputStream()) {
@ -179,7 +179,10 @@ public class InventoryOuterController extends BaseController
if (CollUtil.isEmpty(inventoryInfoExcelDtoList)){
return AjaxResult.error("导入数据为空");
}
innerService.importByOuter(inventoryInfoExcelDtoList, productCode);
if (inventoryInfoExcelDtoList.size()!=quantity.intValue()){
return AjaxResult.error("导入数据应等于发货数量");
}
return AjaxResult.success(innerService.getInventoryInfoList(inventoryInfoExcelDtoList, productCode));
} catch (IOException e) {
throw new ServiceException("读取excel错误,请联系管理员");
@ -187,8 +190,6 @@ public class InventoryOuterController extends BaseController
return AjaxResult.error(e.getMessage());
}
return AjaxResult.success();
}

View File

@ -73,6 +73,7 @@ public class InventoryDelivery extends BaseEntity
private String deliveryStatus;
private List<String> productSnList;
private List<InventoryInfo> productSnDataList;

View File

@ -18,10 +18,15 @@ import com.ruoyi.sip.flowable.service.TodoService;
import com.ruoyi.system.service.ISysUserService;
import lombok.SneakyThrows;
import org.apache.commons.lang3.ObjectUtils;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.common.engine.impl.el.ExpressionManager;
import org.flowable.common.engine.impl.el.JuelExpression;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
import org.flowable.engine.delegate.event.FlowableMultiInstanceActivityCompletedEvent;
import org.flowable.engine.delegate.event.FlowableMultiInstanceActivityEvent;
import org.flowable.engine.delegate.event.FlowableProcessStartedEvent;
import org.flowable.engine.delegate.event.impl.FlowableEntityWithVariablesEventImpl;
@ -35,6 +40,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
@ -88,6 +94,53 @@ public class ProcessListener extends AbstractFlowableEngineEventListener {
super.multiInstanceActivityStarted(event);
}
@SneakyThrows
@Override
protected void multiInstanceActivityCompletedWithCondition(FlowableMultiInstanceActivityCompletedEvent event) {
if ("userTask".equals(event.getActivityType())) {
log.info("多实例任务完成 start--------");
String processInstanceId = event.getProcessInstanceId();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
{
List<Todo> todos = todoService.selectTodoListByProcessInstanceId(new Todo().setProcessInstanceId(processInstanceId));
if (ObjectUtils.isNotEmpty(todos)) {
String ids = todos.stream().map(Todo::getTodoId).map(String::valueOf).collect(Collectors.joining(","));
todoService.deleteTodoByIds(ids);
log.error("待办任务删除成功 {}", ids);
}
// 处理业务回调 - 添加默认回调逻辑
Instance instance = processConfig.getInstance();
String processDefinitionId = processInstance.getProcessDefinitionKey();
try {
Method method1 = BeanUtils.findMethod(instance.getClass(),
"get" + processDefinitionId.substring(0, 1).toUpperCase() + processDefinitionId.substring(1));
if (method1 != null) {
// 默认多实例回调
TodoCommonTemplate todoExecuteInstance = todoService.getTodoExecuteInstance(
new Todo().setProcessKey(processDefinitionId));
if (todoExecuteInstance != null) {
Method multiInstanceCallbackMethod = BeanUtils.findMethod(
todoExecuteInstance.getClass(), "multiInstanceApproveCallback", String.class,ProcessInstance.class);
if (multiInstanceCallbackMethod != null) {
multiInstanceCallbackMethod.invoke(todoExecuteInstance, event.getActivityName(),processInstance);
log.error("默认多实例回调执行成功");
}
}
}
} catch (Exception e) {
log.error("多实例回调执行异常", e);
}
}
}
super.multiInstanceActivityCompletedWithCondition(event);
}
@Override
protected void taskCreated(FlowableEngineEntityEvent event) {
@ -127,11 +180,10 @@ public class ProcessListener extends AbstractFlowableEngineEventListener {
if(!"noTodo".equals(taskEntity.getCategory())) {
List<Todo> todos = todoService.selectTodoListByProcessInstanceId(new Todo().setProcessInstanceId(taskEntity.getProcessInstanceId()));
if (ObjectUtils.isNotEmpty(todos)) {
String ids = todos.stream().map(Todo::getTodoId).map(String::valueOf).collect(Collectors.joining(","));
Integer btn = null;
todoService.deleteTodoByIds(ids);
log.error("待办任务删除成功 {}", ids);
Todo todo = todos.stream().filter(d -> d.getTaskId().equals(taskEntity.getId())).findFirst().get();
todoService.deleteTodoByIds(String.valueOf(todo.getTodoId()));
log.error("待办任务删除成功 {}", todo.getId());
if (event instanceof FlowableEntityWithVariablesEventImpl) {
Map variables = ((FlowableEntityWithVariablesEventImpl) event).getVariables();
log.error("variables {}", ObjectUtils.isNotEmpty(variables) ? JSON.toJSONString(variables) : "无数据");

View File

@ -2,6 +2,7 @@ package com.ruoyi.sip.flowable.service;
import com.ruoyi.sip.flowable.domain.Todo;
import org.flowable.engine.runtime.ProcessInstance;
/**
*
@ -39,6 +40,10 @@ public interface TodoCommonTemplate {
//默认实现
return true;
}
default boolean multiInstanceApproveCallback(String activityName,ProcessInstance processInstance) {
//默认实现
return true;
}
}

View File

@ -61,4 +61,6 @@ public interface CustomerInfoMapper
*/
public int deleteCustomerInfoByIds(String[] ids);
public int selectCountByCode(CustomerInfo customerInfo);
int selectMaxByPrefix(String province);
}

View File

@ -70,4 +70,5 @@ public interface InventoryInfoMapper
List<InventoryInfo> countBySn(List<String> productSnList);
void deleteInventoryInfoByInnerIds(String[] idArray);
List<InventoryInfo> listInventoryInfoByInnerIds(String[] idArray);
}

View File

@ -2,6 +2,7 @@ package com.ruoyi.sip.service;
import java.util.List;
import com.ruoyi.sip.domain.InventoryInfo;
import com.ruoyi.sip.domain.OmsInventoryInner;
import com.ruoyi.sip.dto.inventory.InventoryInfoExcelDto;
@ -62,5 +63,6 @@ public interface IOmsInventoryInnerService
public int deleteOmsInventoryInnerById(Long id);
void importByOuter(List<InventoryInfoExcelDto> inventoryInfoExcelDtoList, String productCode);
void importByOuter(List<InventoryInfo> inventoryInfoList,String productCode);
List<InventoryInfo> getInventoryInfoList(List<InventoryInfoExcelDto> inventoryInfoExcelDtoList, String productCode);
}

View File

@ -2,10 +2,14 @@ package com.ruoyi.sip.service.impl;
import java.util.List;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.sip.domain.Cnarea;
import com.ruoyi.sip.domain.CustomerInfo;
import com.ruoyi.sip.mapper.CustomerInfoMapper;
import com.ruoyi.sip.service.ICnareaService;
import com.ruoyi.sip.service.ICustomerInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -23,7 +27,8 @@ public class CustomerInfoServiceImpl implements ICustomerInfoService
{
@Autowired
private CustomerInfoMapper customerInfoMapper;
@Autowired
private ICnareaService cnareaService;
/**
*
*
@ -58,6 +63,7 @@ public class CustomerInfoServiceImpl implements ICustomerInfoService
public int insertCustomerInfo(CustomerInfo customerInfo)
{
customerInfo.setCreateBy(ShiroUtils.getUserId().toString());
customerInfo.setCustomerCode(generateCode(customerInfo.getProvince()));
int i = customerInfoMapper.selectCountByCode(customerInfo);
if (i > 0){
throw new ServiceException("客户编码已存在");
@ -65,6 +71,28 @@ public class CustomerInfoServiceImpl implements ICustomerInfoService
return customerInfoMapper.insertCustomerInfo(customerInfo);
}
private String generateCode(String province) {
if (StringUtils.isEmpty(province)) {
throw new ServiceException("客户所属省为空,无法生成客户编码");
}
Cnarea cnarea = new Cnarea();
cnarea.setName(province);
cnarea.setLevel("1");
List<Cnarea> cnareas = cnareaService.queryAll(cnarea);
if (CollUtil.isEmpty(cnareas)) {
throw new ServiceException("省市未配置,生成订单编号出错,请联系管理员");
}
String shortCode = cnareas.get(0).getShortCode();
StringBuilder result = new StringBuilder();
result.append("CU-");
result.append(shortCode);
result.append("-");
int count = customerInfoMapper.selectMaxByPrefix(result.toString());
// 生成顺序编码,不足四位补零
String sequence = String.format("%04d", count + 1);
result.append(sequence);
return result.toString();
}
/**
*
*
@ -75,10 +103,35 @@ public class CustomerInfoServiceImpl implements ICustomerInfoService
public int updateCustomerInfo(CustomerInfo customerInfo)
{
customerInfo.setUpdateBy(ShiroUtils.getUserId().toString());
int i = customerInfoMapper.selectCountByCode(customerInfo);
if (i > 0){
throw new ServiceException("客户编码已存在");
// 检查客户编码是否已存在(排除当前记录)
// CustomerInfo queryParam = new CustomerInfo();
// queryParam.setCustomerCode(customerInfo.getCustomerCode());
// List<CustomerInfo> customerInfoList = customerInfoMapper.selectCustomerInfoList(queryParam);
//
// if (CollUtil.isNotEmpty(customerInfoList)) {
// CustomerInfo existInfo = customerInfoList.get(0);
// // 如果编码已存在且不是当前正在更新的记录,则抛出异常
// if (!existInfo.getId().equals(customerInfo.getId())) {
// throw new ServiceException("客户编码已存在");
// }
// }
// 如果省份发生变化,需要重新生成客户编码
CustomerInfo oldCustomerInfo = customerInfoMapper.selectCustomerInfoById(customerInfo.getId());
if (oldCustomerInfo != null && !oldCustomerInfo.getProvince().equals(customerInfo.getProvince())) {
String newCustomerCode = generateCode(customerInfo.getProvince());
customerInfo.setCustomerCode(newCustomerCode);
// 检查新生成的编码是否已存在
CustomerInfo codeCheckParam = new CustomerInfo();
codeCheckParam.setCustomerCode(newCustomerCode);
int count = customerInfoMapper.selectCountByCode(codeCheckParam);
if (count > 0) {
throw new ServiceException("客户编码已存在");
}
}
return customerInfoMapper.updateCustomerInfo(customerInfo);
}

View File

@ -2,6 +2,7 @@ package com.ruoyi.sip.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.sip.domain.*;
import com.ruoyi.sip.dto.inventory.ProductDetail;
import com.ruoyi.sip.dto.inventory.ProductWarehouseInfo;
@ -182,9 +183,15 @@ public class ExecutionTrackServiceImpl implements IExecutionTrackService {
}
// 如果仍有未满足的需求,尝试使用默认仓库
if (remainingQuantity > 0) {
List<ProductInfo> productInfoList = productInfoService.selectProductInfoByCodeList(Collections.singletonList(productCode));
if (CollUtil.isEmpty(productInfoList)) {
throw new ServiceException("产品编码对应产品未找到");
}
ProductInfo productInfo = productInfoList.get(0);
List<VendorInfo> currentVendors = inventoryAuthService.currentVendor();
if (CollUtil.isNotEmpty(currentVendors)) {
VendorInfo defaultVendor = currentVendors.get(0);
boolean vendorAuthFlag = currentVendors.stream().anyMatch(item -> item.getVendorCode().equals(productInfo.getVendorCode()));
if (CollUtil.isNotEmpty(currentVendors) && vendorAuthFlag) {
VendorInfo defaultVendor = currentVendors.stream().filter(item -> item.getVendorCode().equals(productInfo.getVendorCode())).findFirst().orElseThrow(() -> new ServiceException("制造商未授权"));
// 检查默认仓库是否已经在列表中
boolean defaultVendorInList = productWarehouseInfoList.stream()
@ -196,8 +203,7 @@ public class ExecutionTrackServiceImpl implements IExecutionTrackService {
defaultWarehouseInfo.setWarehouseId(defaultVendor.getWarehouseId());
defaultWarehouseInfo.setWarehouseName(defaultVendor.getWarehouseName());
// 这里假设默认仓库有足够库存,实际应用中可能需要查询具体库存
List<ProductInfo> productInfos = productInfoService.selectProductInfoByCodeList(Collections.singletonList(productCode));
defaultWarehouseInfo.setAvailableCount(productInfos.get(0).getAvailableCount() == null ? 0L : productInfos.get(0).getAvailableCount());
defaultWarehouseInfo.setAvailableCount(productInfo.getAvailableCount() == null ? 0L : productInfo.getAvailableCount());
defaultWarehouseInfo.setConfirmQuantity((long) remainingQuantity);
defaultWarehouseInfo.setDefaultWarehouse(true);
productWarehouseInfoList.add(defaultWarehouseInfo);

View File

@ -35,6 +35,8 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService {
private InventoryDeliveryMapper inventoryDeliveryMapper;
@Autowired
private IInventoryInfoService inventoryInfoService;
@Autowired
private IOmsInventoryInnerService omsInventoryInnerService;
@Resource
private InventoryOuterMapper inventoryOuterMapper;
@Autowired
@ -74,27 +76,42 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService {
*/
@Override
public int insertInventoryDelivery(InventoryDelivery inventoryDelivery) {
inventoryDelivery.setCreateTime(DateUtils.getNowDate());
Date nowDate = DateUtils.getNowDate();
inventoryDelivery.setCreateTime(nowDate);
String currentUserId = ShiroUtils.getUserId().toString();
inventoryDelivery.setCreateBy(currentUserId);
inventoryDelivery.setCreateTime(DateUtils.getNowDate());
inventoryDelivery.setCreateTime(nowDate);
inventoryDelivery.setUpdateBy(currentUserId);
inventoryDelivery.setUpdateTime(DateUtils.getNowDate());
inventoryDelivery.setUpdateTime(nowDate);
inventoryDelivery.setDeliveryStatus(InventoryDelivery.DeliveryStatusEnum.WAIT_DELIVERY.getCode());
//处理库存
List<String> productSnList = inventoryDelivery.getProductSnList();
if (CollUtil.isEmpty(productSnList)) {
List<InventoryInfo> productSnDataList = inventoryDelivery.getProductSnDataList();
if (CollUtil.isEmpty(productSnList) && CollUtil.isEmpty(productSnDataList)) {
throw new ServiceException("发货清单为空,保存失败");
}
List<InventoryInfo> inventoryInfoList = productSnList.stream().map(item -> {
InventoryInfo info = new InventoryInfo();
info.setProductSn(item);
info.setOuterCode(inventoryDelivery.getOuterCode());
info.setInventoryStatus(InventoryInfo.InventoryStatusEnum.OUTER.getCode());
info.setUpdateBy(currentUserId);
return info;
}).collect(Collectors.toList());
inventoryInfoService.saveBatch(inventoryInfoList);
if (CollUtil.isEmpty(productSnDataList)) {
List<InventoryInfo> inventoryInfoList = productSnList.stream().map(item -> {
InventoryInfo info = new InventoryInfo();
info.setProductSn(item);
info.setOuterCode(inventoryDelivery.getOuterCode());
info.setInventoryStatus(InventoryInfo.InventoryStatusEnum.OUTER.getCode());
info.setUpdateBy(currentUserId);
info.setUpdateTime(nowDate);
return info;
}).collect(Collectors.toList());
inventoryInfoService.saveBatch(inventoryInfoList);
}else{
for (InventoryInfo inventoryInfo : productSnDataList) {
inventoryInfo.setInventoryStatus(InventoryInfo.InventoryStatusEnum.OUTER.getCode());
inventoryInfo.setOuterCode(inventoryDelivery.getOuterCode());
inventoryInfo.setUpdateBy(currentUserId);
inventoryInfo.setUpdateTime(nowDate);
}
omsInventoryInnerService.importByOuter(productSnDataList,inventoryDelivery.getProductCode());
}
return inventoryDeliveryMapper.insertInventoryDelivery(inventoryDelivery);
}

View File

@ -20,6 +20,7 @@ import com.ruoyi.sip.vo.DeliveryInfoVo;
import liquibase.pro.packaged.O;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.List;
@ -34,6 +35,7 @@ import java.util.stream.Collectors;
* @date 2025-08-07
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class InventoryInfoServiceImpl implements IInventoryInfoService {
@Autowired
private InventoryInfoMapper inventoryInfoMapper;
@ -186,6 +188,12 @@ public class InventoryInfoServiceImpl implements IInventoryInfoService {
@Override
public void deleteInventoryInfoByInnerIds(String[] idArray) {
List<InventoryInfo> inventoryInfos = inventoryInfoMapper.listInventoryInfoByInnerIds(idArray);
Map<String, List<InventoryInfo>> listMap = inventoryInfos.stream().collect(Collectors.groupingBy(InventoryInfo::getProductCode));
for (Map.Entry<String, List<InventoryInfo>> entry : listMap.entrySet()) {
//此处删除 应该只有一个productCode
productInfoService.updateAvailableCount((long) -entry.getValue().size(),entry.getKey());
}
inventoryInfoMapper.deleteInventoryInfoByInnerIds(idArray);
}

View File

@ -175,7 +175,19 @@ public class OmsInventoryInnerServiceImpl implements IOmsInventoryInnerService {
}
@Override
public void importByOuter(List<InventoryInfoExcelDto> inventoryInfoExcelDtoList, String productCode) {
public void importByOuter(List<InventoryInfo> inventoryInfoList,String productCode) {
List<ProductInfo> productInfos = productInfoService.selectProductInfoByCodeList(Collections.singletonList(productCode));
OmsInventoryInner omsInventoryInner = new OmsInventoryInner();
omsInventoryInner.setVendorCode(productInfos.get(0).getVendorCode());
omsInventoryInner.setProductCode(productCode);
omsInventoryInner.setWarehouseId(inventoryInfoList.get(0).getWarehouseId());
omsInventoryInner.setInventoryInfoList(inventoryInfoList);
this.insertOmsInventoryInner(omsInventoryInner);
}
@Override
public List<InventoryInfo> getInventoryInfoList(List<InventoryInfoExcelDto> inventoryInfoExcelDtoList, String productCode) {
long count = inventoryInfoExcelDtoList.stream().filter(item -> !item.getProductCode().equals(productCode)).count();
if (count > 0){
throw new ServiceException("导入清单的产品与出库单不符");
@ -184,6 +196,10 @@ public class OmsInventoryInnerServiceImpl implements IOmsInventoryInnerService {
if (warehouseNameList.size() > 1){
throw new ServiceException("导入清单只能有一个仓库");
}
List<ProductInfo> productInfos = productInfoService.selectProductInfoByCodeList(Collections.singletonList(productCode));
if (CollUtil.isEmpty(productInfos)){
throw new ServiceException("产品编码对应产品未找到");
}
List<OmsWarehouseInfo> warehouseInfoList = warehouseInfoService.listByNameList(warehouseNameList);
Map<String, OmsWarehouseInfo> warehouseInfoMap = warehouseInfoList.stream().collect(Collectors.toMap(OmsWarehouseInfo::getWarehouseName, Function.identity(), (v1, v2) -> v1));
List<InventoryInfo> inventoryInfoList = inventoryInfoExcelDtoList.stream().map(item -> {
@ -191,23 +207,23 @@ public class OmsInventoryInnerServiceImpl implements IOmsInventoryInnerService {
info.setInventoryStatus(InventoryInfo.InventoryStatusEnum.INNER.getCode());
info.setProductSn(item.getProductSn());
info.setProductCode(productCode);
info.setModel(productInfos.get(0).getModel());
info.setProductDesc(productInfos.get(0).getDescription());
info.setInnerPrice(item.getInnerPrice());
OmsWarehouseInfo omsWarehouseInfo = warehouseInfoMap.get(item.getWarehouseName());
if (omsWarehouseInfo == null){
throw new ServiceException("仓库未找到,导入失败");
}
info.setWarehouseId(omsWarehouseInfo.getId());
info.setWarehouseName(omsWarehouseInfo.getWarehouseName());
return info;
}).collect(Collectors.toList());
List<ProductInfo> productInfos = productInfoService.selectProductInfoByCodeList(Collections.singletonList(productCode));
OmsInventoryInner omsInventoryInner = new OmsInventoryInner();
omsInventoryInner.setVendorCode(productInfos.get(0).getVendorCode());
omsInventoryInner.setProductCode(productCode);
omsInventoryInner.setWarehouseId(warehouseInfoList.get(0).getId());
omsInventoryInner.setInventoryInfoList(inventoryInfoList);
this.insertOmsInventoryInner(omsInventoryInner);
List<String> repeatSnList = inventoryInfoService.checkUnq(inventoryInfoList.stream().map(InventoryInfo::getProductSn).collect(Collectors.toList()));
if (CollUtil.isNotEmpty(repeatSnList)) {
throw new ServiceException(StrUtil.format("SN码[{}]已存在,导入失败", repeatSnList));
}
return inventoryInfoList;
}

View File

@ -1033,14 +1033,25 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To
// 审批通过处理
if ("产品经理".equals(taskName)) {
handleProductManagerApproval(businessKey);
} else if ("公司领导".equals(taskName)) {
handleCompanyLeaderApproval(businessKey);
}
}
return TodoCommonTemplate.super.todoApproveCallback(todo);
}
@Override
public boolean multiInstanceApproveCallback(String activityName,ProcessInstance processInstance) {
String flowBusinessKey = processInstance.getBusinessKey();
String[] split = flowBusinessKey.split("#");
String businessKey = split.length > 1 ? split[1] : split[0];
Map<String, Object> processVariables = processInstance.getProcessVariables();
Integer approveBtn = (Integer) processVariables.get("approveBtn");
if ("公司领导".equals(activityName) && approveBtn == 1) {
handleCompanyLeaderApproval(businessKey);
}
return TodoCommonTemplate.super.multiInstanceApproveCallback(activityName,processInstance);
}
/**
*

View File

@ -73,6 +73,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{item}
</foreach>
</select>
<select id="listInventoryInfoByInnerIds" resultType="com.ruoyi.sip.domain.InventoryInfo">
select product_code from oms_inventory_info where inner_code in (
select inner_code from oms_inventory_inner where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
)
</select>
<insert id="insertInventoryInfo" parameterType="InventoryInfo" useGeneratedKeys="true" keyProperty="id">

View File

@ -67,6 +67,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select count(1) from customer_info where customer_code = #{customerCode} and status=0
<if test="id != null">and id != #{id}</if>
</select>
<select id="selectMaxByPrefix" resultType="java.lang.Integer">
select ifnull(max(SUBSTR(customer_code FROM LENGTH(#{prefix}) + 1 FOR 4)), 0)
from customer_info
WHERE customer_code like concat(#{prefix}, '%');
</select>
<insert id="insertCustomerInfo" parameterType="CustomerInfo">
insert into customer_info