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) { formatter: function (value, row, index) {
var actions = []; var actions = [];
let disabled = Number(row.quantity) <= Number(row.generatedQuantity) + Number(row.confirmQuantity) 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>`); onclick="checkOut(\'${row.productCode}\',\'${row.model}\',\'${row.vendorName}\',\'${row.quantity}\',\'${row.generatedQuantity}\',\'${row.confirmQuantity}\',\'[[${projectOrderInfo.id}]]\')">出库</a>`);
return actions.join(''); return actions.join('');
} }
@ -555,7 +555,7 @@ function initWarehouseTable(data) {
}, },
{ {
field: 'availableCount', field: 'availableCount',
title: '实时库存' title: '实时库存'
}, },
{ {
field: 'confirmQuantity', field: 'confirmQuantity',
@ -767,7 +767,7 @@ function initWarehouseTable(data) {
} else { } 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-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(''); return actions.join('');
} }

View File

@ -110,6 +110,7 @@
</div> </div>
<form class="form-horizontal m" id="generateDeliveryForm"> <form class="form-horizontal m" id="generateDeliveryForm">
<div class="col-xs-12"> <div class="col-xs-12">
<input type="hidden" id="deliveryQuantity">
<table> <table>
<tr> <tr>
<td><label class="control-label is-required">物流单号:</label></td> <td><label class="control-label is-required">物流单号:</label></td>
@ -172,6 +173,75 @@
var productPrefix = ctx + "inventory/info"; var productPrefix = ctx + "inventory/info";
var deliveryPrefix = ctx + "inventory/delivery"; var deliveryPrefix = ctx + "inventory/delivery";
const showReturnFlag = [[${deliveryList}]] && [[${deliveryList.size()}]]>0; 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({ $("#form-outer-edit").validate({
focusCleanup: true focusCleanup: true
}); });
@ -197,6 +267,7 @@
let data = new FormData() let data = new FormData()
data.append('file', file) data.append('file', file)
data.append('productCode', $('[name="productCode"]').val()) data.append('productCode', $('[name="productCode"]').val())
data.append('quantity', Number($('#deliveryQuantity').val()))
var xhr = new XMLHttpRequest(); // 创建XMLHttpRequest对象 var xhr = new XMLHttpRequest(); // 创建XMLHttpRequest对象
xhr.open('POST', prefix + '/importData', true); // 设置请求类型和URL xhr.open('POST', prefix + '/importData', true); // 设置请求类型和URL
// 当请求完成时执行的回调函数 // 当请求完成时执行的回调函数
@ -204,7 +275,17 @@
let data = JSON.parse(res.currentTarget.response) let data = JSON.parse(res.currentTarget.response)
if (data.code === 0) { if (data.code === 0) {
$.modal.msgSuccess('上传成功'); $.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 { } else {
top.layer.alert(data.msg || '导入失败', { top.layer.alert(data.msg || '导入失败', {
icon: 2, icon: 2,
@ -272,61 +353,10 @@
} }
} }
function initProductSnTable() {
var options = {
id: 'bootstrap-table',
url: productPrefix + "/list",
modalName: "出库单",
onCheck: (row, $ele) => { function initProductSnTable() {
updateTotal()
}, $.table.init(productSnOptions);
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);
$('#bootstrap-table').before('<div ><span>已选:</span><span id="table-select-count">0</span><span>(台)</span></div>'); $('#bootstrap-table').before('<div ><span>已选:</span><span id="table-select-count">0</span><span>(台)</span></div>');
} }
@ -335,7 +365,7 @@
if ($tableCount.length > 0) { if ($tableCount.length > 0) {
// 延迟100毫秒等待表格渲染完成 // 延迟100毫秒等待表格渲染完成
setTimeout(function () { setTimeout(function () {
$tableCount.text($.table.selectColumns("productSn").length); $tableCount.text(productSnData.length > 0 ? productSnData.length : $.table.selectColumns("productSn").length);
}, 100) }, 100)
} }
} }
@ -398,7 +428,7 @@
formatter: function (value, row, index) { formatter: function (value, row, index) {
var actions = []; var actions = [];
let disabled = Number(row.quantity) <= Number(row.deliveryGenerateQuantity) + Number(row.deliveryConfirmQuantity) 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(''); return actions.join('');
} }
}] }]
@ -412,12 +442,18 @@
let width = 1000, height = 700 let width = 1000, height = 700
parent.$('.layui-layer-btn').css('display', 'none') parent.$('.layui-layer-btn').css('display', 'none')
parent.$('.layui-layer-setwin').css('display', 'none') parent.$('.layui-layer-setwin').css('display', 'none')
$('#deliveryQuantity').val(quantity)
$('[name="warehouseId"]').val(warehouseId) $('[name="warehouseId"]').val(warehouseId)
$('[name="productCode"]').val(productCode) $('[name="productCode"]').val(productCode)
$('[name="inventoryStatus"]').val(0) $('[name="inventoryStatus"]').val(0)
$('#query-product-sn [name="outerCode"]').val('') $('#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); $('#table-select-count').text(0);
let index = layer.open({ let index = layer.open({
id: 'generate_delivery', id: 'generate_delivery',
@ -432,15 +468,25 @@
$.modal.msgError('物流单号必填') $.modal.msgError('物流单号必填')
return; return;
} }
var arrays = $.table.selectColumns("productSn"); let arrays = []
if (productSnData.length <= 0) {
arrays = $.table.selectColumns("productSn");
if (arrays.length != quantity) { if (arrays.length != quantity) {
$.modal.msgError(`产品选中数量应与发货数量一致,应发货数量为[${quantity}]`) $.modal.msgError(`产品选中数量应与发货数量一致,应发货数量为[${quantity}]`)
return return
} }
} else {
if (productSnData.length != quantity) {
$.modal.msgError(`产品选中数量应与发货数量一致,应发货数量为[${quantity}]`)
return
}
}
//保存数据 //保存数据
let data = { let data = {
productSnList: arrays, productSnList: arrays,
logisticsCode: $('#logisticsCode').val(), logisticsCode: $('#logisticsCode').val(),
productCode: productCode,
quantity: quantity, quantity: quantity,
warehouseId: warehouseId, warehouseId: warehouseId,
logisticsCompany: $('#logisticsCompany').val(), logisticsCompany: $('#logisticsCompany').val(),
@ -448,6 +494,7 @@
deliveryTime: $('#deliveryTime').val(), deliveryTime: $('#deliveryTime').val(),
deliveryTimeType: $('#deliveryTimeType').val(), deliveryTimeType: $('#deliveryTimeType').val(),
outerCode: $('[name="outerCode"]').val(), outerCode: $('[name="outerCode"]').val(),
productSnDataList: productSnData,
} }
var config = { var config = {
url: deliveryPrefix + "/add", url: deliveryPrefix + "/add",
@ -460,18 +507,22 @@
$.modal.disable(); $.modal.disable();
}, },
success: function (result) { success: function (result) {
if (result.code != 0) {
$.modal.closeLoading();
$.modal.enable();
$.modal.msgError(result.msg)
return
}
if (typeof callback == "function") { if (typeof callback == "function") {
callback(result); callback(result);
} }
refreshTable() refreshTable()
$.modal.closeLoading(); $.modal.closeLoading();
$.modal.enable(); $.modal.enable();
layer.close(index);
} }
}; };
$.ajax(config) $.ajax(config)
layer.close(index);
}, },
end: function () { end: function () {
parent.$('.layui-layer-btn').css('display', '') 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> '); 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 { } 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="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(''); return actions.join('');
} }
@ -140,11 +140,11 @@
function received(id) { function received(id) {
$.modal.confirm("确认要确认接收吗?", function () { // $.modal.confirm("确认要确认接收吗?", function () {
$.operate.post(prefix + "/status", {"id": id, "outerStatus": '3'},()=>{ $.operate.post(prefix + "/status", {"id": id, "outerStatus": '3'},()=>{
// $.table.refresh() // $.table.refresh()
}); });
}) // })
} }
function refundable(id,orderCode) { function refundable(id,orderCode) {

View File

@ -9,9 +9,9 @@
<form class="form-horizontal m" id="form-info-add"> <form class="form-horizontal m" id="form-info-add">
<div class="col-xs-6"> <div class="col-xs-6">
<div class="form-group"> <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"> <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> </div>
</div> </div>

View File

@ -12,7 +12,7 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-5 control-label is-required">客户编码:</label> <label class="col-sm-5 control-label is-required">客户编码:</label>
<div class="col-sm-7"> <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> </div>
</div> </div>

View File

@ -171,7 +171,7 @@ public class InventoryOuterController extends BaseController
@PostMapping("/importData") @PostMapping("/importData")
@ResponseBody @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); ExcelUtil<InventoryInfoExcelDto> util = new ExcelUtil<InventoryInfoExcelDto>(InventoryInfoExcelDto.class);
try (InputStream inputStream = file.getInputStream()) { try (InputStream inputStream = file.getInputStream()) {
@ -179,7 +179,10 @@ public class InventoryOuterController extends BaseController
if (CollUtil.isEmpty(inventoryInfoExcelDtoList)){ if (CollUtil.isEmpty(inventoryInfoExcelDtoList)){
return AjaxResult.error("导入数据为空"); 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) { } catch (IOException e) {
throw new ServiceException("读取excel错误,请联系管理员"); throw new ServiceException("读取excel错误,请联系管理员");
@ -187,8 +190,6 @@ public class InventoryOuterController extends BaseController
return AjaxResult.error(e.getMessage()); return AjaxResult.error(e.getMessage());
} }
return AjaxResult.success();
} }

View File

@ -73,6 +73,7 @@ public class InventoryDelivery extends BaseEntity
private String deliveryStatus; private String deliveryStatus;
private List<String> productSnList; 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 com.ruoyi.system.service.ISysUserService;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.apache.commons.lang3.ObjectUtils; 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.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.RuntimeService;
import org.flowable.engine.TaskService; import org.flowable.engine.TaskService;
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener; 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.FlowableMultiInstanceActivityEvent;
import org.flowable.engine.delegate.event.FlowableProcessStartedEvent; import org.flowable.engine.delegate.event.FlowableProcessStartedEvent;
import org.flowable.engine.delegate.event.impl.FlowableEntityWithVariablesEventImpl; 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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -88,6 +94,53 @@ public class ProcessListener extends AbstractFlowableEngineEventListener {
super.multiInstanceActivityStarted(event); 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 @Override
protected void taskCreated(FlowableEngineEntityEvent event) { protected void taskCreated(FlowableEngineEntityEvent event) {
@ -127,11 +180,10 @@ public class ProcessListener extends AbstractFlowableEngineEventListener {
if(!"noTodo".equals(taskEntity.getCategory())) { if(!"noTodo".equals(taskEntity.getCategory())) {
List<Todo> todos = todoService.selectTodoListByProcessInstanceId(new Todo().setProcessInstanceId(taskEntity.getProcessInstanceId())); List<Todo> todos = todoService.selectTodoListByProcessInstanceId(new Todo().setProcessInstanceId(taskEntity.getProcessInstanceId()));
if (ObjectUtils.isNotEmpty(todos)) { if (ObjectUtils.isNotEmpty(todos)) {
String ids = todos.stream().map(Todo::getTodoId).map(String::valueOf).collect(Collectors.joining(","));
Integer btn = null; Integer btn = null;
todoService.deleteTodoByIds(ids);
log.error("待办任务删除成功 {}", ids);
Todo todo = todos.stream().filter(d -> d.getTaskId().equals(taskEntity.getId())).findFirst().get(); 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) { if (event instanceof FlowableEntityWithVariablesEventImpl) {
Map variables = ((FlowableEntityWithVariablesEventImpl) event).getVariables(); Map variables = ((FlowableEntityWithVariablesEventImpl) event).getVariables();
log.error("variables {}", ObjectUtils.isNotEmpty(variables) ? JSON.toJSONString(variables) : "无数据"); 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 com.ruoyi.sip.flowable.domain.Todo;
import org.flowable.engine.runtime.ProcessInstance;
/** /**
* *
@ -39,6 +40,10 @@ public interface TodoCommonTemplate {
//默认实现 //默认实现
return true; 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 deleteCustomerInfoByIds(String[] ids);
public int selectCountByCode(CustomerInfo customerInfo); public int selectCountByCode(CustomerInfo customerInfo);
int selectMaxByPrefix(String province);
} }

View File

@ -70,4 +70,5 @@ public interface InventoryInfoMapper
List<InventoryInfo> countBySn(List<String> productSnList); List<InventoryInfo> countBySn(List<String> productSnList);
void deleteInventoryInfoByInnerIds(String[] idArray); 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 java.util.List;
import com.ruoyi.sip.domain.InventoryInfo;
import com.ruoyi.sip.domain.OmsInventoryInner; import com.ruoyi.sip.domain.OmsInventoryInner;
import com.ruoyi.sip.dto.inventory.InventoryInfoExcelDto; import com.ruoyi.sip.dto.inventory.InventoryInfoExcelDto;
@ -62,5 +63,6 @@ public interface IOmsInventoryInnerService
public int deleteOmsInventoryInnerById(Long id); 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 java.util.List;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ShiroUtils; 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.domain.CustomerInfo;
import com.ruoyi.sip.mapper.CustomerInfoMapper; import com.ruoyi.sip.mapper.CustomerInfoMapper;
import com.ruoyi.sip.service.ICnareaService;
import com.ruoyi.sip.service.ICustomerInfoService; import com.ruoyi.sip.service.ICustomerInfoService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -23,7 +27,8 @@ public class CustomerInfoServiceImpl implements ICustomerInfoService
{ {
@Autowired @Autowired
private CustomerInfoMapper customerInfoMapper; private CustomerInfoMapper customerInfoMapper;
@Autowired
private ICnareaService cnareaService;
/** /**
* *
* *
@ -58,6 +63,7 @@ public class CustomerInfoServiceImpl implements ICustomerInfoService
public int insertCustomerInfo(CustomerInfo customerInfo) public int insertCustomerInfo(CustomerInfo customerInfo)
{ {
customerInfo.setCreateBy(ShiroUtils.getUserId().toString()); customerInfo.setCreateBy(ShiroUtils.getUserId().toString());
customerInfo.setCustomerCode(generateCode(customerInfo.getProvince()));
int i = customerInfoMapper.selectCountByCode(customerInfo); int i = customerInfoMapper.selectCountByCode(customerInfo);
if (i > 0){ if (i > 0){
throw new ServiceException("客户编码已存在"); throw new ServiceException("客户编码已存在");
@ -65,6 +71,28 @@ public class CustomerInfoServiceImpl implements ICustomerInfoService
return customerInfoMapper.insertCustomerInfo(customerInfo); 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) public int updateCustomerInfo(CustomerInfo customerInfo)
{ {
customerInfo.setUpdateBy(ShiroUtils.getUserId().toString()); customerInfo.setUpdateBy(ShiroUtils.getUserId().toString());
int i = customerInfoMapper.selectCountByCode(customerInfo);
if (i > 0){ // 检查客户编码是否已存在(排除当前记录)
// 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("客户编码已存在"); throw new ServiceException("客户编码已存在");
} }
}
return customerInfoMapper.updateCustomerInfo(customerInfo); return customerInfoMapper.updateCustomerInfo(customerInfo);
} }

View File

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

View File

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

View File

@ -20,6 +20,7 @@ import com.ruoyi.sip.vo.DeliveryInfoVo;
import liquibase.pro.packaged.O; import liquibase.pro.packaged.O;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -34,6 +35,7 @@ import java.util.stream.Collectors;
* @date 2025-08-07 * @date 2025-08-07
*/ */
@Service @Service
@Transactional(rollbackFor = Exception.class)
public class InventoryInfoServiceImpl implements IInventoryInfoService { public class InventoryInfoServiceImpl implements IInventoryInfoService {
@Autowired @Autowired
private InventoryInfoMapper inventoryInfoMapper; private InventoryInfoMapper inventoryInfoMapper;
@ -186,6 +188,12 @@ public class InventoryInfoServiceImpl implements IInventoryInfoService {
@Override @Override
public void deleteInventoryInfoByInnerIds(String[] idArray) { 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); inventoryInfoMapper.deleteInventoryInfoByInnerIds(idArray);
} }

View File

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

View File

@ -1033,14 +1033,25 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To
// 审批通过处理 // 审批通过处理
if ("产品经理".equals(taskName)) { if ("产品经理".equals(taskName)) {
handleProductManagerApproval(businessKey); handleProductManagerApproval(businessKey);
} else if ("公司领导".equals(taskName)) {
handleCompanyLeaderApproval(businessKey);
} }
} }
return TodoCommonTemplate.super.todoApproveCallback(todo); 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} #{item}
</foreach> </foreach>
</select> </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"> <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 select count(1) from customer_info where customer_code = #{customerCode} and status=0
<if test="id != null">and id != #{id}</if> <if test="id != null">and id != #{id}</if>
</select> </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 id="insertCustomerInfo" parameterType="CustomerInfo">
insert into customer_info insert into customer_info