完成了 BOM 管理和生产管理,完成部分发料单、采购计划和调拨单。

This commit is contained in:
c
2026-02-28 18:14:57 +08:00
parent 6d609f8156
commit bdea5287cb
88 changed files with 1693 additions and 518 deletions

View File

@@ -0,0 +1,4 @@
package com.niuan.erp.common.base;
public record BaseSelectDto(Object value, String label) {
}

View File

@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusPropertiesCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.niuan.erp.common.handler.CustomerTenantHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -14,6 +16,9 @@ public class MybatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
var tenantLineInnerInterceptor = new TenantLineInnerInterceptor();
tenantLineInnerInterceptor.setTenantLineHandler(new CustomerTenantHandler());
interceptor.addInnerInterceptor(tenantLineInnerInterceptor);
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}

View File

@@ -0,0 +1,42 @@
package com.niuan.erp.common.handler;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.niuan.erp.common.utils.SecurityUtils;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import java.util.HashSet;
import java.util.Set;
/**
* 数据区分的 Handler
*/
public class CustomerTenantHandler implements TenantLineHandler {
private final static Set<String> activeTables = new HashSet<String>();
/*
这里添加需要进行账户验证的数据表
*/
static {
activeTables.add("product");
activeTables.add("storage_list");
activeTables.add("bom_list");
}
@Override
public Expression getTenantId() {
Integer customerId = SecurityUtils.getLoginUser().getUser().getCustomerId();
return new LongValue(customerId);
}
@Override
public String getTenantIdColumn() {
return "CustomerId";
}
@Override
public boolean ignoreTable(String tableName) {
return !activeTables.contains(tableName);
}
}

View File

@@ -21,6 +21,10 @@ public class SecurityUtils {
throw new SystemException("auth.userDetailsError");
}
public static Integer getCustomerId() {
return getLoginUser().getUser().getCustomerId();
}
public static Long getUserId(){
return getLoginUser().getUser().getId();
}

View File

@@ -4,6 +4,9 @@ import com.niuan.erp.module.auth.controller.dto.ButtonProp;
import com.niuan.erp.module.auth.controller.dto.RouterConfigRaw;
import com.niuan.erp.module.auth.controller.dto.RouterConfigRawMeta;
import com.niuan.erp.module.sys.entity.SysChannel;
import com.niuan.erp.module.sys.entity.SysPermission;
import com.niuan.erp.module.sys.enums.PermissionType;
import org.springframework.util.StringUtils;
import java.util.*;
@@ -19,12 +22,63 @@ public class SystemAuthFactory {
private static final Integer BUTTON_TYPE = 1;
public static List<RouterConfigRaw> generateTeekFrameMenuBySysPermissions(List<SysPermission> sysPermissions) {
List<RouterConfigRaw> configList = new ArrayList<>();
HashMap<Long, RouterConfigRaw> configMap = new HashMap<>();
sysPermissions.stream().filter(p -> p.getPermissionType().equals(PermissionType.MENU)).forEach(p -> {
var config = convertToRouterConfigRaw(p);
if (Objects.equals(p.getParentId(), ROOT_ID)) {
// 如果是顶级节点则加入最后结果
configList.add(config);
// 将自身添加进 Map 中
saveInConfigMap(config, p.getId(), configMap);
} else {
// 如果不是是顶级节点则说明有上级节点
// 先添加到父组件
if (configMap.containsKey(p.getParentId())) {
// 如果 Map 里有保存这个内容,说明已经被作为父组件
var parentConfig = configMap.get(p.getParentId());
if (parentConfig.getChildren() != null) parentConfig.getChildren().add(config);
else parentConfig.setChildren(new ArrayList<>(List.of(config)));
} else {
// 如果 Map 没有父节点则缓存一个父节点
var parentConfig = new RouterConfigRaw(null, null);
parentConfig.setChildren(new ArrayList<>(List.of(config)));
configMap.put(p.getParentId(), parentConfig);
}
// 接着将自身添加进 Map 中
saveInConfigMap(config, p.getId(), configMap);
}
});
sysPermissions.stream().filter(p -> p.getPermissionType().equals(PermissionType.TOP_PAGE_BUTTON) ||
p.getPermissionType().equals(PermissionType.TABLE_OPERATOR_BUTTON) ||
p.getPermissionType().equals(PermissionType.TABLE_STATUS_BUTTON) ||
p.getPermissionType().equals(PermissionType.DIALOG_BUTTON))
.forEach(p -> {
var buttonProp = convertToButtonProp(p);
var menuConfig = configMap.get(p.getParentId());
if (menuConfig != null) {
switch (p.getPermissionType()) {
case TOP_PAGE_BUTTON -> saveInButtonAuthList(menuConfig.getMeta().getButtonAuth(), buttonProp);
case TABLE_OPERATOR_BUTTON -> saveInButtonAuthList(menuConfig.getMeta().getToolButtonAuth(), buttonProp);
case DIALOG_BUTTON -> saveInButtonAuthList(menuConfig.getMeta().getDialogButtonAuth(), buttonProp);
}
}
});
return configList;
}
/**
* 生成 Teek 框架的前端动态菜单数据
* @param sysChannels
* @return
*/
public static List<RouterConfigRaw> generateTeekFrameMenu(List<SysChannel> sysChannels) {
public static List<RouterConfigRaw> generateTeekFrameMenuBySysChannels(List<SysChannel> sysChannels) {
List<RouterConfigRaw> configList = new ArrayList<>();
HashMap<Long, RouterConfigRaw> configMap = new HashMap<>();
@@ -133,6 +187,23 @@ public class SystemAuthFactory {
configMap.put(id, config);
}
/**
* 转化成权限按钮属性,里面包含按钮的各项属性
* @param sysPermission
* @return
*/
private static ButtonProp convertToButtonProp(SysPermission sysPermission) {
ButtonProp buttonProp = new ButtonProp();
buttonProp.setButtonName(sysPermission.getPermissionName());
buttonProp.setText(sysPermission.getPermissionName());
buttonProp.setEventName(sysPermission.getEventName());
buttonProp.setColorType(TeekFrameMappingUtils.getTeekButtonType(sysPermission.getClassName()));
buttonProp.setIcon(sysPermission.getIconName());
buttonProp.setRank(sysPermission.getSort());
return buttonProp;
}
/**
* 转化成权限按钮属性,里面包含按钮的各项属性
* @param sysChannel
@@ -172,5 +243,37 @@ public class SystemAuthFactory {
return config;
}
/**
* 转化成 初始化的 RouterConfigRaw需要进一步完善才能匹配前端框架
* @param sysPermission
* @return
*/
private static RouterConfigRaw convertToRouterConfigRaw(SysPermission sysPermission) {
// 使用 channelLink 和 eventName 来作为菜单路径和名字
RouterConfigRaw config = new RouterConfigRaw(sysPermission.getPageLink(), sysPermission.getPageLink());
if (StringUtils.hasText(sysPermission.getViewLink())) {
config.setComponent(sysPermission.getViewLink());
}
RouterConfigRawMeta meta = new RouterConfigRawMeta();
// 设置 i18n 的位置
if (StringUtils.hasText(sysPermission.getPermissionI18n())) {
meta.setTitle("{{ _route.%s }}".formatted(sysPermission.getPermissionI18n()));
} else {
meta.setTitle(sysPermission.getPermissionName());
}
// 设置排序
meta.setRank(sysPermission.getSort());
// 设置图标
meta.setIcon(sysPermission.getIconName());
// 设置是否隐藏图标
meta.setHideInMenu(sysPermission.getHidden());
config.setMeta(meta);
return config;
}
}

View File

@@ -2,11 +2,14 @@ package com.niuan.erp.module.auth.controller;
import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.module.auth.service.SystemAuthService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "系统权限")
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
@@ -14,7 +17,12 @@ public class SystemAuthController {
private final SystemAuthService systemAuthService;
/**
* 后台权限接口
* @return
*/
@GetMapping("/getRouterConfigRawList")
@Operation(summary = "查询后台权限", operationId = "getRouterConfigRawList")
public BaseResult<?> getRouterConfigRawList() {
return BaseResult.successWithData(systemAuthService.getRouterConfigRawList());
}

View File

@@ -136,4 +136,9 @@ public class RouterConfigRawMeta {
* 操作栏 Button 权限
*/
private List<ButtonProp> toolButtonAuth = new ArrayList<>();
/**
* Dialog Button 权限
*/
private List<ButtonProp> dialogButtonAuth = new ArrayList<>();
}

View File

@@ -6,12 +6,15 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
import com.niuan.erp.common.base.LoginUser;
import com.niuan.erp.common.exception.BusinessException;
import com.niuan.erp.module.sys.entity.SysChannel;
import com.niuan.erp.module.sys.entity.SysPermission;
import com.niuan.erp.module.sys.entity.SysRole;
import com.niuan.erp.module.sys.entity.SysUser;
import com.niuan.erp.module.sys.mapper.SysChannelMapper;
import com.niuan.erp.module.sys.mapper.SysPermissionMapper;
import com.niuan.erp.module.sys.mapper.SysRoleMapper;
import com.niuan.erp.module.sys.mapper.SysUserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -22,6 +25,7 @@ import org.springframework.util.StringUtils;
import java.time.Duration;
import java.util.List;
import java.util.stream.Collectors;
@Service
@Transactional
@@ -30,10 +34,10 @@ public class CustomUserDetailsService implements UserDetailsService {
private final SysUserMapper sysUserMapper;
private final SysChannelMapper sysChannelMapper;
private final SysRoleMapper sysRoleMapper;
private final SysPermissionMapper sysPermissionMapper;
private final LoadingCache<String, UserDetails> userCache = Caffeine.newBuilder()
.maximumSize(100)
.expireAfterWrite(Duration.ofMinutes(10))
@@ -52,15 +56,15 @@ public class CustomUserDetailsService implements UserDetailsService {
throw new BusinessException("");
}
List<SysRole> roleList = sysRoleMapper.selectByUserId(user.getId());
List<SysChannel> channelList = sysChannelMapper.selectByUserId(user.getId());
List<String> authorityList = channelList.stream()
.map(SysChannel::getChannelLink)
.filter(StringUtils::hasText)
.toList();
var permissionList = sysPermissionMapper.selectByUserId(user.getId());
List<GrantedAuthority> authorities = permissionList.stream()
.filter(p -> StringUtils.hasText(p.getPermissionCode()))
.map(p -> new SimpleGrantedAuthority(p.getPermissionCode()))
.collect(Collectors.toUnmodifiableList());
return LoginUser.builder()
.user(user)
.roleList(roleList)
.authorities(List.of(new SimpleGrantedAuthority("vendor:index")))
.authorities(authorities)
.build();
}

View File

@@ -6,7 +6,9 @@ import com.niuan.erp.common.utils.SystemAuthFactory;
import com.niuan.erp.module.auth.controller.dto.RouterConfigRaw;
import com.niuan.erp.module.auth.service.SystemAuthService;
import com.niuan.erp.module.sys.entity.SysChannel;
import com.niuan.erp.module.sys.entity.SysPermission;
import com.niuan.erp.module.sys.mapper.SysChannelMapper;
import com.niuan.erp.module.sys.mapper.SysPermissionMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -18,10 +20,11 @@ public class SystemAuthServiceImpl implements SystemAuthService {
private final SysChannelMapper sysChannelMapper;
private final SysPermissionMapper sysPermissionMapper;
@Override
public List<RouterConfigRaw> getRouterConfigRawList() {
LoginUser loginUser = SecurityUtils.getLoginUser();
List<SysChannel> sysChannels = sysChannelMapper.selectByUserId(loginUser.getUser().getId());
return SystemAuthFactory.generateTeekFrameMenu(sysChannels);
List<SysPermission> sysPermissions = sysPermissionMapper.selectByUserId(SecurityUtils.getUserId());
return SystemAuthFactory.generateTeekFrameMenuBySysPermissions(sysPermissions);
}
}

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.niuan.erp.module.common.enums.DocumentType;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@@ -58,7 +59,7 @@ public class Document implements Serializable {
private String storeName;
@TableField("FormType")
private Integer formType;
private DocumentType formType;
@TableField("FormCode")
private String formCode;

View File

@@ -1,5 +1,6 @@
package com.niuan.erp.module.common.enums;
import com.baomidou.mybatisplus.annotation.IEnum;
import lombok.Getter;
/**
@@ -9,7 +10,7 @@ import lombok.Getter;
* 5.生产发料单 6.生产退料单 7.成品出货单 8.仓库调拨单 9.库存盘点单
*/
@Getter
public enum DocumentType {
public enum DocumentType implements IEnum<Integer> {
PURCHASE_ORDER(1, "采购订单"),
SALES_ORDER(2, "销售订单"),
WAREHOUSE_RECEIPT(3, "仓库入库单"),
@@ -27,4 +28,8 @@ public enum DocumentType {
}
@Override
public Integer getValue() {
return code;
}
}

View File

@@ -4,23 +4,23 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.annotation.ApiLog;
import com.niuan.erp.common.annotation.ModuleLog;
import com.niuan.erp.common.base.BaseDeleteBody;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.*;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import com.niuan.erp.common.base.OperationType;
import com.niuan.erp.module.production.controller.dto.BomDto;
import com.niuan.erp.module.production.controller.dto.*;
import com.niuan.erp.module.production.entity.Bom;
import com.niuan.erp.module.production.service.BomService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Tag(name = "Bom")
import java.util.List;
@Tag(name = "Bom管理")
@ModuleLog("Bom管理")
@RestController
@RequestMapping("/production/bom")
@@ -32,54 +32,71 @@ public class BomController {
@Operation(summary = "分页查询Bom数据", operationId = "getBomPage")
@GetMapping("/getBomPage")
@PreAuthorize("hasAuthority('bom:index')")
public BaseResult<IPage<BomDto>> getBomPage(@Validated BasePageReqParams pageParams,
@Validated(Get.class) BomDto searchParams) {
public BaseResult<IPage<BomDto>> getBomPage(@Validated BasePageReqParams pageParams, BomSearchParams searchParams) {
var wrapper = new LambdaQueryWrapper<Bom>();
if (searchParams != null) {
if (StringUtils.hasText(searchParams.customerName())) {
wrapper.like(Bom::getCustomerName, searchParams.customerName());
}
if (StringUtils.hasText(searchParams.searchCode())) {
wrapper.like(Bom::getBomNo, searchParams.searchCode());
}
if (searchParams != null) {
if (StringUtils.hasText(searchParams.partNumber())) {
return BaseResult.successWithData(bomService.getBomPageWithItem(pageParams, searchParams.searchCode(),
searchParams.partNumber()));
}
if (StringUtils.hasText(searchParams.searchCode())) {
wrapper.like(Bom::getBomNo, searchParams.searchCode()).or().like(Bom::getBomName, searchParams.searchCode());
}
}
wrapper.orderByDesc(Bom::getCreateDate);
return BaseResult.successWithData(bomService.getBomPage(pageParams, wrapper));
}
@Operation(summary = "查询Bom明细数据", operationId = "getBomItemList")
@GetMapping("/getBomItemList")
@PreAuthorize("hasAuthority('bom:showItem')")
public BaseResult<List<BomItemDto>> getBomItemList(@RequestParam("bomId")
@NotNull(message = "production.bom.validate.bom_id.not_null")
Long bomId) {
return BaseResult.successWithData(bomService.getBomItemList(bomId));
}
@Operation(summary = "查询 BOM 列表", operationId = "getBomSelectList")
@GetMapping("/getBomSelectList")
@PreAuthorize("hasAnyAuthority('production_plan:add')")
public BaseResult<List<BaseSelectDto>> getBomSelectList() {
return BaseResult.successWithData(bomService.getBomSelectList());
}
@ApiLog(type = OperationType.ADD, remark = "新增一条Bom记录")
@Operation(summary = "新增Bom", operationId = "addBom")
@PostMapping("/addBom")
@PreAuthorize("hasAuthority('bom:add')")
public BaseResult<?> addBom(@Validated(Add.class) @RequestBody BomDto dto) {
public BaseResult<?> addBom(@RequestBody BomAddDto dto) {
bomService.addBom(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.UPDATE, remark = "更新一条Bom记录")
@Operation(summary = "更新Bom", operationId = "updateBom")
@PostMapping("/updateBom")
@PreAuthorize("hasAuthority('bom:update')")
public BaseResult<?> updateBom(@Validated(Update.class) @RequestBody BomDto dto) {
bomService.updateBom(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.DELETE, remark = "删除一条Bom记录")
@Operation(summary = "删除Bom", operationId = "deleteBom")
@PostMapping("/deleteBom")
@PreAuthorize("hasAuthority('bom:delete')")
public BaseResult<?> deleteBom(@Validated(DeleteOne.class) @RequestBody BaseDeleteBody req) {
bomService.deleteBom(req.id());
return BaseResult.success();
}
@ApiLog(type = OperationType.DELETE, remark = "批量删除Bom记录")
@Operation(summary = "批量删除Bom", operationId = "deleteBomBatch")
@PostMapping("/deleteBomBatch")
@PreAuthorize("hasAuthority('bom:deleteBatch')")
public BaseResult<?> deleteBomBatch(@Validated(DeleteBatch.class) @RequestBody BaseDeleteBody req) {
bomService.deleteBatch(req.ids());
return BaseResult.success();
}
// @ApiLog(type = OperationType.UPDATE, remark = "更新一条Bom记录")
// @Operation(summary = "更新Bom", operationId = "updateBom")
// @PostMapping("/updateBom")
// @PreAuthorize("hasAuthority('bom:update')")
// public BaseResult<?> updateBom(@Validated(Update.class) @RequestBody BomDto dto) {
// bomService.updateBom(dto);
// return BaseResult.success();
// }
//
// @ApiLog(type = OperationType.DELETE, remark = "删除一条Bom记录")
// @Operation(summary = "删除Bom", operationId = "deleteBom")
// @PostMapping("/deleteBom")
// @PreAuthorize("hasAuthority('bom:delete')")
// public BaseResult<?> deleteBom(@Validated(DeleteOne.class) @RequestBody BaseDeleteBody req) {
// bomService.deleteBom(req.id());
// return BaseResult.success();
// }
//
// @ApiLog(type = OperationType.DELETE, remark = "批量删除Bom记录")
// @Operation(summary = "批量删除Bom", operationId = "deleteBomBatch")
// @PostMapping("/deleteBomBatch")
// @PreAuthorize("hasAuthority('bom:deleteBatch')")
// public BaseResult<?> deleteBomBatch(@Validated(DeleteBatch.class) @RequestBody BaseDeleteBody req) {
// bomService.deleteBatch(req.ids());
// return BaseResult.success();
// }
}

View File

@@ -10,6 +10,7 @@ import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import com.niuan.erp.common.base.OperationType;
import com.niuan.erp.module.common.entity.Document;
import com.niuan.erp.module.production.controller.dto.ProductionIssueAddDto;
import com.niuan.erp.module.production.controller.dto.ProductionIssueDto;
import com.niuan.erp.module.production.service.ProductionIssueService;
import io.swagger.v3.oas.annotations.Operation;
@@ -42,7 +43,7 @@ public class ProductionIssueController {
@Operation(summary = "新增ProductionIssue", operationId = "addProductionIssue")
@PostMapping("/addProductionIssue")
@PreAuthorize("hasAuthority('productionissue:add')")
public BaseResult<?> addProductionIssue(@Validated(Add.class) @RequestBody ProductionIssueDto dto) {
public BaseResult<?> addProductionIssue(@Validated(Add.class) @RequestBody ProductionIssueAddDto dto) {
productionIssueService.addProductionIssue(dto);
return BaseResult.success();
}

View File

@@ -9,9 +9,15 @@ import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import com.niuan.erp.common.base.OperationType;
import com.niuan.erp.module.production.controller.dto.PlanProductionIssueAddDto;
import com.niuan.erp.module.production.controller.dto.ProductionPlanDto;
import com.niuan.erp.module.production.controller.dto.ProductionPlanShortageDto;
import com.niuan.erp.module.production.entity.ProductionPlan;
import com.niuan.erp.module.production.service.ProductionPlanService;
import com.niuan.erp.module.purchase.controller.dto.PurchasePlanAddDto;
import com.niuan.erp.module.purchase.service.PurchasePlanService;
import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderAddDto;
import com.niuan.erp.module.warehouse.service.StockTransferOrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
@@ -20,66 +26,109 @@ import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "ProductionPlan")
@ModuleLog("ProductionPlan管理")
@ModuleLog("生产计划管理")
@RestController
@RequestMapping("/production/productionplan")
@RequestMapping("/production/productionPlan")
@RequiredArgsConstructor
public class ProductionPlanController {
private final ProductionPlanService productionPlanService;
@Operation(summary = "分页查询ProductionPlan数据", operationId = "getProductionPlanPage")
private final PurchasePlanService purchasePlanService;
private final StockTransferOrderService stockTransferOrderService;
@Operation(summary = "分页查询生产计划数据", operationId = "getProductionPlanPage")
@GetMapping("/getProductionPlanPage")
@PreAuthorize("hasAuthority('productionplan:index')")
@PreAuthorize("hasAuthority('production_plan:index')")
public BaseResult<IPage<ProductionPlanDto>> getProductionPlanPage(@Validated BasePageReqParams pageParams,
@Validated(Get.class) ProductionPlanDto searchParams) {
var wrapper = new LambdaQueryWrapper<ProductionPlan>();
if (searchParams != null) {
if (StringUtils.hasText(searchParams.customerName())) {
wrapper.like(ProductionPlan::getCreateUserName, searchParams.customerName());
}
if (StringUtils.hasText(searchParams.projectName())) {
wrapper.like(ProductionPlan::getProjectName, searchParams.projectName());
}
if (searchParams != null) {
if (StringUtils.hasText(searchParams.customerName())) {
wrapper.like(ProductionPlan::getCreateUserName, searchParams.customerName());
}
if (StringUtils.hasText(searchParams.projectName())) {
wrapper.like(ProductionPlan::getProjectName, searchParams.projectName());
}
}
wrapper.orderByDesc(ProductionPlan::getCreateDate);
return BaseResult.successWithData(productionPlanService.getProductionPlanPage(pageParams, wrapper));
}
@ApiLog(type = OperationType.ADD, remark = "新增一条ProductionPlan记录")
@Operation(summary = "新增ProductionPlan", operationId = "addProductionPlan")
@ApiLog(type = OperationType.ADD, remark = "新增一条生产计划记录")
@Operation(summary = "新增生产计划", operationId = "addProductionPlan")
@PostMapping("/addProductionPlan")
@PreAuthorize("hasAuthority('productionplan:add')")
@PreAuthorize("hasAuthority('production_plan:add')")
public BaseResult<?> addProductionPlan(@Validated(Add.class) @RequestBody ProductionPlanDto dto) {
productionPlanService.addProductionPlan(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.UPDATE, remark = "更新一条ProductionPlan记录")
@Operation(summary = "更新ProductionPlan", operationId = "updateProductionPlan")
@ApiLog(type = OperationType.UPDATE, remark = "更新一条生产计划记录")
@Operation(summary = "更新生产计划", operationId = "updateProductionPlan")
@PostMapping("/updateProductionPlan")
@PreAuthorize("hasAuthority('productionplan:update')")
@PreAuthorize("hasAuthority('production_plan:update')")
public BaseResult<?> updateProductionPlan(@Validated(Update.class) @RequestBody ProductionPlanDto dto) {
productionPlanService.updateProductionPlan(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.DELETE, remark = "删除一条ProductionPlan记录")
@Operation(summary = "删除ProductionPlan", operationId = "deleteProductionPlan")
@ApiLog(type = OperationType.DELETE, remark = "删除一条生产计划记录")
@Operation(summary = "删除生产计划", operationId = "deleteProductionPlan")
@PostMapping("/deleteProductionPlan")
@PreAuthorize("hasAuthority('productionplan:delete')")
@PreAuthorize("hasAuthority('production_plan:delete')")
public BaseResult<?> deleteProductionPlan(@Validated(DeleteOne.class) @RequestBody BaseDeleteBody req) {
productionPlanService.deleteProductionPlan(req.id());
return BaseResult.success();
}
@ApiLog(type = OperationType.DELETE, remark = "批量删除ProductionPlan记录")
@Operation(summary = "批量删除ProductionPlan", operationId = "deleteProductionPlanBatch")
@PostMapping("/deleteProductionPlanBatch")
@PreAuthorize("hasAuthority('productionplan:deleteBatch')")
public BaseResult<?> deleteProductionPlanBatch(@Validated(DeleteBatch.class) @RequestBody BaseDeleteBody req) {
productionPlanService.deleteBatch(req.ids());
@Operation(summary = "得到生产计划缺料值", operationId = "getMaterialShortageList")
@GetMapping("/getMaterialShortageList")
@PreAuthorize("hasAuthority('production_plan:viewMaterialShortage')")
public BaseResult<List<ProductionPlanShortageDto>> getMaterialShortageList(@RequestParam("ids") List<Long> ids) {
return BaseResult.successWithData(productionPlanService.getProductionPlanShortageList(ids));
}
@ApiLog(type = OperationType.ADD, remark = "生成一个采购计划")
@Operation(summary = "生成采购计划", operationId = "generatePurchasePlan")
@PostMapping("/generatePurchasePlan")
@PreAuthorize("hasAuthority('production_plan:generatePurchasePlan')")
public BaseResult<?> generatePurchasePlan(@Validated @RequestBody PurchasePlanAddDto dto) {
purchasePlanService.addPurchasePlan(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.ADD, remark = "生成一个调拨单")
@Operation(summary = "生成调拨单", operationId = "generateTransferOrder")
@PostMapping("/generateTransferOrder")
@PreAuthorize("hasAuthority('production_plan:generateTransferOrder')")
public BaseResult<?> generateTransferOrder(@Validated @RequestBody StockTransferOrderAddDto dto) {
stockTransferOrderService.addStockTransferOrder(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.ADD, remark = "生成一个出料单")
@Operation(summary = "生成出料单", operationId = "generateProductionIssue")
@PostMapping("/generateProductionIssue")
@PreAuthorize("hasAuthority('production_plan:generateProductionIssue')")
public BaseResult<?> generateProductionIssue(@Validated @RequestBody PlanProductionIssueAddDto dto) {
productionPlanService.generateProductionIssue(dto);
return BaseResult.success();
}
// @ApiLog(type = OperationType.DELETE, remark = "批量删除ProductionPlan记录")
// @Operation(summary = "批量删除生产计划", operationId = "deleteProductionPlanBatch")
// @PostMapping("/deleteProductionPlanBatch")
// @PreAuthorize("hasAuthority('production_plan:deleteBatch')")
// public BaseResult<?> deleteProductionPlanBatch(@Validated(DeleteBatch.class) @RequestBody BaseDeleteBody req) {
// productionPlanService.deleteBatch(req.ids());
// return BaseResult.success();
// }
}

View File

@@ -0,0 +1,30 @@
package com.niuan.erp.module.production.controller.dto;
import jakarta.validation.constraints.NotNull;
import java.util.List;
/**
* 添加 BOM Dto
* @param bomNo
* @param bomName
* @param manufacturer
* @param spec
* @param brandName
* @param formMark
* @param bomItems
*/
public record BomAddDto(
@NotNull(message = "production.bom.validate.bom_no.not_null")
String bomNo,
@NotNull(message = "production.bom.validate.bom_name.not_null")
String bomName,
@NotNull(message = "production.bom.validate.manufacturer.not_null")
String manufacturer,
@NotNull(message = "production.bom.validate.spec.not_null")
String spec,
@NotNull(message = "production.bom.validate.brand_name.not_null")
String brandName,
String formMark,
List<BomItemAddDto> bomItems
) {}

View File

@@ -1,23 +1,29 @@
package com.niuan.erp.module.production.controller.dto;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;
/**
* 前端展示 Dto
* @param id
* @param bomNo
* @param manufacturer
* @param bomName
* @param spec
* @param brandName
* @param formMark
* @param customerName
* @param bomItems
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public record BomDto(
Long id,
Integer status,
LocalDateTime createDate,
Long createUserId,
String createUserName,
LocalDateTime updateDate,
Long updateUserId,
String updateUserName,
Long parentId,
String bomNo,
String manufacturer,
String bomName,
String spec,
String brandName,
String formMark,
String customerName,
Integer customerId,
String searchCode) {}
Long id,
String bomNo,
String manufacturer,
String bomName,
String spec,
String brandName,
String formMark,
String customerName,
List<BomItemDto> bomItems) {}

View File

@@ -0,0 +1,30 @@
package com.niuan.erp.module.production.controller.dto;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
/**
* 添加 BOM 明细 Dto
* @param partNumber
* @param manufactureCount
* @param itemPosition
* @param productMark
* @param sameUseNum1
* @param sameUseNum2
* @param sameUseNum3
* @param sameUseNum
*/
public record BomItemAddDto(
@NotNull(message = "production.bom.validate.part_number.not_null")
String partNumber,
@NotNull(message = "production.bom.validate.manufacture_count.not_null")
@Min(value = 1, message = "production.bom.validate.manufacture_count.min")
Integer manufactureCount,
@NotNull(message = "production.bom.validate.item_position.not_null")
String itemPosition,
String productMark,
String sameUseNum1,
String sameUseNum2,
String sameUseNum3,
String sameUseNum
) {}

View File

@@ -1,18 +1,24 @@
package com.niuan.erp.module.production.controller.dto;
/**
* 前端展示 BOM 明细 Dto
* @param partNumber
* @param productType
* @param productSpecs
* @param productPackSize
* @param productBrand
* @param manufactureCount
* @param itemPosition
* @param sameUseCount
* @param productMark
*/
public record BomItemDto(
Long id,
Integer bomId,
String projectName,
String partNumber,
String itemPosition,
String productType,
String productSpecs,
String productPackSize,
String productBrand,
Integer manufactureCount,
String itemPosition,
Integer sameUseCount,
String sameUseNum1,
String sameUseNum2,
String sameUseNum3,
Integer loseRate,
Integer manufactureSpec,
String productMark,
Integer reserve1,
String reserve2) {}
String productMark) {}

View File

@@ -0,0 +1,5 @@
package com.niuan.erp.module.production.controller.dto;
public record BomSearchParams(
String searchCode,
String partNumber) {}

View File

@@ -0,0 +1,17 @@
package com.niuan.erp.module.production.controller.dto;
import jakarta.validation.constraints.NotNull;
import java.util.List;
/**
* 用于生产计划生成发料单
* @param ids 生产计划 ID List
* @param issue
*/
public record PlanProductionIssueAddDto(
@NotNull(message = "production.production_plan.validate.ids.not_null")
List<Long> ids,
@NotNull(message = "production.production_plan.validate.issue.not_null")
ProductionIssueAddDto issue
) {}

View File

@@ -0,0 +1,27 @@
package com.niuan.erp.module.production.controller.dto;
import jakarta.validation.constraints.NotNull;
import java.util.List;
/**
* 添加发料单 Dto
* @param formCode
* @param formName
* @param formMark
* @param storeNo
* @param storeName
* @param items
*/
public record ProductionIssueAddDto(
@NotNull(message = "production.production_plan.validate.form_code.not_null")
String formCode,
String formName,
String formMark,
@NotNull(message = "production.production_plan.validate.store_no.not_null")
Long storeNo,
@NotNull(message = "production.production_plan.validate.store_name.not_null")
String storeName,
@NotNull(message = "production.production_plan.validate.items.not_null")
List<ProductionIssueItemAddDto> items
) {}

View File

@@ -0,0 +1,24 @@
package com.niuan.erp.module.production.controller.dto;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
/**
* 发料单明细 Dto
* @param partNumber 物料便哈
* @param storeNo 发料仓库
* @param productCount 实发数量
* @param demandCount 需求数量
*/
public record ProductionIssueItemAddDto(
@NotNull(message = "production.production_plan.validate.part_number.not_null")
String partNumber,
@NotNull(message = "production.production_plan.validate.store_no.not_null")
Long storeNo,
@NotNull(message = "production.production_plan.validate.product_count.not_null")
@Min(value = 1, message = "production.production_plan.validate.product_count.min")
Integer productCount,
@NotNull(message = "production.production_plan.validate.demand_count.not_null")
@Min(value = 1, message = "production.production_plan.validate.demand_count.min")
Integer demandCount
) {}

View File

@@ -1,29 +1,30 @@
package com.niuan.erp.module.production.controller.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
@JsonInclude(JsonInclude.Include.NON_NULL)
public record ProductionPlanDto(
@NotNull(groups = Update.class, message = "")
Long id,
Integer status,
LocalDateTime createDate,
Long createUserId,
String createUserName,
LocalDateTime updateDate,
Long updateUserId,
String updateUserName,
@NotNull(groups = { Add.class, Update.class }, message = "")
String productionNum,
@NotNull(groups = { Add.class, Update.class }, message = "")
String projectName,
@NotNull(groups = { Add.class, Update.class }, message = "")
Integer projectId,
@NotNull(groups = { Add.class, Update.class }, message = "")
Integer productionCount,
Integer productionStatus,
String productionNote,
String productionReport,
String productionMark,
String reserve1,
String reserve2,
@NotNull(groups = { Add.class, Update.class }, message = "")
Integer storeNo,
@NotNull(groups = { Add.class, Update.class }, message = "")
String storeName,
Integer groupId,
String groupName,
Integer customerId,
String customerName) {}

View File

@@ -0,0 +1,12 @@
package com.niuan.erp.module.production.controller.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public record ProductionPlanShortageDto(
Long id,
String partNumber,
String productSpecs,
Integer requiredQty,
Integer stockQty,
Integer diffQty) {}

View File

@@ -1,5 +1,6 @@
package com.niuan.erp.module.production.converter;
import com.niuan.erp.module.production.controller.dto.BomAddDto;
import com.niuan.erp.module.production.controller.dto.BomDto;
import com.niuan.erp.module.production.entity.Bom;
import org.mapstruct.Mapper;
@@ -12,4 +13,6 @@ public interface BomConverter {
Bom toEntity(BomDto dto);
BomDto toDto(Bom entity);
List<BomDto> toDtoList(List<Bom> entities);
Bom toEntity(BomAddDto dto);
}

View File

@@ -1,5 +1,6 @@
package com.niuan.erp.module.production.converter;
import com.niuan.erp.module.production.controller.dto.BomItemAddDto;
import com.niuan.erp.module.production.controller.dto.BomItemDto;
import com.niuan.erp.module.production.entity.BomItem;
import org.mapstruct.Mapper;
@@ -10,6 +11,8 @@ import java.util.List;
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface BomItemConverter {
BomItem toEntity(BomItemDto dto);
BomItem toEntity(BomItemAddDto dto);
BomItemDto toDto(BomItem entity);
List<BomItemDto> toDtoList(List<BomItem> entities);
List<BomItem> toEntityList(List<BomItemAddDto> dtos);
}

View File

@@ -1,7 +1,10 @@
package com.niuan.erp.module.production.converter;
import com.niuan.erp.module.common.entity.Document;
import com.niuan.erp.module.common.entity.DocumentMaterial;
import com.niuan.erp.module.production.controller.dto.ProductionIssueAddDto;
import com.niuan.erp.module.production.controller.dto.ProductionIssueDto;
import com.niuan.erp.module.production.controller.dto.ProductionIssueItemAddDto;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
@@ -10,6 +13,9 @@ import java.util.List;
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface ProductionIssueConverter {
Document toEntity(ProductionIssueDto dto);
Document toEntity(ProductionIssueAddDto dto);
DocumentMaterial toEntity(ProductionIssueItemAddDto dto);
List<DocumentMaterial> toEntityList(List<ProductionIssueItemAddDto> dtoList);
ProductionIssueDto toDto(Document entity);
List<ProductionIssueDto> toDtoList(List<Document> entities);
}

View File

@@ -4,12 +4,14 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.niuan.erp.module.production.controller.dto.BomItemDto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
/**
* <p>
@@ -77,4 +79,7 @@ public class Bom implements Serializable {
@TableField("CustomerId")
private Integer customerId;
@TableField(exist = false)
private List<BomItemDto> bomItems;
}

View File

@@ -0,0 +1,42 @@
package com.niuan.erp.module.production.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class ProduceOrderList implements Serializable {
// 基础信息
private Integer id;
private String partnumber;
private String productspecs;
private String storeNo;
// BOM 信息
private Integer sameUseCount; // 1, 2, 3
private String sameNum1;
private String sameNum2;
private String sameNum3;
private Integer bomTotal; // 单个BOM用量
private Integer orderTotal; // 订单数量
// 【新增】从 SQL 直接查出的库存字段
// 主料库存
private Integer mainStock;
// 替换料1库存
private Integer sub1Stock;
// 替换料2库存
private Integer sub2Stock;
// 替换料3库存
private Integer sub3Stock;
// 占用数量 (假设默认0或从其他字段映射此处保持逻辑一致)
private Integer productOccupyTotal = 0;
// 【计算字段】(对应 C# 中的 m.Productstocktotal 等)
// 注意C# 代码中 m.Productstocktotal 初始值是主料库存,后续会累加替换料
private Integer productstocktotal;
private Integer demandTotal;
private Integer surplus;
private Integer differenceTotal;
private String mark;
private String shortageForm;
}

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.niuan.erp.module.production.enums.ProductionPlanStatus;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@@ -64,7 +65,7 @@ public class ProductionPlan implements Serializable {
private Integer productionCount;
@TableField("ProductionStatus")
private Integer productionStatus;
private ProductionPlanStatus productionStatus;
@TableField("ProductionNote")
private String productionNote;

View File

@@ -0,0 +1,32 @@
package com.niuan.erp.module.production.enums;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.niuan.erp.common.base.BaseStatus;
public enum ProductionPlanStatus implements IEnum<Integer> {
NoComplete(0, "未完成"),
Completed(1, "已完成"),
Approving(2, "审核中"),
Reviewed(3, "已审核");
final int code;
final String description;
ProductionPlanStatus(int code, String description) {
this.code = code;
this.description = description;
}
/**
*
* @param code
* @return
*/
public static ProductionPlanStatus fromCode(int code) {
return ProductionPlanStatus.values()[code];
}
@Override
public Integer getValue() {
return code;
}
}

View File

@@ -1,8 +1,11 @@
package com.niuan.erp.module.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.niuan.erp.module.production.controller.dto.BomItemDto;
import com.niuan.erp.module.production.entity.BomItem;
import java.util.List;
/**
* <p>
* Mapper 接口
@@ -13,4 +16,8 @@ import com.niuan.erp.module.production.entity.BomItem;
*/
public interface BomItemMapper extends BaseMapper<BomItem> {
List<BomItemDto> getBomItemListByBomId(Long bomId);
List<BomItemDto> getBomItemListByBomIdAndPartNumber(Long bomId, String partNumber);
}

View File

@@ -1,8 +1,13 @@
package com.niuan.erp.module.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.niuan.erp.common.base.BaseSelectDto;
import com.niuan.erp.module.production.entity.Bom;
import java.util.List;
/**
* <p>
* Mapper 接口
@@ -13,4 +18,8 @@ import com.niuan.erp.module.production.entity.Bom;
*/
public interface BomMapper extends BaseMapper<Bom> {
IPage<Bom> selectPageByPartNumber(Page page, String searchCode, String partNumber);
List<BaseSelectDto> getBomSelectList();
}

View File

@@ -1,7 +1,14 @@
package com.niuan.erp.module.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.niuan.erp.module.production.controller.dto.ProductionPlanShortageDto;
import com.niuan.erp.module.production.entity.ProduceOrderList;
import com.niuan.erp.module.production.entity.ProductionPlan;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* <p>
@@ -13,4 +20,9 @@ import com.niuan.erp.module.production.entity.ProductionPlan;
*/
public interface ProductionPlanMapper extends BaseMapper<ProductionPlan> {
List<ProductionPlanShortageDto> getProductionPlanRequiredQtyList(@Param("ids") List<Long> ids,
@Param("warehouseId") Long warehouseId);
List<ProduceOrderList> selectProduceOrderData(@Param("ids") List<Long> ids);
}

View File

@@ -3,7 +3,10 @@ package com.niuan.erp.module.production.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseSelectDto;
import com.niuan.erp.module.production.controller.dto.BomAddDto;
import com.niuan.erp.module.production.controller.dto.BomDto;
import com.niuan.erp.module.production.controller.dto.BomItemDto;
import com.niuan.erp.module.production.entity.Bom;
import java.util.List;
@@ -12,7 +15,13 @@ public interface BomService {
IPage<BomDto> getBomPage(BasePageReqParams pageParams, LambdaQueryWrapper<Bom> wrapper);
void addBom(BomDto dto);
IPage<BomDto> getBomPageWithItem(BasePageReqParams pageParams, String searchCode, String partNumber);
List<BaseSelectDto> getBomSelectList();
List<BomItemDto> getBomItemList(Long bomId);
void addBom(BomAddDto dto);
void updateBom(BomDto dto);

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.module.common.entity.Document;
import com.niuan.erp.module.production.controller.dto.ProductionIssueAddDto;
import com.niuan.erp.module.production.controller.dto.ProductionIssueDto;
import java.util.List;
@@ -12,7 +13,7 @@ public interface ProductionIssueService {
IPage<ProductionIssueDto> getProductionIssuePage(BasePageReqParams pageParams, LambdaQueryWrapper<Document> wrapper);
void addProductionIssue(ProductionIssueDto dto);
void addProductionIssue(ProductionIssueAddDto dto);
void updateProductionIssue(ProductionIssueDto dto);

View File

@@ -3,7 +3,10 @@ package com.niuan.erp.module.production.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.module.production.controller.dto.PlanProductionIssueAddDto;
import com.niuan.erp.module.production.controller.dto.ProductionIssueAddDto;
import com.niuan.erp.module.production.controller.dto.ProductionPlanDto;
import com.niuan.erp.module.production.controller.dto.ProductionPlanShortageDto;
import com.niuan.erp.module.production.entity.ProductionPlan;
import java.util.List;
@@ -20,4 +23,8 @@ public interface ProductionPlanService {
void deleteBatch(List<Long> ids);
List<ProductionPlanShortageDto> getProductionPlanShortageList(List<Long> ids);
void generateProductionIssue(PlanProductionIssueAddDto dto);
}

View File

@@ -5,12 +5,19 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseSelectDto;
import com.niuan.erp.common.exception.BusinessException;
import com.niuan.erp.common.utils.SecurityUtils;
import com.niuan.erp.module.production.controller.dto.BomDto;
import com.niuan.erp.module.production.controller.dto.*;
import com.niuan.erp.module.production.converter.BomConverter;
import com.niuan.erp.module.production.converter.BomItemConverter;
import com.niuan.erp.module.production.entity.Bom;
import com.niuan.erp.module.production.entity.BomItem;
import com.niuan.erp.module.production.mapper.BomItemMapper;
import com.niuan.erp.module.production.mapper.BomMapper;
import com.niuan.erp.module.production.service.BomService;
import com.niuan.erp.module.warehouse.entity.WarehouseItem;
import com.niuan.erp.module.warehouse.mapper.WarehouseItemMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -27,6 +34,12 @@ public class BomServiceImpl extends ServiceImpl<BomMapper, Bom> implements BomSe
private final BomConverter bomConverter;
private final BomItemMapper bomItemMapper;
private final WarehouseItemMapper warehouseItemMapper;
private final BomItemConverter bomItemConverter;
@Override
public IPage<BomDto> getBomPage(BasePageReqParams pageParams, LambdaQueryWrapper<Bom> wrapper) {
IPage<Bom> result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper);
@@ -34,13 +47,63 @@ public class BomServiceImpl extends ServiceImpl<BomMapper, Bom> implements BomSe
}
@Override
public void addBom(BomDto dto) {
public IPage<BomDto> getBomPageWithItem(BasePageReqParams pageParams, String searchCode, String partNumber) {
IPage<Bom> bomPage = this.baseMapper.selectPageByPartNumber(new Page<>(pageParams.page(), pageParams.pageSize()),
searchCode, partNumber);
List<Bom> bomList = bomPage.getRecords();
bomList.forEach(b -> {
b.setBomItems(bomItemMapper.getBomItemListByBomIdAndPartNumber(b.getId(), partNumber));
});
return bomPage.convert(bomConverter::toDto);
}
@Override
public List<BaseSelectDto> getBomSelectList() {
return this.baseMapper.getBomSelectList();
}
@Override
public List<BomItemDto> getBomItemList(Long bomId) {
return bomItemMapper.getBomItemListByBomId(bomId);
}
@Override
public void addBom(BomAddDto dto) {
// 检验数据
var searchBomNameWrapper = new LambdaQueryWrapper<Bom>().eq(Bom::getBomName, dto.bomName());
if (this.baseMapper.selectCount(searchBomNameWrapper) > 0) {
throw new BusinessException("production.bom.exception.duplicate_bom_name");
}
List<BomItemAddDto> items = dto.bomItems();
List<String> itemPartNumbers = items.stream().map(BomItemAddDto::partNumber).distinct().toList();
if (items.size() != itemPartNumbers.size()) {
throw new BusinessException("production.bom.exception.duplicate_bom_item");
}
items.forEach(item -> {
if (item.itemPosition().split(",").length != item.manufactureCount()) {
throw new BusinessException("production.bom.exception.unpair_position_count");
}
});
var searchBomItemWrapper = new LambdaQueryWrapper<WarehouseItem>().in(WarehouseItem::getPartNumber, itemPartNumbers);
if (warehouseItemMapper.selectCount(searchBomItemWrapper) != items.size()) {
throw new BusinessException("production.bom.exception.unexists_bom_item");
}
// save
Bom entity = bomConverter.toEntity(dto);
entity.setCreateUserId(SecurityUtils.getUserId());
entity.setCreateUserName(SecurityUtils.getUserName());
entity.setCreateDate(LocalDateTime.now());
entity.setStatus(0);
entity.setCustomerId(SecurityUtils.getLoginUser().getUser().getCustomerId());
entity.setCustomerName(SecurityUtils.getUserName());
this.baseMapper.insert(entity);
List<BomItem> bomItemEntities = bomItemConverter.toEntityList(items);
bomItemEntities.forEach(item -> {
item.setBomId(Math.toIntExact(entity.getId()));
});
bomItemMapper.insert(bomItemEntities);
}
@Override

View File

@@ -7,16 +7,22 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.utils.SecurityUtils;
import com.niuan.erp.module.common.entity.Document;
import com.niuan.erp.module.common.entity.DocumentMaterial;
import com.niuan.erp.module.common.enums.DocumentType;
import com.niuan.erp.module.common.mapper.DocumentMapper;
import com.niuan.erp.module.common.mapper.DocumentMaterialMapper;
import com.niuan.erp.module.production.controller.dto.ProductionIssueAddDto;
import com.niuan.erp.module.production.controller.dto.ProductionIssueDto;
import com.niuan.erp.module.production.converter.ProductionIssueConverter;
import com.niuan.erp.module.production.service.ProductionIssueService;
import com.niuan.erp.module.warehouse.mapper.WarehouseItemMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@Service
@@ -24,9 +30,12 @@ import java.util.List;
@RequiredArgsConstructor
public class ProductionIssueServiceImpl extends ServiceImpl<DocumentMapper, Document> implements ProductionIssueService {
private final ProductionIssueConverter productionIssueConverter;
private final WarehouseItemMapper warehouseItemMapper;
private final DocumentMaterialMapper documentMaterialMapper;
@Override
public IPage<ProductionIssueDto> getProductionIssuePage(BasePageReqParams pageParams, LambdaQueryWrapper<Document> wrapper) {
IPage<Document> result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper);
@@ -34,13 +43,34 @@ public class ProductionIssueServiceImpl extends ServiceImpl<DocumentMapper, Docu
}
@Override
public void addProductionIssue(ProductionIssueDto dto) {
public void addProductionIssue(ProductionIssueAddDto dto) {
System.out.println(dto);
Document entity = productionIssueConverter.toEntity(dto);
entity.setCreateUserId(SecurityUtils.getUserId());
entity.setCreateUserName(SecurityUtils.getUserName());
entity.setCreateDate(LocalDateTime.now());
entity.setStatus(0);
entity.setFormType(DocumentType.PRODUCTION_ISSUE);
entity.setCustomerId(SecurityUtils.getCustomerId());
entity.setGroupId(SecurityUtils.getLoginUser().getUser().getProjectId().intValue());
this.baseMapper.insert(entity);
List<DocumentMaterial> materials = productionIssueConverter.toEntityList(dto.items());
// 查库存
Map<String, Map<String, Object>> warehouseItems =
warehouseItemMapper.getWarehouseItemStockListByPartNumbers(materials.stream()
.map(DocumentMaterial::getPartNumber)
.toList());
materials.forEach(m -> {
m.setCreateUserId(SecurityUtils.getUserId());
m.setCreateUserName(SecurityUtils.getUserName());
m.setCreateDate(LocalDateTime.now());
m.setStatus(0);
m.setDocumentNo(entity.getId().intValue());
});
documentMaterialMapper.insert(materials);
}
@Override

View File

@@ -5,18 +5,25 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.exception.BusinessException;
import com.niuan.erp.common.utils.SecurityUtils;
import com.niuan.erp.module.production.controller.dto.ProductionPlanDto;
import com.niuan.erp.module.common.mapper.DocumentMapper;
import com.niuan.erp.module.production.controller.dto.*;
import com.niuan.erp.module.production.converter.ProductionPlanConverter;
import com.niuan.erp.module.production.entity.ProduceOrderList;
import com.niuan.erp.module.production.entity.ProductionPlan;
import com.niuan.erp.module.production.enums.ProductionPlanStatus;
import com.niuan.erp.module.production.mapper.ProductionPlanMapper;
import com.niuan.erp.module.production.service.ProductionIssueService;
import com.niuan.erp.module.production.service.ProductionPlanService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.Validator;
import java.time.LocalDateTime;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
@Service
@@ -24,9 +31,14 @@ import java.util.List;
@RequiredArgsConstructor
public class ProductionPlanServiceImpl extends ServiceImpl<ProductionPlanMapper, ProductionPlan> implements ProductionPlanService {
private final ProductionPlanConverter productionPlanConverter;
private final ProductionIssueService productionIssueService;
private final DocumentMapper documentMapper;
private final Validator validator;
@Override
public IPage<ProductionPlanDto> getProductionPlanPage(BasePageReqParams pageParams, LambdaQueryWrapper<ProductionPlan> wrapper) {
IPage<ProductionPlan> result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper);
@@ -40,6 +52,9 @@ public class ProductionPlanServiceImpl extends ServiceImpl<ProductionPlanMapper,
entity.setCreateUserName(SecurityUtils.getUserName());
entity.setCreateDate(LocalDateTime.now());
entity.setStatus(0);
entity.setCustomerId(SecurityUtils.getCustomerId());
entity.setProductionStatus(ProductionPlanStatus.NoComplete);
entity.setGroupId(SecurityUtils.getLoginUser().getUser().getProjectId().intValue());
this.baseMapper.insert(entity);
}
@@ -62,4 +77,175 @@ public class ProductionPlanServiceImpl extends ServiceImpl<ProductionPlanMapper,
this.baseMapper.deleteByIds(ids);
}
/**
* 核心业务方法:获取数据并计算差异
* 逻辑完全对标 C# 的 GetData + forList
*/
@Override
public List<ProductionPlanShortageDto> getProductionPlanShortageList(List<Long> ids) {
// 2. 【性能优化点】一次性查出所有数据 (包含主料和所有替换料库存)
// 对应 C#: base.Context.Queryable(...).ToPageListAsync(...)
// 注意:这里先不分页,因为后面有 GroupBy分页应在聚合后处理或者如果数据量极大需在 SQL 层面先过滤明细再聚合
List<ProduceOrderList> list = this.baseMapper.selectProduceOrderData(ids);
// 3. 【核心逻辑】内存计算 (对应 C# 的 forList 方法)
// 此时不再访问数据库,直接使用 list 中已查出的 mainStock, sub1Stock 等字段
for (ProduceOrderList m : list) {
int count1 = 0;
int count2 = 0;
int count3 = 0;
// 初始化主料库存 (对应 C# m.Productstocktotal 初始值)
// C# 代码中 m.Productstocktotal 来自 f.ProductCount (即主料)
int currentStockTotal = (m.getMainStock() == null) ? 0 : m.getMainStock();
int occupyTotal = (m.getProductOccupyTotal() == null) ? 0 : m.getProductOccupyTotal();
// --- 开始模拟 C# 的 if 判断 ---
// if (m.SameUseCount == 1)
if (m.getSameUseCount() != null && m.getSameUseCount() == 1) {
// C#: productcount1 = ... Where(PartNumber == m.SameNum1)
// Java: 直接从 sub1Stock 取 (SQL 已经帮我们要到了)
count1 = (m.getSub1Stock() == null) ? 0 : m.getSub1Stock();
}
// if (m.SameUseCount == 2)
if (m.getSameUseCount() != null && m.getSameUseCount() == 2) {
count1 = (m.getSub1Stock() == null) ? 0 : m.getSub1Stock();
count2 = (m.getSub2Stock() == null) ? 0 : m.getSub2Stock();
}
// if (m.SameUseCount == 3)
if (m.getSameUseCount() != null && m.getSameUseCount() == 3) {
count1 = (m.getSub1Stock() == null) ? 0 : m.getSub1Stock();
count2 = (m.getSub2Stock() == null) ? 0 : m.getSub2Stock();
count3 = (m.getSub3Stock() == null) ? 0 : m.getSub3Stock();
}
// --- 开始计算逻辑 (与 C# 完全一致) ---
// m.DemandTotal = m.OrderTotal * m.BomTotal;
int orderTotal = (m.getOrderTotal() == null) ? 0 : m.getOrderTotal();
int bomTotal = (m.getBomTotal() == null) ? 0 : m.getBomTotal();
m.setDemandTotal(orderTotal * bomTotal);
// m.Surplus = m.Productstocktotal - m.ProductOccupyTotal;
m.setProductstocktotal(currentStockTotal); // 设置初始库存
m.setSurplus(currentStockTotal - occupyTotal);
// m.DifferenceTotal = m.Surplus - m.DemandTotal;
m.setDifferenceTotal(m.getSurplus() - m.getDemandTotal());
// 当Bom里主干物料够用的时候替换料不计入统计
// if ((m.DifferenceTotal < 0) && (count1 > 0 || count2 > 0 || count3 > 0))
if ((m.getDifferenceTotal() < 0) && (count1 > 0 || count2 > 0 || count3 > 0)) {
StringBuilder markBuilder = new StringBuilder("用到替换料:");
boolean hasSub = false;
if (count1 > 0) {
markBuilder.append(m.getSameNum1()).append(".");
hasSub = true;
}
if (count2 > 0) {
markBuilder.append(m.getSameNum2()).append(".");
hasSub = true;
}
if (count3 > 0) {
markBuilder.append(m.getSameNum3()).append(".");
hasSub = true;
}
if (hasSub) {
m.setMark(markBuilder.toString());
// m.DifferenceTotal += count1 + count2 + count3;
m.setDifferenceTotal(m.getDifferenceTotal() + count1 + count2 + count3);
// m.Productstocktotal += count1 + count2 + count3;
int newStockTotal = currentStockTotal + count1 + count2 + count3;
m.setProductstocktotal(newStockTotal);
// m.Surplus = m.Productstocktotal - m.ProductOccupyTotal;
m.setSurplus(newStockTotal - occupyTotal);
}
}
// m.DifferenceTotal = m.DifferenceTotal > 0 ? 0 : m.DifferenceTotal;
if (m.getDifferenceTotal() > 0) {
m.setDifferenceTotal(0);
}
}
// 4. 【聚合逻辑】对应 C# 的 GroupBy
// Key: Id, Partnumber, Productspecs, Mark
List<ProduceOrderList> resultList = list.stream()
.collect(Collectors.groupingBy(m -> {
// 构建复合键
return Arrays.asList(
m.getId(),
m.getPartnumber(),
m.getProductspecs(),
m.getMark() == null ? "" : m.getMark()
);
}))
.values().stream()
.map(group -> {
ProduceOrderList first = group.get(0);
ProduceOrderList aggregated = new ProduceOrderList();
aggregated.setId(first.getId());
aggregated.setPartnumber(first.getPartnumber());
aggregated.setProductspecs(first.getProductspecs());
aggregated.setMark(first.getMark());
// Sum DemandTotal
int sumDemand = group.stream()
.mapToInt(item -> (item.getDemandTotal() == null ? 0 : item.getDemandTotal()))
.sum();
aggregated.setDemandTotal(sumDemand);
// Max Surplus (C# 逻辑: a.Max(c => c.Surplus))
int maxSurplus = group.stream()
.mapToInt(item -> (item.getSurplus() == null ? 0 : item.getSurplus()))
.max()
.orElse(0);
aggregated.setSurplus(maxSurplus);
// DifferenceTotal = Max(Surplus) - Sum(DemandTotal)
aggregated.setDifferenceTotal(maxSurplus - sumDemand);
return aggregated;
})
.toList();
return resultList.stream().map(result -> new ProductionPlanShortageDto(
Long.valueOf(result.getId()), result.getPartnumber(), result.getProductspecs(),
result.getDemandTotal(), result.getSurplus(), result.getDifferenceTotal())).toList();
}
@Override
public void generateProductionIssue(PlanProductionIssueAddDto dto) {
List<ProductionPlan> plans = this.baseMapper
.selectList(new LambdaQueryWrapper<ProductionPlan>().in(ProductionPlan::getId, dto.ids()));
plans.forEach(plan -> {
if (!plan.getProductionStatus().equals(ProductionPlanStatus.NoComplete)) {
throw new BusinessException("production.production_plan.exception.must_no_complete");
}
});
if (plans.stream().collect(Collectors.groupingBy(ProductionPlan::getStoreNo)).size() > 1) {
throw new BusinessException("production.production_plan.exception.more_than_one_warehouse");
}
plans.forEach(plan -> {
plan.setUpdateUserId(SecurityUtils.getUserId());
plan.setUpdateUserName(SecurityUtils.getUserName());
plan.setUpdateDate(LocalDateTime.now());
plan.setProductionStatus(ProductionPlanStatus.Completed);
});
this.baseMapper.updateById(plans);
productionIssueService.addProductionIssue(dto.issue());
}
}

View File

@@ -9,6 +9,7 @@ import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import com.niuan.erp.common.base.OperationType;
import com.niuan.erp.module.purchase.controller.dto.PurchasePlanAddDto;
import com.niuan.erp.module.purchase.controller.dto.PurchasePlanDto;
import com.niuan.erp.module.purchase.entity.PurchasePlan;
import com.niuan.erp.module.purchase.service.PurchasePlanService;
@@ -48,7 +49,7 @@ public class PurchasePlanController {
@Operation(summary = "新增PurchasePlan", operationId = "addPurchasePlan")
@PostMapping("/addPurchasePlan")
@PreAuthorize("hasAuthority('purchaseplan:add')")
public BaseResult<?> addPurchasePlan(@Validated(Add.class) @RequestBody PurchasePlanDto dto) {
public BaseResult<?> addPurchasePlan(@Validated(Add.class) @RequestBody PurchasePlanAddDto dto) {
purchasePlanService.addPurchasePlan(dto);
return BaseResult.success();
}

View File

@@ -0,0 +1,22 @@
package com.niuan.erp.module.purchase.controller.dto;
import jakarta.validation.constraints.NotNull;
import java.util.List;
public record PurchasePlanAddDto(
@NotNull(message = "purchase.purchase_plan.validate.plan_no.not_null")
String planNo,
// 收货仓库
@NotNull(message = "purchase.purchase_plan.validate.store_no.not_null")
Long storeNo,
@NotNull(message = "purchase.purchase_plan.validate.store_name.not_null")
String storeName,
// 备注
String remask,
// 计划单名称内容
@NotNull(message = "purchase.purchase_plan.validate.plan_name.not_null")
String planName,
List<PurchasePlanItemAddDto> planItems
) {}

View File

@@ -0,0 +1,16 @@
package com.niuan.erp.module.purchase.controller.dto;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
public record PurchasePlanItemAddDto(
@NotNull(message = "purchase.purchase_plan.validate.part_number.not_null")
String partNumber,
@NotNull(message = "purchase.purchase_plan.validate.purchase_count.not_null")
@Min(value = 0, message = "purchase.purchase_plan.validate.purchase_count.min")
Integer purchaseCount,
@NotNull(message = "purchase.purchase_plan.validate.part_id.not_null")
Long partId
) {}

View File

@@ -1,5 +1,6 @@
package com.niuan.erp.module.purchase.converter;
import com.niuan.erp.module.purchase.controller.dto.PurchasePlanAddDto;
import com.niuan.erp.module.purchase.controller.dto.PurchasePlanDto;
import com.niuan.erp.module.purchase.entity.PurchasePlan;
import org.mapstruct.Mapper;
@@ -10,6 +11,7 @@ import java.util.List;
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface PurchasePlanConverter {
PurchasePlan toEntity(PurchasePlanDto dto);
PurchasePlan toEntity(PurchasePlanAddDto dto);
PurchasePlanDto toDto(PurchasePlan entity);
List<PurchasePlanDto> toDtoList(List<PurchasePlan> entities);
}

View File

@@ -1,5 +1,6 @@
package com.niuan.erp.module.purchase.converter;
import com.niuan.erp.module.purchase.controller.dto.PurchasePlanItemAddDto;
import com.niuan.erp.module.purchase.controller.dto.PurchasePlanItemDto;
import com.niuan.erp.module.purchase.entity.PurchasePlanItem;
import org.mapstruct.Mapper;
@@ -10,6 +11,8 @@ import java.util.List;
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface PurchasePlanItemConverter {
PurchasePlanItem toEntity(PurchasePlanItemDto dto);
PurchasePlanItem toEntity(PurchasePlanItemAddDto dto);
List<PurchasePlanItem> toEntityList(List<PurchasePlanItemAddDto> dtoList);
PurchasePlanItemDto toDto(PurchasePlanItem entity);
List<PurchasePlanItemDto> toDtoList(List<PurchasePlanItem> entities);
}

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.niuan.erp.module.purchase.enums.PurchasePlanStatus;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@@ -64,7 +65,7 @@ public class PurchasePlan implements Serializable {
private Long storeNo;
@TableField("PlanStatus")
private Integer planStatus;
private PurchasePlanStatus planStatus;
@TableField("StoreName")
private String storeName;

View File

@@ -0,0 +1,31 @@
package com.niuan.erp.module.purchase.enums;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.niuan.erp.common.base.BaseStatus;
public enum PurchasePlanStatus implements IEnum<Integer> {
UNSTART(0, "未开始"),
IN_PROGRESS(1, "执行中"),
Completed(2, "已完成");
final int code;
final String description;
PurchasePlanStatus(int code, String description) {
this.code = code;
this.description = description;
}
/**
*
* @param code
* @return
*/
public static PurchasePlanStatus fromCode(int code) {
return PurchasePlanStatus.values()[code];
}
@Override
public Integer getValue() {
return code;
}
}

View File

@@ -3,6 +3,7 @@ package com.niuan.erp.module.purchase.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.module.purchase.controller.dto.PurchasePlanAddDto;
import com.niuan.erp.module.purchase.controller.dto.PurchasePlanDto;
import com.niuan.erp.module.purchase.entity.PurchasePlan;
@@ -12,7 +13,7 @@ public interface PurchasePlanService {
IPage<PurchasePlanDto> getPurchasePlanPage(BasePageReqParams pageParams, LambdaQueryWrapper<PurchasePlan> wrapper);
void addPurchasePlan(PurchasePlanDto dto);
void addPurchasePlan(PurchasePlanAddDto dto);
void updatePurchasePlan(PurchasePlanDto dto);

View File

@@ -6,9 +6,14 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.utils.SecurityUtils;
import com.niuan.erp.module.purchase.controller.dto.PurchasePlanAddDto;
import com.niuan.erp.module.purchase.controller.dto.PurchasePlanDto;
import com.niuan.erp.module.purchase.converter.PurchasePlanConverter;
import com.niuan.erp.module.purchase.converter.PurchasePlanItemConverter;
import com.niuan.erp.module.purchase.entity.PurchasePlan;
import com.niuan.erp.module.purchase.entity.PurchasePlanItem;
import com.niuan.erp.module.purchase.enums.PurchasePlanStatus;
import com.niuan.erp.module.purchase.mapper.PurchasePlanItemMapper;
import com.niuan.erp.module.purchase.mapper.PurchasePlanMapper;
import com.niuan.erp.module.purchase.service.PurchasePlanService;
import lombok.RequiredArgsConstructor;
@@ -24,9 +29,12 @@ import java.util.List;
@RequiredArgsConstructor
public class PurchasePlanServiceImpl extends ServiceImpl<PurchasePlanMapper, PurchasePlan> implements PurchasePlanService {
private final PurchasePlanConverter purchasePlanConverter;
private final PurchasePlanItemConverter purchasePlanItemConverter;
private final PurchasePlanItemMapper purchasePlanItemMapper;
@Override
public IPage<PurchasePlanDto> getPurchasePlanPage(BasePageReqParams pageParams, LambdaQueryWrapper<PurchasePlan> wrapper) {
IPage<PurchasePlan> result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper);
@@ -34,13 +42,20 @@ public class PurchasePlanServiceImpl extends ServiceImpl<PurchasePlanMapper, Pur
}
@Override
public void addPurchasePlan(PurchasePlanDto dto) {
public void addPurchasePlan(PurchasePlanAddDto dto) {
PurchasePlan entity = purchasePlanConverter.toEntity(dto);
entity.setCreateUserId(SecurityUtils.getUserId());
entity.setCreateUserName(SecurityUtils.getUserName());
entity.setCreateDate(LocalDateTime.now());
entity.setStatus(0);
entity.setPlanStatus(PurchasePlanStatus.UNSTART);
this.baseMapper.insert(entity);
List<PurchasePlanItem> planItems = purchasePlanItemConverter.toEntityList(dto.planItems());
planItems.forEach(item -> {
item.setPlanId(entity.getId());
});
purchasePlanItemMapper.insert(planItems);
}
@Override

View File

@@ -0,0 +1,32 @@
package com.niuan.erp.module.sys.enums;
import com.baomidou.mybatisplus.annotation.IEnum;
import lombok.Getter;
@Getter
public enum PermissionType implements IEnum<Integer> {
MENU(0, "菜单"),
TOP_PAGE_BUTTON(1, "页面按钮"),
TABLE_OPERATOR_BUTTON(2, "表格操作按钮"),
TABLE_STATUS_BUTTON(3, "表格状态按钮"),
DIALOG_BUTTON(4, "对话框按钮");
final int code;
final String description;
PermissionType(int code, String description) {
this.code = code;
this.description = description;
}
public static PermissionType fromCode(int code) {
for (PermissionType permissionType : PermissionType.values()) {
if (permissionType.code == code) return permissionType;
}
// TODO 异常
return null;
}
@Override
public Integer getValue() {
return code;
}
}

View File

@@ -1,82 +0,0 @@
package com.niuan.erp.module.warehouse.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.annotation.ApiLog;
import com.niuan.erp.common.annotation.ModuleLog;
import com.niuan.erp.common.base.BaseDeleteBody;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import com.niuan.erp.common.base.OperationType;
import com.niuan.erp.module.warehouse.controller.dto.StockByBrandDto;
import com.niuan.erp.module.warehouse.entity.Stock;
import com.niuan.erp.module.warehouse.service.StockByBrandService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Tag(name = "StockByBrand")
@ModuleLog("StockByBrand管理")
@RestController
@RequestMapping("/warehouse/stockbybrand")
@RequiredArgsConstructor
public class StockByBrandController {
private final StockByBrandService stockByBrandService;
@Operation(summary = "分页查询StockByBrand数据", operationId = "getStockByBrandPage")
@GetMapping("/getStockByBrandPage")
@PreAuthorize("hasAuthority('stockbybrand:index')")
public BaseResult<IPage<StockByBrandDto>> getStockByBrandPage(@Validated BasePageReqParams pageParams,
@Validated(Get.class) StockByBrandDto searchParams) {
var wrapper = new LambdaQueryWrapper<Stock>();
if (searchParams != null) {
if (StringUtils.hasText(searchParams.partNumber())) {
wrapper.like(Stock::getPartNumber, searchParams.partNumber());
}
}
return BaseResult.successWithData(stockByBrandService.getStockByBrandPage(pageParams, wrapper));
}
@ApiLog(type = OperationType.ADD, remark = "新增一条StockByBrand记录")
@Operation(summary = "新增StockByBrand", operationId = "addStockByBrand")
@PostMapping("/addStockByBrand")
@PreAuthorize("hasAuthority('stockbybrand:add')")
public BaseResult<?> addStockByBrand(@Validated(Add.class) @RequestBody StockByBrandDto dto) {
stockByBrandService.addStockByBrand(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.UPDATE, remark = "更新一条StockByBrand记录")
@Operation(summary = "更新StockByBrand", operationId = "updateStockByBrand")
@PostMapping("/updateStockByBrand")
@PreAuthorize("hasAuthority('stockbybrand:update')")
public BaseResult<?> updateStockByBrand(@Validated(Update.class) @RequestBody StockByBrandDto dto) {
stockByBrandService.updateStockByBrand(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.DELETE, remark = "删除一条StockByBrand记录")
@Operation(summary = "删除StockByBrand", operationId = "deleteStockByBrand")
@PostMapping("/deleteStockByBrand")
@PreAuthorize("hasAuthority('stockbybrand:delete')")
public BaseResult<?> deleteStockByBrand(@Validated(DeleteOne.class) @RequestBody BaseDeleteBody req) {
stockByBrandService.deleteStockByBrand(req.id());
return BaseResult.success();
}
@ApiLog(type = OperationType.DELETE, remark = "批量删除StockByBrand记录")
@Operation(summary = "批量删除StockByBrand", operationId = "deleteStockByBrandBatch")
@PostMapping("/deleteStockByBrandBatch")
@PreAuthorize("hasAuthority('stockbybrand:deleteBatch')")
public BaseResult<?> deleteStockByBrandBatch(@Validated(DeleteBatch.class) @RequestBody BaseDeleteBody req) {
stockByBrandService.deleteBatch(req.ids());
return BaseResult.success();
}
}

View File

@@ -1,82 +0,0 @@
package com.niuan.erp.module.warehouse.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.annotation.ApiLog;
import com.niuan.erp.common.annotation.ModuleLog;
import com.niuan.erp.common.base.BaseDeleteBody;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import com.niuan.erp.common.base.OperationType;
import com.niuan.erp.module.warehouse.controller.dto.StockByTypeDto;
import com.niuan.erp.module.warehouse.entity.Stock;
import com.niuan.erp.module.warehouse.service.StockByTypeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Tag(name = "StockByType")
@ModuleLog("StockByType管理")
@RestController
@RequestMapping("/warehouse/stockbytype")
@RequiredArgsConstructor
public class StockByTypeController {
private final StockByTypeService stockByTypeService;
@Operation(summary = "分页查询StockByType数据", operationId = "getStockByTypePage")
@GetMapping("/getStockByTypePage")
@PreAuthorize("hasAuthority('stockbytype:index')")
public BaseResult<IPage<StockByTypeDto>> getStockByTypePage(@Validated BasePageReqParams pageParams,
@Validated(Get.class) StockByTypeDto searchParams) {
var wrapper = new LambdaQueryWrapper<Stock>();
if (searchParams != null) {
if (StringUtils.hasText(searchParams.partNumber())) {
wrapper.like(Stock::getPartNumber, searchParams.partNumber());
}
}
return BaseResult.successWithData(stockByTypeService.getStockByTypePage(pageParams, wrapper));
}
@ApiLog(type = OperationType.ADD, remark = "新增一条StockByType记录")
@Operation(summary = "新增StockByType", operationId = "addStockByType")
@PostMapping("/addStockByType")
@PreAuthorize("hasAuthority('stockbytype:add')")
public BaseResult<?> addStockByType(@Validated(Add.class) @RequestBody StockByTypeDto dto) {
stockByTypeService.addStockByType(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.UPDATE, remark = "更新一条StockByType记录")
@Operation(summary = "更新StockByType", operationId = "updateStockByType")
@PostMapping("/updateStockByType")
@PreAuthorize("hasAuthority('stockbytype:update')")
public BaseResult<?> updateStockByType(@Validated(Update.class) @RequestBody StockByTypeDto dto) {
stockByTypeService.updateStockByType(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.DELETE, remark = "删除一条StockByType记录")
@Operation(summary = "删除StockByType", operationId = "deleteStockByType")
@PostMapping("/deleteStockByType")
@PreAuthorize("hasAuthority('stockbytype:delete')")
public BaseResult<?> deleteStockByType(@Validated(DeleteOne.class) @RequestBody BaseDeleteBody req) {
stockByTypeService.deleteStockByType(req.id());
return BaseResult.success();
}
@ApiLog(type = OperationType.DELETE, remark = "批量删除StockByType记录")
@Operation(summary = "批量删除StockByType", operationId = "deleteStockByTypeBatch")
@PostMapping("/deleteStockByTypeBatch")
@PreAuthorize("hasAuthority('stockbytype:deleteBatch')")
public BaseResult<?> deleteStockByTypeBatch(@Validated(DeleteBatch.class) @RequestBody BaseDeleteBody req) {
stockByTypeService.deleteBatch(req.ids());
return BaseResult.success();
}
}

View File

@@ -1,82 +0,0 @@
package com.niuan.erp.module.warehouse.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.annotation.ApiLog;
import com.niuan.erp.common.annotation.ModuleLog;
import com.niuan.erp.common.base.BaseDeleteBody;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import com.niuan.erp.common.base.OperationType;
import com.niuan.erp.module.warehouse.controller.dto.StockDto;
import com.niuan.erp.module.warehouse.entity.Stock;
import com.niuan.erp.module.warehouse.service.StockService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Tag(name = "Stock")
@ModuleLog("Stock管理")
@RestController
@RequestMapping("/warehouse/stock")
@RequiredArgsConstructor
public class StockByWarehouseController {
private final StockService stockService;
@Operation(summary = "分页查询Stock数据", operationId = "getStockPage")
@GetMapping("/getStockPage")
@PreAuthorize("hasAuthority('stock:index')")
public BaseResult<IPage<StockDto>> getStockPage(@Validated BasePageReqParams pageParams,
@Validated(Get.class) StockDto searchParams) {
var wrapper = new LambdaQueryWrapper<Stock>();
if (searchParams != null) {
if (StringUtils.hasText(searchParams.partNumber())) {
wrapper.like(Stock::getPartNumber, searchParams.partNumber());
}
}
return BaseResult.successWithData(stockService.getStockPage(pageParams, wrapper));
}
@ApiLog(type = OperationType.ADD, remark = "新增一条Stock记录")
@Operation(summary = "新增Stock", operationId = "addStock")
@PostMapping("/addStock")
@PreAuthorize("hasAuthority('stock:add')")
public BaseResult<?> addStock(@Validated(Add.class) @RequestBody StockDto dto) {
stockService.addStock(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.UPDATE, remark = "更新一条Stock记录")
@Operation(summary = "更新Stock", operationId = "updateStock")
@PostMapping("/updateStock")
@PreAuthorize("hasAuthority('stock:update')")
public BaseResult<?> updateStock(@Validated(Update.class) @RequestBody StockDto dto) {
stockService.updateStock(dto);
return BaseResult.success();
}
@ApiLog(type = OperationType.DELETE, remark = "删除一条Stock记录")
@Operation(summary = "删除Stock", operationId = "deleteStock")
@PostMapping("/deleteStock")
@PreAuthorize("hasAuthority('stock:delete')")
public BaseResult<?> deleteStock(@Validated(DeleteOne.class) @RequestBody BaseDeleteBody req) {
stockService.deleteStock(req.id());
return BaseResult.success();
}
@ApiLog(type = OperationType.DELETE, remark = "批量删除Stock记录")
@Operation(summary = "批量删除Stock", operationId = "deleteStockBatch")
@PostMapping("/deleteStockBatch")
@PreAuthorize("hasAuthority('stock:deleteBatch')")
public BaseResult<?> deleteStockBatch(@Validated(DeleteBatch.class) @RequestBody BaseDeleteBody req) {
stockService.deleteBatch(req.ids());
return BaseResult.success();
}
}

View File

@@ -0,0 +1,32 @@
package com.niuan.erp.module.warehouse.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.annotation.ModuleLog;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import com.niuan.erp.module.warehouse.controller.dto.StockDto;
import com.niuan.erp.module.warehouse.service.StockService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Tag(name = "Stock")
@RestController
@RequestMapping("/warehouse/stock")
@RequiredArgsConstructor
public class StockController {
private final StockService stockService;
@Operation(summary = "分页查询库存数据", operationId = "getStockPage")
@GetMapping("/getStockPage")
@PreAuthorize("hasAuthority('stock_by_type:index')")
public BaseResult<IPage<StockDto>> getStockByTypePage(@Validated BasePageReqParams pageParams,
@Validated(Get.class) StockDto searchParams) {
return BaseResult.successWithData(stockService.getStockPage(pageParams, searchParams));
}
}

View File

@@ -10,6 +10,7 @@ import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import com.niuan.erp.common.base.OperationType;
import com.niuan.erp.module.common.entity.Document;
import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderAddDto;
import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderDto;
import com.niuan.erp.module.warehouse.service.StockTransferOrderService;
import io.swagger.v3.oas.annotations.Operation;
@@ -48,7 +49,7 @@ public class StockTransferOrderController {
@Operation(summary = "新增StockTransferOrder", operationId = "addStockTransferOrder")
@PostMapping("/addStockTransferOrder")
@PreAuthorize("hasAuthority('stocktransferorder:add')")
public BaseResult<?> addStockTransferOrder(@Validated(Add.class) @RequestBody StockTransferOrderDto dto) {
public BaseResult<?> addStockTransferOrder(@Validated(Add.class) @RequestBody StockTransferOrderAddDto dto) {
stockTransferOrderService.addStockTransferOrder(dto);
return BaseResult.success();
}

View File

@@ -4,11 +4,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.annotation.ApiLog;
import com.niuan.erp.common.annotation.ModuleLog;
import com.niuan.erp.common.base.BaseDeleteBody;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.*;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import com.niuan.erp.common.base.OperationType;
import com.niuan.erp.module.warehouse.controller.dto.WarehouseDto;
import com.niuan.erp.module.warehouse.entity.Warehouse;
import com.niuan.erp.module.warehouse.service.WarehouseService;
@@ -20,8 +17,10 @@ import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Tag(name = "Warehouse")
@ModuleLog("Warehouse管理")
import java.util.List;
@Tag(name = "仓库管理")
@ModuleLog("仓库管理")
@RestController
@RequestMapping("/warehouse/warehouse")
@RequiredArgsConstructor
@@ -29,7 +28,14 @@ public class WarehouseController {
private final WarehouseService warehouseService;
@Operation(summary = "分页查询Warehouse数据", operationId = "getWarehousePage")
@Operation(summary = "查询仓库列表", operationId = "getWarehouseSelectList")
@GetMapping("/getWarehouseSelectList")
@PreAuthorize("hasAnyAuthority('stock_by_warehouse:index', 'production_plan:add')")
public BaseResult<List<BaseSelectDto>> getWarehouseSelectList() {
return BaseResult.successWithData(warehouseService.getWarehouseSelectList());
}
@Operation(summary = "分页查询仓库数据", operationId = "getWarehousePage")
@GetMapping("/getWarehousePage")
@PreAuthorize("hasAuthority('warehouse:index')")
public BaseResult<IPage<WarehouseDto>> getWarehousePage(@Validated BasePageReqParams pageParams,
@@ -37,7 +43,7 @@ public class WarehouseController {
var wrapper = new LambdaQueryWrapper<Warehouse>();
if (searchParams != null) {
if (StringUtils.hasText(searchParams.searchCode())) {
wrapper.like(Warehouse::getSearchCode, searchParams.searchCode());
wrapper.like(Warehouse::getStoreNo, searchParams.searchCode());
}
}
return BaseResult.successWithData(warehouseService.getWarehousePage(pageParams, wrapper));

View File

@@ -4,22 +4,22 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.annotation.ApiLog;
import com.niuan.erp.common.annotation.ModuleLog;
import com.niuan.erp.common.base.BaseDeleteBody;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.*;
import com.niuan.erp.common.base.CommonValidateGroup.*;
import com.niuan.erp.common.base.OperationType;
import com.niuan.erp.module.warehouse.controller.dto.WarehouseItemDto;
import com.niuan.erp.module.warehouse.entity.WarehouseItem;
import com.niuan.erp.module.warehouse.service.WarehouseItemService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "WarehouseItem")
@ModuleLog("WarehouseItem管理")
@RestController
@@ -29,6 +29,20 @@ public class WarehouseItemController {
private final WarehouseItemService warehouseItemService;
@Operation(summary = "查询物料规格列表", operationId = "getProductTypeSelectList")
@GetMapping("/getProductTypeSelectList")
@PreAuthorize("hasAuthority('stock_by_type:index')")
public BaseResult<List<BaseSelectDto>> getProductTypeSelectList() {
return BaseResult.successWithData(warehouseItemService.getProductTypeSelectList());
}
@Operation(summary = "查询物料品牌列表", operationId = "getProductBrandSelectList")
@GetMapping("/getProductBrandSelectList")
@PreAuthorize("hasAuthority('stock_by_brand:index')")
public BaseResult<List<BaseSelectDto>> getProductBrandSelectList() {
return BaseResult.successWithData(warehouseItemService.getProductBrandSelectList());
}
@Operation(summary = "分页查询WarehouseItem数据", operationId = "getWarehouseItemPage")
@GetMapping("/getWarehouseItemPage")
@PreAuthorize("hasAuthority('warehouseitem:index')")
@@ -37,7 +51,7 @@ public class WarehouseItemController {
var wrapper = new LambdaQueryWrapper<WarehouseItem>();
if (searchParams != null) {
if (StringUtils.hasText(searchParams.searchCode())) {
wrapper.like(WarehouseItem::getSearchCode, searchParams.searchCode());
wrapper.like(WarehouseItem::getPartNumber, searchParams.searchCode());
}
}
return BaseResult.successWithData(warehouseItemService.getWarehouseItemPage(pageParams, wrapper));
@@ -79,4 +93,13 @@ public class WarehouseItemController {
warehouseItemService.deleteBatch(req.ids());
return BaseResult.success();
}
@Operation(summary = "判断 partNumber 的物料是否存在仓库", operationId = "existsWarehouseItem")
@GetMapping("/existsWarehouseItem")
@PreAuthorize("hasAnyAuthority('bom:add')")
public BaseResult<Boolean> existsWarehouseItem(@Validated
@NotNull(message = "warehouse.warehouse_item.part_number.not_null")
@RequestParam("partNumber") String partNumber) {
return BaseResult.successWithData(warehouseItemService.existsWarehouseItemByPartNumber(partNumber));
}
}

View File

@@ -1,21 +1,17 @@
package com.niuan.erp.module.warehouse.controller.dto;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public record StockDto(
Long id,
Integer status,
LocalDateTime createDate,
Long createUserId,
String createUserName,
LocalDateTime updateDate,
Long updateUserId,
String updateUserName,
Integer storeNo,
String storeName,
String partNumber,
Integer productCount,
String storageMark,
Integer reserve1,
String reserve2,
Integer productOccupyTotal) {}
String storeName,
String productType,
String partNumber,
String productSpecs,
Integer productPacking,
String productBrand,
String productPackSize,
Integer productCount,
Integer storeId,
String searchCode) {
}

View File

@@ -0,0 +1,39 @@
package com.niuan.erp.module.warehouse.controller.dto;
import jakarta.validation.constraints.NotNull;
import java.util.List;
/**
* 添加调拨单的 Dto
* @param formCode
* @param formName
* @param formMark
* @param storeNo 入库仓库 ID
* @param storeName 入库仓库名称
* @param outStoreNo 出库仓库 ID
* @param outStoreName 出库仓库名称
* @param transferOrderItems
*/
public record StockTransferOrderAddDto(
@NotNull(message = "warehouse.stock_transfer_order.validate.form_code.not_null")
String formCode,
@NotNull(message = "warehouse.stock_transfer_order.validate.form_name.not_null")
String formName,
String formMark,
// 入库
@NotNull(message = "warehouse.stock_transfer_order.validate.store_no.not_null")
Integer storeNo,
@NotNull(message = "warehouse.stock_transfer_order.validate.store_name.not_null")
String storeName,
// 出库
@NotNull(message = "warehouse.stock_transfer_order.validate.out_store_no.not_null")
Integer outStoreNo,
@NotNull(message = "warehouse.stock_transfer_order.validate.out_store_name.not_null")
String outStoreName,
@NotNull(message = "warehouse.stock_transfer_order.validate.transfer_order_items.not_null")
List<StockTransferOrderItemAddDto> transferOrderItems
) {}

View File

@@ -0,0 +1,23 @@
package com.niuan.erp.module.warehouse.controller.dto;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
/**
* 调拨明细 Dto
* @param partNumber
* @param productSpec
* @param productCount 调拨数量
* @param partId product ID
*/
public record StockTransferOrderItemAddDto(
@NotNull(message = "warehouse.stock_transfer_order.validate.part_number.not_null")
String partNumber,
@NotNull(message = "warehouse.stock_transfer_order.validate.product_spec.not_null")
String productSpec,
@NotNull(message = "warehouse.stock_transfer_order.validate.product_count.not_null")
@Min(value = 1, message = "warehouse.stock_transfer_order.validate.product_count.min")
Integer productCount,
@NotNull(message = "warehouse.stock_transfer_order.validate.part_id.not_null")
Long partId
) {}

View File

@@ -17,4 +17,5 @@ public record WarehouseDto(
Integer reserve1,
String reserve2,
Long projectId,
Integer customerId) {}
Integer customerId,
String searchCode) {}

View File

@@ -29,4 +29,5 @@ public record WarehouseItemDto(
Integer reserve1,
String reserve2,
Integer productOccupyTotal,
Integer customerId) {}
Integer customerId,
String searchCode) {}

View File

@@ -1,7 +1,11 @@
package com.niuan.erp.module.warehouse.converter;
import com.niuan.erp.module.common.entity.Document;
import com.niuan.erp.module.common.entity.DocumentMaterial;
import com.niuan.erp.module.common.mapper.DocumentMapper;
import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderAddDto;
import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderDto;
import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderItemAddDto;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
@@ -10,6 +14,10 @@ import java.util.List;
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface StockTransferOrderConverter {
Document toEntity(StockTransferOrderDto dto);
Document toEntity(StockTransferOrderAddDto dto);
StockTransferOrderDto toDto(Document entity);
List<StockTransferOrderDto> toDtoList(List<Document> entities);
DocumentMaterial toEntity(StockTransferOrderItemAddDto dto);
List<DocumentMaterial> toEntityList(List<StockTransferOrderItemAddDto> dtoList);
}

View File

@@ -1,7 +1,14 @@
package com.niuan.erp.module.warehouse.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.module.warehouse.controller.dto.StockDto;
import com.niuan.erp.module.warehouse.entity.Stock;
import org.apache.ibatis.annotations.Arg;
import org.apache.ibatis.annotations.ConstructorArgs;
import org.apache.ibatis.type.JdbcType;
/**
* <p>
@@ -13,4 +20,6 @@ import com.niuan.erp.module.warehouse.entity.Stock;
*/
public interface StockMapper extends BaseMapper<Stock> {
IPage<StockDto> selectPageByParams(Page<?> t, StockDto searchParams, Long userId);
}

View File

@@ -2,6 +2,10 @@ package com.niuan.erp.module.warehouse.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.niuan.erp.module.warehouse.entity.WarehouseItem;
import org.apache.ibatis.annotations.MapKey;
import java.util.List;
import java.util.Map;
/**
* <p>
@@ -13,4 +17,11 @@ import com.niuan.erp.module.warehouse.entity.WarehouseItem;
*/
public interface WarehouseItemMapper extends BaseMapper<WarehouseItem> {
List<String> getProductTypeSelectList();
List<String> getProductBrandSelectList();
@MapKey("partNumber")
Map<String, Map<String, Object>> getWarehouseItemStockListByPartNumbers(List<String> partNumbers);
}

View File

@@ -1,8 +1,11 @@
package com.niuan.erp.module.warehouse.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.niuan.erp.common.base.BaseSelectDto;
import com.niuan.erp.module.warehouse.entity.Warehouse;
import java.util.List;
/**
* <p>
* Mapper 接口
@@ -13,4 +16,6 @@ import com.niuan.erp.module.warehouse.entity.Warehouse;
*/
public interface WarehouseMapper extends BaseMapper<Warehouse> {
List<BaseSelectDto> getWarehouseSelectList();
}

View File

@@ -10,14 +10,6 @@ import java.util.List;
public interface StockService {
IPage<StockDto> getStockPage(BasePageReqParams pageParams, LambdaQueryWrapper<Stock> wrapper);
void addStock(StockDto dto);
void updateStock(StockDto dto);
void deleteStock(long id);
void deleteBatch(List<Long> ids);
IPage<StockDto> getStockPage(BasePageReqParams pageParams, StockDto searchParams);
}

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.module.common.entity.Document;
import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderAddDto;
import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderDto;
import java.util.List;
@@ -12,7 +13,7 @@ public interface StockTransferOrderService {
IPage<StockTransferOrderDto> getStockTransferOrderPage(BasePageReqParams pageParams, LambdaQueryWrapper<Document> wrapper);
void addStockTransferOrder(StockTransferOrderDto dto);
void addStockTransferOrder(StockTransferOrderAddDto dto);
void updateStockTransferOrder(StockTransferOrderDto dto);

View File

@@ -3,6 +3,8 @@ package com.niuan.erp.module.warehouse.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseSelectDto;
import com.niuan.erp.common.base.BaseTree;
import com.niuan.erp.module.warehouse.controller.dto.WarehouseItemDto;
import com.niuan.erp.module.warehouse.entity.WarehouseItem;
@@ -10,6 +12,10 @@ import java.util.List;
public interface WarehouseItemService {
List<BaseSelectDto> getProductTypeSelectList();
List<BaseSelectDto> getProductBrandSelectList();
IPage<WarehouseItemDto> getWarehouseItemPage(BasePageReqParams pageParams, LambdaQueryWrapper<WarehouseItem> wrapper);
void addWarehouseItem(WarehouseItemDto dto);
@@ -20,4 +26,6 @@ public interface WarehouseItemService {
void deleteBatch(List<Long> ids);
boolean existsWarehouseItemByPartNumber(String partNumber);
}

View File

@@ -3,6 +3,8 @@ package com.niuan.erp.module.warehouse.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseSelectDto;
import com.niuan.erp.common.base.BaseTree;
import com.niuan.erp.module.warehouse.controller.dto.WarehouseDto;
import com.niuan.erp.module.warehouse.entity.Warehouse;
@@ -10,6 +12,8 @@ import java.util.List;
public interface WarehouseService {
List<BaseSelectDto> getWarehouseSelectList();
IPage<WarehouseDto> getWarehousePage(BasePageReqParams pageParams, LambdaQueryWrapper<Warehouse> wrapper);
void addWarehouse(WarehouseDto dto);

View File

@@ -28,38 +28,9 @@ public class StockServiceImpl extends ServiceImpl<StockMapper, Stock> implements
private final StockConverter stockConverter;
@Override
public IPage<StockDto> getStockPage(BasePageReqParams pageParams, LambdaQueryWrapper<Stock> wrapper) {
IPage<Stock> result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper);
return result.convert(stockConverter::toDto);
}
@Override
public void addStock(StockDto dto) {
Stock entity = stockConverter.toEntity(dto);
entity.setCreateUserId(SecurityUtils.getUserId());
entity.setCreateUserName(SecurityUtils.getUserName());
entity.setCreateDate(LocalDateTime.now());
entity.setStatus(0);
this.baseMapper.insert(entity);
}
@Override
public void updateStock(StockDto dto) {
Stock entity = stockConverter.toEntity(dto);
entity.setUpdateUserId(SecurityUtils.getUserId());
entity.setUpdateUserName(SecurityUtils.getUserName());
entity.setUpdateDate(LocalDateTime.now());
this.baseMapper.updateById(entity);
}
@Override
public void deleteStock(long id) {
this.baseMapper.deleteById(id);
}
@Override
public void deleteBatch(List<Long> ids) {
this.baseMapper.deleteByIds(ids);
public IPage<StockDto> getStockPage(BasePageReqParams pageParams, StockDto searchParams) {
return this.baseMapper.selectPageByParams(new Page<>(pageParams.page(), pageParams.pageSize()),
searchParams, SecurityUtils.getUserId());
}
}

View File

@@ -7,9 +7,16 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.utils.SecurityUtils;
import com.niuan.erp.module.common.entity.Document;
import com.niuan.erp.module.common.entity.DocumentMaterial;
import com.niuan.erp.module.common.enums.DocumentType;
import com.niuan.erp.module.common.mapper.DocumentMapper;
import com.niuan.erp.module.common.mapper.DocumentMaterialMapper;
import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderAddDto;
import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderDto;
import com.niuan.erp.module.warehouse.controller.dto.StockTransferOrderItemAddDto;
import com.niuan.erp.module.warehouse.converter.StockTransferOrderConverter;
import com.niuan.erp.module.warehouse.entity.WarehouseItem;
import com.niuan.erp.module.warehouse.mapper.WarehouseItemMapper;
import com.niuan.erp.module.warehouse.service.StockTransferOrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -17,6 +24,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@Service
@@ -27,6 +35,10 @@ public class StockTransferOrderServiceImpl extends ServiceImpl<DocumentMapper, D
private final StockTransferOrderConverter stockTransferOrderConverter;
private final WarehouseItemMapper warehouseItemMapper;
private final DocumentMaterialMapper documentMaterialMapper;
@Override
public IPage<StockTransferOrderDto> getStockTransferOrderPage(BasePageReqParams pageParams, LambdaQueryWrapper<Document> wrapper) {
IPage<Document> result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper);
@@ -34,13 +46,34 @@ public class StockTransferOrderServiceImpl extends ServiceImpl<DocumentMapper, D
}
@Override
public void addStockTransferOrder(StockTransferOrderDto dto) {
public void addStockTransferOrder(StockTransferOrderAddDto dto) {
Document entity = stockTransferOrderConverter.toEntity(dto);
entity.setCreateUserId(SecurityUtils.getUserId());
entity.setCreateUserName(SecurityUtils.getUserName());
entity.setCreateDate(LocalDateTime.now());
entity.setStatus(0);
entity.setCustomerId(SecurityUtils.getCustomerId());
entity.setFormType(DocumentType.STOCK_TRANSFER_ORDER);
this.baseMapper.insert(entity);
List<DocumentMaterial> materials = stockTransferOrderConverter.toEntityList(dto.transferOrderItems());
Map<String, Map<String, Object>> warehouseItems =
warehouseItemMapper.getWarehouseItemStockListByPartNumbers(materials.stream()
.map(DocumentMaterial::getPartNumber)
.toList());
materials.forEach(m -> {
m.setDocumentNo(entity.getId().intValue());
m.setCreateUserId(SecurityUtils.getUserId());
m.setCreateUserName(SecurityUtils.getUserName());
m.setCreateDate(LocalDateTime.now());
m.setStatus(0);
m.setDemandCount(((Long) warehouseItems.get(m.getPartNumber()).get("productCount")).intValue());
});
documentMaterialMapper.insert(materials);
}
@Override

View File

@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseSelectDto;
import com.niuan.erp.common.base.BaseTree;
import com.niuan.erp.common.utils.SecurityUtils;
import com.niuan.erp.module.warehouse.controller.dto.WarehouseItemDto;
import com.niuan.erp.module.warehouse.converter.WarehouseItemConverter;
@@ -27,6 +29,20 @@ public class WarehouseItemServiceImpl extends ServiceImpl<WarehouseItemMapper, W
private final WarehouseItemConverter warehouseItemConverter;
@Override
public List<BaseSelectDto> getProductTypeSelectList() {
return this.baseMapper.getProductTypeSelectList().stream()
.map(s -> new BaseSelectDto(s, s))
.toList();
}
@Override
public List<BaseSelectDto> getProductBrandSelectList() {
return this.baseMapper.getProductBrandSelectList().stream()
.map(s -> new BaseSelectDto(s, s))
.toList();
}
@Override
public IPage<WarehouseItemDto> getWarehouseItemPage(BasePageReqParams pageParams, LambdaQueryWrapper<WarehouseItem> wrapper) {
IPage<WarehouseItem> result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper);
@@ -62,4 +78,10 @@ public class WarehouseItemServiceImpl extends ServiceImpl<WarehouseItemMapper, W
this.baseMapper.deleteByIds(ids);
}
@Override
public boolean existsWarehouseItemByPartNumber(String partNumber) {
var wrapper = new LambdaQueryWrapper<WarehouseItem>().eq(WarehouseItem::getPartNumber, partNumber);
return this.baseMapper.selectCount(wrapper) > 0;
}
}

View File

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.BaseSelectDto;
import com.niuan.erp.common.utils.SecurityUtils;
import com.niuan.erp.module.warehouse.controller.dto.WarehouseDto;
import com.niuan.erp.module.warehouse.converter.WarehouseConverter;
@@ -27,6 +28,11 @@ public class WarehouseServiceImpl extends ServiceImpl<WarehouseMapper, Warehouse
private final WarehouseConverter warehouseConverter;
@Override
public List<BaseSelectDto> getWarehouseSelectList() {
return this.baseMapper.getWarehouseSelectList();
}
@Override
public IPage<WarehouseDto> getWarehousePage(BasePageReqParams pageParams, LambdaQueryWrapper<Warehouse> wrapper) {
IPage<Warehouse> result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper);

View File

@@ -12,6 +12,12 @@ springdoc:
api-docs:
path: /v3/api-docs
group-configs:
- group: 'default'
- group: '权限控制'
paths-to-match: '/**'
packages-to-scan: com.niuan.erp.module.sys.controller
packages-to-scan: com.niuan.erp.module.auth.controller
- group: '系统设置'
paths-to-match: '/**'
packages-to-scan: com.niuan.erp.module.sys.controller
- group: '生产管理'
paths-to-match: '/**'
packages-to-scan: com.niuan.erp.module.production.controller

View File

@@ -13,7 +13,7 @@ spring:
# mybatis 设置
mybatis-plus:
type-aliases-package: com.niuan.erp.module.*.entity
type-aliases-package: com.niuan.erp.module.*.entity,com.niuan.erp.module.*.controller.dto,com.niuan.erp.common.base
configuration:
map-underscore-to-camel-case: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

View File

@@ -12,8 +12,68 @@ validation.common.pageParams.pageSize.notNull=页数不能为空
validation.common.pageParams.page.min=页数不能小于0
validation.common.pageParams.pageSize.min=页数不能小于0
warehouse.warehouse_item.part_number.not_null=编号不能为空
# ==========>> 仓库管理
warehouse.stock_transfer_order.validate.form_code.not_null=调拨单编号不能为空
warehouse.stock_transfer_order.validate.form_name.not_null=调拨单名称不能为空
warehouse.stock_transfer_order.validate.store_no.not_null=入库仓库 ID 不能为空
warehouse.stock_transfer_order.validate.store_name.not_null=入库仓库名称不能为空
warehouse.stock_transfer_order.validate.out_store_no.not_null=出库仓库 ID 不能为空
warehouse.stock_transfer_order.validate.out_store_name.not_null=出库仓库名称不能为空
warehouse.stock_transfer_order.validate.transfer_order_items.not_null=调拨单明细不能为空
warehouse.stock_transfer_order.validate.part_number.not_null=物料编号不能为空
warehouse.stock_transfer_order.validate.product_spec.not_null=物料型号不能为空
warehouse.stock_transfer_order.validate.product_count.not_null=调拨数量不能为空
warehouse.stock_transfer_order.validate.product_count.min=调拨数量不能小于 1
warehouse.stock_transfer_order.validate.part_id.not_null=物料 ID 不能为空
# ==========>> 生产管理
production.bom.validate.bom_id.not_null=BOM Id 不能为空
production.bom.validate.bom_no.not_null=BOM 编号不能为空
production.bom.validate.bom_name.not_null=BOM 名称不能为空
production.bom.validate.manufacturer.not_null=厂家 / 型号不能为空
production.bom.validate.spec.not_null=封装规格不能为空
production.bom.validate.brand_name.not_null=品牌不能为空
production.bom.validate.part_number.not_null=物料编号不能为空
production.bom.validate.manufacture_count.not_null=用量不能为空
production.bom.validate.manufacture_count.min=用量最小为 1
production.bom.validate.item_position.not_null=位号不能为空
production.bom.exception.duplicate_bom_name=BOM 名字重复
production.bom.exception.duplicate_bom_item=BOM 明细重复
production.bom.exception.unpair_position_count=BOM 明细中存在位点和数量不一致
production.bom.exception.unexists_bom_item=BOM 物料有不存在的物料
production.production_plan.validate.ids.not_null=生产计划 ID 不能为空
production.production_plan.validate.issue.not_null=发料单数据不能为空
production.production_plan.validate.form_code.not_null=发料单编号不能为空
production.production_plan.validate.store_no.not_null=发料仓库 ID 不能为空
production.production_plan.validate.store_name.not_null=发料仓库名称不能为空
production.production_plan.validate.items.not_null=发料单明细不能为空
production.production_plan.validate.part_number.not_null=物料编号不能为空
production.production_plan.validate.product_count.not_null=实发数量不能为空
production.production_plan.validate.product_count.min=实发数量不能小于 1
production.production_plan.validate.demand_count.not_null=需求数量不能为空
production.production_plan.validate.demand_count.min=需求数量不能小于 1
production.production_plan.exception.must_no_complete=选中的行其中有不是未完成的状态
production.production_plan.exception.more_than_one_warehouse=选中的行不能有多个仓库
sys.operationType.codeNotExists=编号不存在
# ==========>> 采购管理
purchase.purchase_plan.validate.plan_no.not_null=采购计划编号不能为空
purchase.purchase_plan.validate.store_no.not_null=收货仓库 ID 不能为空
purchase.purchase_plan.validate.store_name.not_null=收货仓库名称不能为空
purchase.purchase_plan.validate.plan_name.not_null=采购计划名称不能为空
purchase.purchase_plan.validate.part_number.not_null=物料编号不能为空
purchase.purchase_plan.validate.part_id.not_null=物料 ID 不能为空
purchase.purchase_plan.validate.purchase_count.not_null=购买数量不能为空
purchase.purchase_plan.validate.purchase_count.min=购买数量不能小于 0
# ==========> 类型
loginName.notNull=登录名称不能为空

View File

@@ -21,4 +21,22 @@
<result column="reserve2" property="reserve2" />
</resultMap>
<select id="getBomItemListByBomId" parameterType="Long" resultType="com.niuan.erp.module.production.controller.dto.BomItemDto">
SELECT b.PartNumber, p.ProductType, p.ProductSpecs, p.ProductPacksize, p.ProductBrand,
b.ManufactureCount, b.ItemPosition, b.SameUseCount, b.ProductMark
FROM bom b
INNER JOIN product p ON b.PartNumber = p.PartNumber
WHERE b.BomId = ${bomId}
</select>
<select id="getBomItemListByBomIdAndPartNumber" parameterType="Long" resultType="com.niuan.erp.module.production.controller.dto.BomItemDto">
SELECT b.PartNumber, p.ProductType, p.ProductSpecs, p.ProductPacksize, p.ProductBrand,
b.ManufactureCount, b.ItemPosition, b.SameUseCount, b.ProductMark
FROM bom b
INNER JOIN product p ON b.PartNumber = p.PartNumber
<where>
b.BomId = #{bomId} AND b.PartNumber Like CONCAT('%', #{partNumber}, '%')
</where>
</select>
</mapper>

View File

@@ -2,25 +2,25 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.niuan.erp.module.production.mapper.BomMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.niuan.erp.module.production.entity.Bom">
<id column="Id" property="id" />
<result column="Status" property="status" />
<result column="CreateDate" property="createDate" />
<result column="CreateUserId" property="createUserId" />
<result column="CreateUserName" property="createUserName" />
<result column="UpdateDate" property="updateDate" />
<result column="UpdateUserId" property="updateUserId" />
<result column="UpdateUserName" property="updateUserName" />
<result column="ParentId" property="parentId" />
<result column="BomNo" property="bomNo" />
<result column="Manufacturer" property="manufacturer" />
<result column="BomName" property="bomName" />
<result column="Spec" property="spec" />
<result column="BrandName" property="brandName" />
<result column="FormMark" property="formMark" />
<result column="customerName" property="customerName" />
<result column="CustomerId" property="customerId" />
</resultMap>
<select id="selectPageByPartNumber" resultType="com.niuan.erp.module.production.entity.Bom">
SELECT DISTINCT b.*
FROM bom_list b
INNER JOIN bom i ON i.BomId = b.Id
INNER JOIN product p ON i.PartNumber = p.PartNumber
<where>
<if test="searchCode != null and searchCode != ''">
AND (b.BomNo LIKE CONCAT('%', #{searchCode}, '%')
OR b.BomName LIKE CONCAT('%', #{searchCode}, '%'))
</if>
<if test="partNumber != null and searchCode != ''">
AND i.PartNumber LIKE CONCAT('%', #{partNumber}, '%')
</if>
</where>
ORDER BY b.CreateDate DESC
</select>
<select id="getBomSelectList" resultType="BaseSelectDto">
SELECT Id, BomName FROM bom_list
</select>
</mapper>

View File

@@ -29,4 +29,83 @@
<result column="CustomerId" property="customerId" />
</resultMap>
<select id="getProductionPlanRequiredQtyList" resultType="ProductionPlanShortageDto">
SELECT b.Id AS id, b.PartNumber AS partNumber, MAX(pro.ProductSpecs) AS productSpecs,
SUM(p.ProductionCount * b.ManufactureCount) AS requiredQty, COALESCE(MAX(s.ProductCount), 0) AS stockQty,
NULL AS diffQty
FROM produceorder p
INNER JOIN bom b ON p.ProjectId = b.BomId
INNER JOIN product pro ON b.PartNumber = pro.PartNumber
LEFT JOIN storagecount s ON s.PartNumber = pro.PartNumber
<if test="warehouseId != null">
AND s.StoreNo = #{warehouseId}
</if>
<where>
p.Id IN
<foreach item="id" collection="ids" open="(" separator="," close=")">
#{id}
</foreach>
</where>
GROUP BY b.Id, b.PartNumber, pro.ProductSpecs
</select>
<select id="selectProduceOrderData" resultType="ProduceOrderList">
SELECT
d.Id,
d.PartNumber AS Partnumber,
d.ProductSpecs AS Productspecs,
a.StoreNo,
b.SameUseCount,
b.SameUseNum1 AS SameNum1,
b.SameUseNum2 AS SameNum2,
b.SameUseNum3 AS SameNum3,
b.ManufactureCount AS BomTotal,
a.ProductionCount AS OrderTotal,
<!-- 1. 主料库存 -->
COALESCE(f_main.ProductCount, 0) AS MainStock,
<!-- 2. 替换料1库存 (根据 SameNum1 关联) -->
COALESCE(f_sub1.ProductCount, 0) AS Sub1Stock,
<!-- 3. 替换料2库存 (根据 SameNum2 关联) -->
COALESCE(f_sub2.ProductCount, 0) AS Sub2Stock,
<!-- 4. 替换料3库存 (根据 SameNum3 关联) -->
COALESCE(f_sub3.ProductCount, 0) AS Sub3Stock,
<!-- 占用数量 (示例设为0实际请根据表结构补充) -->
0 AS OccupyTotal
FROM produceorder a
INNER JOIN bom b ON a.ProjectId = b.BomId
INNER JOIN product d ON b.PartNumber = d.PartNumber AND d.CustomerId = a.CustomerId
<!-- 关联主料库存 -->
LEFT JOIN storagecount f_main
ON a.StoreNo = f_main.StoreNo AND b.PartNumber = f_main.PartNumber
<!-- 关联替换料1库存 -->
LEFT JOIN storagecount f_sub1
ON a.StoreNo = f_sub1.StoreNo AND b.SameUseNum1 = f_sub1.PartNumber
<!-- 关联替换料2库存 -->
LEFT JOIN storagecount f_sub2
ON a.StoreNo = f_sub2.StoreNo AND b.SameUseNum2 = f_sub2.PartNumber
<!-- 关联替换料3库存 -->
LEFT JOIN storagecount f_sub3
ON a.StoreNo = f_sub3.StoreNo AND b.SameUseNum3 = f_sub3.PartNumber
<where>
a.Id IN
<foreach item="itemId" collection="ids" open="(" separator="," close=")">
#{itemId}
</foreach>
</where>
</select>
</mapper>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.niuan.erp.module.sys.mapper.RolePermissionMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.niuan.erp.module.sys.entity.RolePermission">
<id column="role_id" property="roleId" />
<id column="permission_id" property="permissionId" />
</resultMap>
</mapper>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.niuan.erp.module.sys.mapper.SysPermissionMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.niuan.erp.module.sys.entity.SysPermission">
<id column="id" property="id" />
<result column="parent_id" property="parentId" />
<result column="status" property="status" />
<result column="create_date" property="createDate" />
<result column="create_user_id" property="createUserId" />
<result column="create_user_name" property="createUserName" />
<result column="update_date" property="updateDate" />
<result column="update_user_id" property="updateUserId" />
<result column="update_user_name" property="updateUserName" />
<result column="permission_name" property="permissionName" />
<result column="permission_i18n" property="permissionI18n" />
<result column="permission_type" property="permissionType" />
<result column="page_link" property="pageLink" />
<result column="view_link" property="viewLink" />
<result column="permission_code" property="permissionCode" />
<result column="event_name" property="eventName" />
<result column="class_name" property="className" />
<result column="icon_name" property="iconName" />
<result column="sort" property="sort" />
<result column="hidden" property="hidden" />
</resultMap>
<select id="selectByUserId" parameterType="Long" resultMap="BaseResultMap">
SELECT p.* FROM sys_permission p
LEFT JOIN role_permission rp ON rp.permission_id = p.id
LEFT JOIN yy_sysrole r ON r.Id = rp.role_id
LEFT JOIN yy_usersrolemapping ur ON ur.RoleId = r.Id
WHERE ur.UserId = #{userId} AND r.status = 1 AND p.status = 0
</select>
</mapper>

View File

@@ -22,4 +22,30 @@
<result column="ProductOccupyTotal" property="productOccupyTotal" />
</resultMap>
<select id="selectPageByParams" resultType="com.niuan.erp.module.warehouse.controller.dto.StockDto">
SELECT s.StoreName as storeName, p.ProductType as productType, p.PartNumber as partNumber,
p.ProductSpecs as productSpecs, p.ProductPacking as productPacking, p.ProductBrand as productBrand,
p.ProductPackSize as productPackSize, c.ProductCount as productCount, null as storeId, null as searchCode
FROM product p
INNER JOIN storagecount c ON p.PartNumber = c.PartNumber
INNER JOIN storage_list s ON s.Id = c.StoreNo
<where>
<if test="searchParams != null">
<if test="searchParams.productType != null and searchParams.productType != ''">
AND p.ProductType = #{searchParams.productType}
</if>
<if test="searchParams.productBrand != null and searchParams.productBrand != ''">
AND p.ProductBrand = #{searchParams.productBrand}
</if>
<if test="searchParams.storeId != null">
AND s.Id = #{searchParams.storeId}
</if>
<if test="searchParams.searchCode != null and searchParams.searchCode != ''">
AND (p.PartNumber LIKE CONCAT("%", #{searchParams.searchCode}, "%")
OR p.ProductSpecs LIKE CONCAT("%", #{searchParams.searchCode}, "%"))
</if>
</if>
</where>
</select>
</mapper>

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.niuan.erp.module.warehouse.mapper.StockTransferOrderMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.niuan.erp.module.warehouse.entity.StockTransferOrder">
<id column="Id" property="id" />
<result column="Status" property="status" />
<result column="CreateDate" property="createDate" />
<result column="CreateUserId" property="createUserId" />
<result column="CreateUserName" property="createUserName" />
<result column="UpdateDate" property="updateDate" />
<result column="UpdateUserId" property="updateUserId" />
<result column="UpdateUserName" property="updateUserName" />
<result column="StoreNo" property="storeNo" />
<result column="StoreName" property="storeName" />
<result column="FormType" property="formType" />
<result column="FormCode" property="formCode" />
<result column="FormName" property="formName" />
<result column="FormStatus" property="formStatus" />
<result column="FormMark" property="formMark" />
<result column="reserve1" property="reserve1" />
<result column="reserve2" property="reserve2" />
<result column="VendorNo" property="vendorNo" />
<result column="VendorName" property="vendorName" />
<result column="TotalValue" property="totalValue" />
<result column="OutStoreNo" property="outStoreNo" />
<result column="OutStoreName" property="outStoreName" />
<result column="GroupId" property="groupId" />
<result column="CustomerId" property="customerId" />
</resultMap>
</mapper>

View File

@@ -32,5 +32,25 @@
<result column="ProductOccupyTotal" property="productOccupyTotal" />
<result column="CustomerId" property="customerId" />
</resultMap>
<select id="getProductTypeSelectList" resultType="java.lang.String">
SELECT DISTINCT ProductType FROM product
</select>
<select id="getProductBrandSelectList" resultType="java.lang.String">
SELECT DISTINCT ProductBrand FROM product
</select>
<select id="getWarehouseItemStockListByPartNumbers" resultType="java.util.Map">
SELECT p.PartNumber AS partNumber, COALESCE(s.ProductCount, 0) AS productCount
FROM product p
LEFT JOIN storagecount s ON p.PartNumber = s.PartNumber
<where>
p.PartNumber IN
<foreach collection="partNumbers" item="partNumber" open="(" separator=", " close=")">
#{partNumber}
</foreach>
</where>
</select>
</mapper>

View File

@@ -21,4 +21,8 @@
<result column="CustomerId" property="customerId" />
</resultMap>
<select id="getWarehouseSelectList" resultType="com.niuan.erp.common.base.BaseSelectDto">
SELECT Id, StoreName FROM storage_list
</select>
</mapper>

View File

@@ -0,0 +1,15 @@
INSERT INTO sys_permission (
id, parent_id, permission_name, permission_i18n, permission_type, page_link,
view_link, permission_code, event_name, class_name, icon_name, sort
) SELECT
c.Id, c.ParentId, c.ChannelName, c.EventName,
CASE
WHEN c.IsMenuShow = 1 THEN 0
WHEN c.IsMenuShow = 0 and (c.EventName = 'add' or c.EventName = 'import') THEN 1
WHEN c.IsMenuShow = 0 and (c.EventName = 'enable' or c.EventName = 'disable') THEN 3
ELSE 2
END,
c.EventName, c.ChannelLink, c.EventName, c.EventName,
NULL, NULL, c.Sort
FROM yy_syschannel c;

View File

@@ -0,0 +1,37 @@
CREATE TABLE IF NOT EXISTS sys_permission (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
parent_id BIGINT NOT NULL DEFAULT 0 COMMENT '父权限ID0表示根节点',
status INT NOT NULL DEFAULT 0 COMMENT '状态0-禁用1-启用',
hidden BOOL NOT NULL DEFAULT FALSE COMMENT '是否隐藏',
create_date DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
create_user_id BIGINT NULL COMMENT '创建人ID',
create_user_name VARCHAR(50) NULL COMMENT '创建人姓名',
update_date DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
update_user_id BIGINT NULL COMMENT '更新人ID',
update_user_name VARCHAR(50) NULL COMMENT '更新人姓名',
permission_name VARCHAR(100) NOT NULL COMMENT '权限名字,没有 i18n 时,作为显示名称',
permission_i18n VARCHAR(100) DEFAULT NULL COMMENT '权限 i18n 键,用于前端多语言取值',
permission_type TINYINT NOT NULL COMMENT '权限类型关系到权限的位置0-菜单1-Table 上方按钮2-Table 操作栏按钮3-状态栏按钮',
page_link VARCHAR(100) DEFAULT NULL COMMENT '前端页面路由地址',
view_link VARCHAR(100) DEFAULT NULL COMMENT '前端 Vue 组件路径',
permission_code VARCHAR(50) DEFAULT NULL COMMENT '后端鉴权用的权限编码',
event_name VARCHAR(50) DEFAULT NULL COMMENT '前端按钮绑定的方法名',
class_name VARCHAR(30) DEFAULT NULL COMMENT '前端样式类名',
icon_name VARCHAR(30) DEFAULT NULL COMMENT '前端图标名称',
sort INT NOT NULL DEFAULT 0 COMMENT '排序值,越小越靠前'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统权限表';
CREATE TABLE IF NOT EXISTS role_permission (
role_id BIGINT NOT NULL COMMENT '角色ID',
permission_id BIGINT NOT NULL COMMENT '权限ID',
-- 联合主键:确保 (role_id, permission_id) 唯一,避免重复授权
PRIMARY KEY (role_id, permission_id),
-- 外键约束(可选但推荐):确保引用的角色和权限真实存在
CONSTRAINT fk_role_permission_role
FOREIGN KEY (role_id) REFERENCES yy_sysrole(Id) ON DELETE CASCADE,
CONSTRAINT fk_role_permission_permission
FOREIGN KEY (permission_id) REFERENCES sys_permission(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色-权限关联表,用的是原有框架的 yy_sysrole';