基于spring boot的ERP进销存管理系统 单据流转 物流信息管理系统源码 物流信息系统...
本系统功能包括单据之间的流转、销售单单入库单出,库单采购申请单采购单等六大单据、库存管理、商品管理、商品分类、客户管理、供应商管理、商品客户供应商优先级排序、系统给多个用户管理员设置权限管理等。本系统功能包括单据之间的流转、销售单单入库单出,库单采购申请单采购单等六大单据、库存管理、商品管理、商品分类、客户管理、供应商管理、商品客户供应商优先级排序、系统给多个用户管理员设置权限管理等。Rediss
基于spring boot的ERP进销存管理系统 单据流转 物流信息管理系统源码 物流信息系统 超市进销存管理系 药品管理系统 系统设计与开发 SSM框架、Java开发、vue开发、B/S架构、Java项目 亮点:单据之间有关联,可以实现单据的流转 前后端分离 本系统功能包括单据之间的流转、销售单单入库单出,库单采购申请单采购单等六大单据、库存管理、商品管理、商品分类、客户管理、供应商管理、商品客户供应商优先级排序、系统给多个用户管理员设置权限管理等 前端方面也进行了很多细节设计,具体包括透明背景、信息提示框、按钮的提示语、关联单据只可选择一次(选择过的会变灰,不可选择的会隐藏)等 会本人70页、2.3w字的程度报告作为使用参考

最近在搞一个ERP系统开发,发现单据流转这个功能坑是真的多。就拿采购单变入库单来说,要是没处理好关联关系,库存数据分分钟错得亲妈都不认识。今天就拿我们团队用Spring Boot撸的进销存系统举个栗子,看看怎么让单据手拉手跳转不翻车。

先看后端怎么玩关联单据。核心逻辑是给每个单据实体加个"前任"字段,像这样:
@Entity
@Table(name = "procurement_order")
public class ProcurementOrder {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne
@JoinColumn(name = "related_purchase_apply_id")
private PurchaseApply relatedApply; // 关联的采购申请单
// 其他字段省略...
}
@Service
public class OrderService {
@Transactional
public void convertToStockIn(ProcurementOrder order) {
StockIn stockIn = new StockIn();
stockIn.setSourceOrderId(order.getId());
stockIn.setSourceOrderType(OrderType.PROCUREMENT);
// 复制商品明细等操作...
stockInRepository.save(stockIn);
order.setStatus(OrderStatus.CONVERTED);
procurementOrderRepository.save(order);
}
}
这里用JPA的@OneToOne直接绑定采购申请单,转换时把原单ID和类型都塞到新单据里。注意事务注解要加,不然转换到一半崩了可就热闹了。

前端防手贱设计才是真考验。Vue组件里控制关联单据选择,选过的直接变灰:
<template>
<el-select
v-model="selectedOrder"
:disabled="isDisabled"
@change="handleOrderSelect">
<el-option
v-for="order in availableOrders"
:key="order.id"
:label="order.code"
:value="order.id"
:disabled="order.used">
</el-option>
</el-select>
</template>
<script>
export default {
computed: {
availableOrders() {
return this.orders.map(order => ({
...order,
used: this.selectedOrders.includes(order.id)
}))
}
}
}
</script>
这里用computed属性动态计算可选单据,已经关联的直接打上禁用标记。注意要深拷贝原始数据,不然会污染原始订单数据。

基于spring boot的ERP进销存管理系统 单据流转 物流信息管理系统源码 物流信息系统 超市进销存管理系 药品管理系统 系统设计与开发 SSM框架、Java开发、vue开发、B/S架构、Java项目 亮点:单据之间有关联,可以实现单据的流转 前后端分离 本系统功能包括单据之间的流转、销售单单入库单出,库单采购申请单采购单等六大单据、库存管理、商品管理、商品分类、客户管理、供应商管理、商品客户供应商优先级排序、系统给多个用户管理员设置权限管理等 前端方面也进行了很多细节设计,具体包括透明背景、信息提示框、按钮的提示语、关联单据只可选择一次(选择过的会变灰,不可选择的会隐藏)等 会本人70页、2.3w字的程度报告作为使用参考

权限控制这块有个骚操作,用自定义注解+拦截器实现:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataAuth {
String value() default "dept";
}
@Component
public class DataAuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
Method method = ((HandlerMethod) handler).getMethod();
DataAuth annotation = method.getAnnotation(DataAuth.class);
User currentUser = getCurrentUser();
if ("dept".equals(annotation.value()) && !currentUser.getDept().equals(dataOwnerDept)) {
throw new AccessDeniedException("跨部门操作禁止");
}
return true;
}
}
在Controller方法上加个@DataAuth("dept"),拦截器自动校验数据归属部门。比写一堆if else清爽多了,权限规则调整也方便。

库存计算这块有个坑要注意,用Redis分布式锁防止超卖:
public void updateStock(Long productId, Integer quantity) {
String lockKey = "stock_lock:" + productId;
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.tryLock(3, 5, TimeUnit.SECONDS)) {
ProductStock stock = stockRepository.findByProductId(productId);
stock.setQuantity(stock.getQuantity() + quantity);
stockRepository.save(stock);
}
} finally {
lock.unlock();
}
}
Redisson的分布式锁比手撸setnx靠谱,注意锁的粒度控制在单品级别,别傻乎乎给整个库存表加锁。

系统里还藏了不少魔鬼细节。比如采购单转库存单时自动带出供应商信息,销售单生成时自动关联客户信用额度校验。这些业务钩子用Spring的EventListener实现解耦:
@EventListener
public void handleOrderCreate(OrderCreateEvent event) {
if (event.getOrderType() == OrderType.SALES) {
Customer customer = customerService.getById(event.getCustomerId());
if (customer.getCredit() < event.getTotalAmount()) {
throw new BusinessException("客户信用额度不足");
}
}
}
事件驱动设计让核心流程不被各种校验逻辑搞成意大利面条代码。

这个项目的坑基本都踩过了,配套的2.3万字文档里记录了更多血泪史。比如单据编号生成规则怎么防并发,百万级数据量下怎么优化关联查询,都是实战中摔出来的经验。代码虽然不敢说多优雅,但至少业务跑起来没出过大乱子,中小企业的进销存需求基本都能扛得住。

更多推荐
所有评论(0)