完成成品出货单。
This commit is contained in:
@@ -4,24 +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.BaseApproveAndRejectDto;
|
||||
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.common.entity.Document;
|
||||
import com.niuan.erp.module.production.controller.dto.DeviceShipmentDto;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentAddDto;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentDto;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentItemDto;
|
||||
import com.niuan.erp.module.production.service.FinishedProductShipmentService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
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.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -65,54 +64,35 @@ public class FinishedProductShipmentController {
|
||||
@ApiLog(type = OperationType.DELETE, remark = "删除一条FinishedProductShipment记录")
|
||||
@Operation(summary = "删除FinishedProductShipment", operationId = "deleteFinishedProductShipment")
|
||||
@PostMapping("/deleteFinishedProductShipment")
|
||||
@PreAuthorize("hasAuthority('finished_product_shipment:delete')")
|
||||
@PreAuthorize("hasAuthority('finished_product_shipment:remove')")
|
||||
public BaseResult<?> deleteFinishedProductShipment(@Validated(DeleteOne.class) @RequestBody BaseDeleteBody req) {
|
||||
finishedProductShipmentService.deleteFinishedProductShipment(req.id());
|
||||
return BaseResult.success();
|
||||
}
|
||||
|
||||
@ApiLog(type = OperationType.DELETE, remark = "批量删除FinishedProductShipment记录")
|
||||
@Operation(summary = "批量删除FinishedProductShipment", operationId = "deleteFinishedProductShipmentBatch")
|
||||
@PostMapping("/deleteFinishedProductShipmentBatch")
|
||||
@PreAuthorize("hasAuthority('finished_product_shipment:deleteBatch')")
|
||||
public BaseResult<?> deleteFinishedProductShipmentBatch(@Validated(DeleteBatch.class) @RequestBody BaseDeleteBody req) {
|
||||
finishedProductShipmentService.deleteBatch(req.ids());
|
||||
return BaseResult.success();
|
||||
}
|
||||
|
||||
@ApiLog(type = OperationType.UPDATE, remark = "审核FinishedProductShipment")
|
||||
@Operation(summary = "审核FinishedProductShipment", operationId = "approveFinishedProductShipment")
|
||||
@PostMapping("/approveFinishedProductShipment")
|
||||
@PreAuthorize("hasAuthority('finished_product_shipment:approve')")
|
||||
public BaseResult<?> approveFinishedProductShipment(
|
||||
@Parameter(description = "成品出库单ID") @RequestParam Long id) {
|
||||
finishedProductShipmentService.approve(id);
|
||||
public BaseResult<?> approveFinishedProductShipment(@Validated @RequestBody BaseApproveAndRejectDto dto) {
|
||||
finishedProductShipmentService.approve(dto.id());
|
||||
return BaseResult.success();
|
||||
}
|
||||
|
||||
@ApiLog(type = OperationType.UPDATE, remark = "反审核FinishedProductShipment")
|
||||
@Operation(summary = "反审核FinishedProductShipment", operationId = "unapproveFinishedProductShipment")
|
||||
@PostMapping("/unapproveFinishedProductShipment")
|
||||
@PreAuthorize("hasAuthority('finished_product_shipment:unapprove')")
|
||||
public BaseResult<?> unapproveFinishedProductShipment(
|
||||
@Parameter(description = "成品出库单ID") @RequestParam Long id) {
|
||||
finishedProductShipmentService.unapprove(id);
|
||||
@Operation(summary = "反审核FinishedProductShipment", operationId = "rejectFinishedProductShipment")
|
||||
@PostMapping("/rejectFinishedProductShipment")
|
||||
@PreAuthorize("hasAuthority('finished_product_shipment:reject')")
|
||||
public BaseResult<?> rejectFinishedProductShipment(@Validated @RequestBody BaseApproveAndRejectDto dto) {
|
||||
finishedProductShipmentService.unapprove(dto.id());
|
||||
return BaseResult.success();
|
||||
}
|
||||
|
||||
@Operation(summary = "获取FinishedProductShipment明细", operationId = "getFinishedProductShipmentDetail")
|
||||
@GetMapping("/getFinishedProductShipmentDetail")
|
||||
@PreAuthorize("hasAuthority('finishedproductshipment:index')")
|
||||
public BaseResult<List<DeviceShipmentDto>> getFinishedProductShipmentDetail(
|
||||
@Parameter(description = "成品出库单ID") @RequestParam Long id) {
|
||||
@PreAuthorize("hasAuthority('finished_product_shipment:showItem')")
|
||||
public BaseResult<List<FinishedProductShipmentItemDto>> getFinishedProductShipmentDetail(
|
||||
@RequestParam Long id) {
|
||||
return BaseResult.successWithData(finishedProductShipmentService.getDetail(id));
|
||||
}
|
||||
|
||||
@Operation(summary = "导入FinishedProductShipment明细", operationId = "importFinishedProductShipmentItems")
|
||||
@PostMapping("/importFinishedProductShipmentItems")
|
||||
@PreAuthorize("hasAuthority('finished_product_shipment:import')")
|
||||
public BaseResult<List<DeviceShipmentDto>> importFinishedProductShipmentItems(
|
||||
@Parameter(description = "Excel文件") @RequestParam("file") MultipartFile file) {
|
||||
return BaseResult.successWithData(finishedProductShipmentService.importItems(file));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,52 @@
|
||||
package com.niuan.erp.module.production.controller.dto;
|
||||
|
||||
import com.niuan.erp.module.production.enums.OutStockType;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "成品出库DTO")
|
||||
public record FinishedProductShipmentDto(
|
||||
@Schema(description = "ID")
|
||||
Long id,
|
||||
@Schema(description = "状态")
|
||||
Integer status,
|
||||
@Schema(description = "创建时间")
|
||||
LocalDateTime createDate,
|
||||
@Schema(description = "创建用户ID")
|
||||
Long createUserId,
|
||||
@Schema(description = "创建用户名")
|
||||
String createUserName,
|
||||
@Schema(description = "更新时间")
|
||||
LocalDateTime updateDate,
|
||||
@Schema(description = "更新用户ID")
|
||||
Long updateUserId,
|
||||
@Schema(description = "更新用户名")
|
||||
String updateUserName,
|
||||
@Schema(description = "仓库编号")
|
||||
Integer storeNo,
|
||||
@Schema(description = "仓库名称")
|
||||
String storeName,
|
||||
@Schema(description = "单据类型")
|
||||
Integer formType,
|
||||
@Schema(description = "单据编号")
|
||||
String formCode,
|
||||
@Schema(description = "单据名称")
|
||||
String formName,
|
||||
@Schema(description = "单据状态")
|
||||
Integer formStatus,
|
||||
@Schema(description = "单据备注")
|
||||
String formMark,
|
||||
Integer reserve1,
|
||||
String reserve2,
|
||||
Integer vendorNo,
|
||||
String vendorName,
|
||||
@Schema(description = "出库类型")
|
||||
OutStockType outStockType,
|
||||
@Schema(description = "总价值")
|
||||
Double totalValue,
|
||||
@Schema(description = "出库仓库编号")
|
||||
Integer outStoreNo,
|
||||
@Schema(description = "出库仓库名称")
|
||||
String outStoreName,
|
||||
@Schema(description = "分组ID")
|
||||
Integer groupId,
|
||||
Integer customerId) {}
|
||||
@Schema(description = "客户ID")
|
||||
Integer customerId,
|
||||
@Schema(description = "出库明细列表")
|
||||
java.util.List<FinishedProductShipmentItemDto> shipmentItems) {}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package com.niuan.erp.module.production.converter;
|
||||
|
||||
import com.niuan.erp.module.common.entity.Document;
|
||||
import com.niuan.erp.module.production.controller.dto.DeviceShipmentDto;
|
||||
import com.niuan.erp.module.common.entity.DocumentMaterial;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentAddDto;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentDto;
|
||||
import com.niuan.erp.module.sale.entity.Device;
|
||||
import com.niuan.erp.module.sale.controller.dto.DeviceAddDto;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentItemDto;
|
||||
import com.niuan.erp.module.production.enums.OutStockType;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Named;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
import java.util.List;
|
||||
@@ -14,13 +16,67 @@ import java.util.List;
|
||||
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
public interface FinishedProductShipmentConverter {
|
||||
Document toEntity(FinishedProductShipmentDto dto);
|
||||
|
||||
@Mapping(target = "reserve1", source = "outStockType", qualifiedByName = "outStockTypeToInteger")
|
||||
@Mapping(target = "formType", ignore = true)
|
||||
Document toEntity(FinishedProductShipmentAddDto dto);
|
||||
|
||||
@Mapping(target = "outStockType", source = "reserve1", qualifiedByName = "integerToOutStockType")
|
||||
@Mapping(target = "formType", source = "formType", qualifiedByName = "documentTypeToInteger")
|
||||
@Mapping(target = "formStatus", source = "formStatus", qualifiedByName = "formStatusToInteger")
|
||||
FinishedProductShipmentDto toDto(Document entity);
|
||||
|
||||
List<FinishedProductShipmentDto> toDtoList(List<Document> entities);
|
||||
|
||||
Device toEntity(DeviceAddDto dto);
|
||||
List<Device> toEntityList(List<DeviceAddDto> dtoList);
|
||||
@Mapping(target = "partNumber", source = "partNumber")
|
||||
@Mapping(target = "productCount", source = "productCount")
|
||||
@Mapping(target = "productMark", source = "productMark")
|
||||
FinishedProductShipmentItemDto toItemDto(DocumentMaterial entity);
|
||||
|
||||
DeviceShipmentDto toDeviceShipmentDto(Device entity);
|
||||
List<DeviceShipmentDto> toDeviceShipmentDtoList(List<Device> entities);
|
||||
}
|
||||
List<FinishedProductShipmentItemDto> toItemDtoList(List<DocumentMaterial> entities);
|
||||
|
||||
@Mapping(target = "partNumber", source = "partNumber")
|
||||
@Mapping(target = "productCount", source = "productCount")
|
||||
@Mapping(target = "productMark", source = "productMark")
|
||||
@Mapping(target = "documentNo", ignore = true)
|
||||
DocumentMaterial toMaterialEntity(FinishedProductShipmentItemDto dto);
|
||||
|
||||
List<DocumentMaterial> toMaterialEntityList(List<FinishedProductShipmentItemDto> dtoList);
|
||||
|
||||
@Named("outStockTypeToInteger")
|
||||
default Integer outStockTypeToInteger(OutStockType outStockType) {
|
||||
if (outStockType == null) {
|
||||
return null;
|
||||
}
|
||||
return outStockType.getCode();
|
||||
}
|
||||
|
||||
@Named("integerToOutStockType")
|
||||
default OutStockType integerToOutStockType(Integer code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (OutStockType type : OutStockType.values()) {
|
||||
if (type.getCode() == code) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Named("documentTypeToInteger")
|
||||
default Integer documentTypeToInteger(com.niuan.erp.module.common.enums.DocumentType documentType) {
|
||||
if (documentType == null) {
|
||||
return null;
|
||||
}
|
||||
return documentType.getValue();
|
||||
}
|
||||
|
||||
@Named("formStatusToInteger")
|
||||
default Integer formStatusToInteger(com.niuan.erp.module.common.enums.FormStatus formStatus) {
|
||||
if (formStatus == null) {
|
||||
return null;
|
||||
}
|
||||
return formStatus.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ 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.DeviceShipmentDto;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentAddDto;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentDto;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentItemDto;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
@@ -21,13 +21,9 @@ public interface FinishedProductShipmentService {
|
||||
|
||||
void deleteFinishedProductShipment(long id);
|
||||
|
||||
void deleteBatch(List<Long> ids);
|
||||
|
||||
void approve(long id);
|
||||
|
||||
void unapprove(long id);
|
||||
|
||||
List<DeviceShipmentDto> getDetail(long id);
|
||||
|
||||
List<DeviceShipmentDto> importItems(MultipartFile file);
|
||||
List<FinishedProductShipmentItemDto> getDetail(long id);
|
||||
}
|
||||
|
||||
@@ -9,24 +9,26 @@ 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.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.enums.FormStatus;
|
||||
import com.niuan.erp.module.common.mapper.DocumentMapper;
|
||||
import com.niuan.erp.module.production.controller.dto.DeviceShipmentDto;
|
||||
import com.niuan.erp.module.common.mapper.DocumentMaterialMapper;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentAddDto;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentDto;
|
||||
import com.niuan.erp.module.production.controller.dto.FinishedProductShipmentItemDto;
|
||||
import com.niuan.erp.module.production.converter.FinishedProductShipmentConverter;
|
||||
import com.niuan.erp.module.production.enums.OutStockType;
|
||||
import com.niuan.erp.module.production.service.FinishedProductShipmentService;
|
||||
import com.niuan.erp.module.sale.entity.Device;
|
||||
import com.niuan.erp.module.sale.mapper.DeviceMapper;
|
||||
import com.niuan.erp.module.warehouse.entity.Stock;
|
||||
import com.niuan.erp.module.warehouse.entity.WarehouseItem;
|
||||
import com.niuan.erp.module.warehouse.mapper.StockMapper;
|
||||
import com.niuan.erp.module.warehouse.mapper.WarehouseItemMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -40,60 +42,86 @@ public class FinishedProductShipmentServiceImpl extends ServiceImpl<DocumentMapp
|
||||
|
||||
private final FinishedProductShipmentConverter finishedProductShipmentConverter;
|
||||
|
||||
private final DeviceMapper deviceMapper;
|
||||
private final DocumentMaterialMapper documentMaterialMapper;
|
||||
|
||||
private final StockMapper stockMapper;
|
||||
|
||||
private final WarehouseItemMapper warehouseItemMapper;
|
||||
|
||||
@Override
|
||||
public IPage<FinishedProductShipmentDto> getFinishedProductShipmentPage(BasePageReqParams pageParams, LambdaQueryWrapper<Document> wrapper) {
|
||||
wrapper.eq(Document::getFormType, DocumentType.FINISHED_PRODUCT_SHIPMENT);
|
||||
wrapper.eq(Document::getFormType, DocumentType.FINISHED_PRODUCT_SHIPMENT)
|
||||
.or()
|
||||
.eq(Document::getFormType, DocumentType.WAREHOUSE_ISSUE);
|
||||
// 按创建时间倒序排列
|
||||
wrapper.orderByDesc(Document::getCreateDate);
|
||||
IPage<Document> result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper);
|
||||
return result.convert(finishedProductShipmentConverter::toDto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFinishedProductShipment(FinishedProductShipmentAddDto dto) {
|
||||
List<com.niuan.erp.module.sale.controller.dto.DeviceAddDto> deviceItems = dto.deviceItems();
|
||||
|
||||
if (deviceItems == null || deviceItems.isEmpty()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.no_device_items");
|
||||
// 基础校验
|
||||
if (dto == null) {
|
||||
throw new BusinessException("production.finished_product_shipment.validate.dto.not_null");
|
||||
}
|
||||
if (dto.outStockType() == null) {
|
||||
throw new BusinessException("production.finished_product_shipment.validate.out_stock_type.not_null");
|
||||
}
|
||||
if (!StringUtils.hasText(dto.formCode())) {
|
||||
throw new BusinessException("production.finished_product_shipment.validate.form_code.not_null");
|
||||
}
|
||||
if (!StringUtils.hasText(dto.formName())) {
|
||||
throw new BusinessException("production.finished_product_shipment.validate.form_name.not_null");
|
||||
}
|
||||
if (dto.storeNo() == null) {
|
||||
throw new BusinessException("production.finished_product_shipment.validate.store_no.not_null");
|
||||
}
|
||||
|
||||
List<String> snList = deviceItems.stream()
|
||||
.map(com.niuan.erp.module.sale.controller.dto.DeviceAddDto::productSn)
|
||||
List<FinishedProductShipmentItemDto> shipmentItems = dto.shipmentItems();
|
||||
|
||||
if (shipmentItems == null || shipmentItems.isEmpty()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.no_shipment_items");
|
||||
}
|
||||
|
||||
// 校验明细项
|
||||
for (FinishedProductShipmentItemDto item : shipmentItems) {
|
||||
if (!StringUtils.hasText(item.partNumber())) {
|
||||
throw new BusinessException("production.finished_product_shipment.validate.part_number.not_blank");
|
||||
}
|
||||
if (item.productCount() == null || item.productCount() <= 0) {
|
||||
throw new BusinessException("production.finished_product_shipment.validate.product_count.positive");
|
||||
}
|
||||
}
|
||||
|
||||
List<String> partNumberList = shipmentItems.stream()
|
||||
.map(FinishedProductShipmentItemDto::partNumber)
|
||||
.filter(StringUtils::hasText)
|
||||
.toList();
|
||||
|
||||
if (snList.isEmpty()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.no_device_items");
|
||||
if (partNumberList.isEmpty()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.no_shipment_items");
|
||||
}
|
||||
|
||||
Set<String> uniqueSnSet = new HashSet<>(snList);
|
||||
if (uniqueSnSet.size() != snList.size()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.duplicate_sn_in_request");
|
||||
Set<String> uniquePartNumberSet = new HashSet<>(partNumberList);
|
||||
if (uniquePartNumberSet.size() != partNumberList.size()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.duplicate_part_number_in_request");
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<Device> snWrapper = new LambdaQueryWrapper<>();
|
||||
snWrapper.in(Device::getProductSn, snList);
|
||||
List<Device> existingSnList = deviceMapper.selectList(snWrapper);
|
||||
Set<String> existingSnSet = existingSnList.stream()
|
||||
.map(Device::getProductSn)
|
||||
LambdaQueryWrapper<WarehouseItem> itemWrapper = new LambdaQueryWrapper<>();
|
||||
itemWrapper.in(WarehouseItem::getPartNumber, partNumberList);
|
||||
List<WarehouseItem> existingItems = warehouseItemMapper.selectList(itemWrapper);
|
||||
Set<String> existingPartNumberSet = existingItems.stream()
|
||||
.map(WarehouseItem::getPartNumber)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
List<String> notFoundSn = snList.stream()
|
||||
.filter(sn -> !existingSnSet.contains(sn))
|
||||
.map(sn -> "SN号:" + sn)
|
||||
List<String> notFoundPartNumbers = partNumberList.stream()
|
||||
.filter(pn -> !existingPartNumberSet.contains(pn))
|
||||
.map(pn -> "物料编号:" + pn)
|
||||
.toList();
|
||||
|
||||
if (!notFoundSn.isEmpty()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.sn_not_found");
|
||||
}
|
||||
|
||||
List<String> alreadyShippedSn = existingSnList.stream()
|
||||
.filter(item -> item.getOutStatus() != null && item.getOutStatus())
|
||||
.map(item -> "SN号:" + item.getProductSn())
|
||||
.toList();
|
||||
|
||||
if (!alreadyShippedSn.isEmpty()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.sn_already_shipped");
|
||||
if (!notFoundPartNumbers.isEmpty()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.part_number_not_found");
|
||||
}
|
||||
|
||||
Document entity = finishedProductShipmentConverter.toEntity(dto);
|
||||
@@ -101,25 +129,31 @@ public class FinishedProductShipmentServiceImpl extends ServiceImpl<DocumentMapp
|
||||
entity.setCreateUserName(SecurityUtils.getUserName());
|
||||
entity.setCreateDate(LocalDateTime.now());
|
||||
entity.setStatus(0);
|
||||
entity.setFormType(DocumentType.FINISHED_PRODUCT_SHIPMENT);
|
||||
// 根据出库类型设置不同的单据类型:物料出库使用 WAREHOUSE_ISSUE(4),成品出库使用 FINISHED_PRODUCT_SHIPMENT(7)
|
||||
// 注意:Spring 默认使用枚举的 ordinal 值转换,所以 1 对应 FINISHED_PRODUCT (ordinal=1),需要用 code 比较
|
||||
if (dto.outStockType() != null && dto.outStockType().getCode() == 1) {
|
||||
entity.setFormType(DocumentType.WAREHOUSE_ISSUE);
|
||||
} else {
|
||||
entity.setFormType(DocumentType.FINISHED_PRODUCT_SHIPMENT);
|
||||
}
|
||||
entity.setFormStatus(FormStatus.NO_APPROVE);
|
||||
entity.setTotalValue(Double.valueOf(deviceItems.size()));
|
||||
entity.setTotalValue(Double.valueOf(shipmentItems.size()));
|
||||
entity.setCustomerId(SecurityUtils.getCustomerId());
|
||||
entity.setReserve1(dto.outStockType() != null ? dto.outStockType().getValue() : null);
|
||||
this.baseMapper.insert(entity);
|
||||
|
||||
List<Device> deviceEntities = finishedProductShipmentConverter.toEntityList(deviceItems);
|
||||
List<DocumentMaterial> materialEntities = finishedProductShipmentConverter.toMaterialEntityList(shipmentItems);
|
||||
|
||||
for (Device device : deviceEntities) {
|
||||
device.setDocumentNo(entity.getId().intValue());
|
||||
device.setCreateDate(LocalDateTime.now());
|
||||
device.setCreateUserId(SecurityUtils.getUserId());
|
||||
device.setCreateUserName(SecurityUtils.getUserName());
|
||||
device.setStatus(0);
|
||||
device.setCustomerId(SecurityUtils.getCustomerId());
|
||||
device.setOutStatus(false);
|
||||
for (DocumentMaterial material : materialEntities) {
|
||||
material.setDocumentNo(entity.getId().intValue());
|
||||
material.setCreateDate(LocalDateTime.now());
|
||||
material.setCreateUserId(SecurityUtils.getUserId());
|
||||
material.setCreateUserName(SecurityUtils.getUserName());
|
||||
material.setStatus(0);
|
||||
material.setStoreNo(dto.storeNo());
|
||||
}
|
||||
|
||||
deviceMapper.insert(deviceEntities);
|
||||
documentMaterialMapper.insert(materialEntities);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -151,30 +185,9 @@ public class FinishedProductShipmentServiceImpl extends ServiceImpl<DocumentMapp
|
||||
|
||||
this.baseMapper.deleteById(id);
|
||||
|
||||
LambdaQueryWrapper<Device> itemWrapper = new LambdaQueryWrapper<>();
|
||||
itemWrapper.eq(Device::getDocumentNo, id);
|
||||
deviceMapper.delete(itemWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteBatch(List<Long> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.ids_empty");
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<Document> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.in(Document::getId, ids);
|
||||
wrapper.eq(Document::getFormStatus, FormStatus.APPROVE);
|
||||
Long approvedCount = this.baseMapper.selectCount(wrapper);
|
||||
if (approvedCount > 0) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.cannot_delete_approved_batch");
|
||||
}
|
||||
|
||||
this.baseMapper.deleteBatchIds(ids);
|
||||
|
||||
LambdaQueryWrapper<Device> itemWrapper = new LambdaQueryWrapper<>();
|
||||
itemWrapper.in(Device::getDocumentNo, ids);
|
||||
deviceMapper.delete(itemWrapper);
|
||||
LambdaQueryWrapper<DocumentMaterial> itemWrapper = new LambdaQueryWrapper<>();
|
||||
itemWrapper.eq(DocumentMaterial::getDocumentNo, id);
|
||||
documentMaterialMapper.delete(itemWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -187,20 +200,40 @@ public class FinishedProductShipmentServiceImpl extends ServiceImpl<DocumentMapp
|
||||
throw new BusinessException("production.finished_product_shipment.exception.already_approved");
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<Device> itemWrapper = new LambdaQueryWrapper<>();
|
||||
itemWrapper.eq(Device::getDocumentNo, id);
|
||||
List<Device> items = deviceMapper.selectList(itemWrapper);
|
||||
LambdaQueryWrapper<DocumentMaterial> itemWrapper = new LambdaQueryWrapper<>();
|
||||
itemWrapper.eq(DocumentMaterial::getDocumentNo, id);
|
||||
List<DocumentMaterial> items = documentMaterialMapper.selectList(itemWrapper);
|
||||
if (items == null || items.isEmpty()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.no_device_items");
|
||||
throw new BusinessException("production.finished_product_shipment.exception.no_shipment_items");
|
||||
}
|
||||
|
||||
List<String> alreadyShippedSn = items.stream()
|
||||
.filter(item -> item.getOutStatus() != null && item.getOutStatus())
|
||||
.map(item -> "SN号:" + item.getProductSn())
|
||||
Integer storeNo = entity.getStoreNo();
|
||||
List<String> partNumbers = items.stream()
|
||||
.map(DocumentMaterial::getPartNumber)
|
||||
.distinct()
|
||||
.toList();
|
||||
|
||||
if (!alreadyShippedSn.isEmpty()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.sn_already_shipped");
|
||||
LambdaQueryWrapper<Stock> stockWrapper = new LambdaQueryWrapper<>();
|
||||
stockWrapper.eq(Stock::getStoreNo, storeNo)
|
||||
.in(Stock::getPartNumber, partNumbers);
|
||||
List<Stock> stockList = stockMapper.selectList(stockWrapper);
|
||||
Map<String, Stock> stockMap = stockList.stream()
|
||||
.collect(Collectors.toMap(Stock::getPartNumber, s -> s));
|
||||
|
||||
for (DocumentMaterial item : items) {
|
||||
Stock stock = stockMap.get(item.getPartNumber());
|
||||
if (stock == null || stock.getProductCount() < item.getProductCount()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.insufficient_stock");
|
||||
}
|
||||
}
|
||||
|
||||
for (DocumentMaterial item : items) {
|
||||
Stock stock = stockMap.get(item.getPartNumber());
|
||||
stock.setProductCount(stock.getProductCount() - item.getProductCount());
|
||||
stock.setUpdateDate(LocalDateTime.now());
|
||||
stock.setUpdateUserId(SecurityUtils.getUserId());
|
||||
stock.setUpdateUserName(SecurityUtils.getUserName());
|
||||
stockMapper.updateById(stock);
|
||||
}
|
||||
|
||||
entity.setFormStatus(FormStatus.APPROVE);
|
||||
@@ -208,15 +241,6 @@ public class FinishedProductShipmentServiceImpl extends ServiceImpl<DocumentMapp
|
||||
entity.setUpdateUserId(SecurityUtils.getUserId());
|
||||
entity.setUpdateUserName(SecurityUtils.getUserName());
|
||||
this.baseMapper.updateById(entity);
|
||||
|
||||
LambdaUpdateWrapper<Device> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(Device::getDocumentNo, id)
|
||||
.set(Device::getOutStatus, true)
|
||||
.set(Device::getOutProductDate, LocalDateTime.now())
|
||||
.set(Device::getUpdateDate, LocalDateTime.now())
|
||||
.set(Device::getUpdateUserId, SecurityUtils.getUserId())
|
||||
.set(Device::getUpdateUserName, SecurityUtils.getUserName());
|
||||
deviceMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -229,84 +253,84 @@ public class FinishedProductShipmentServiceImpl extends ServiceImpl<DocumentMapp
|
||||
throw new BusinessException("production.finished_product_shipment.exception.not_approved");
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<Device> itemWrapper = new LambdaQueryWrapper<>();
|
||||
itemWrapper.eq(Device::getDocumentNo, id);
|
||||
List<Device> items = deviceMapper.selectList(itemWrapper);
|
||||
LambdaQueryWrapper<DocumentMaterial> itemWrapper = new LambdaQueryWrapper<>();
|
||||
itemWrapper.eq(DocumentMaterial::getDocumentNo, id);
|
||||
List<DocumentMaterial> items = documentMaterialMapper.selectList(itemWrapper);
|
||||
|
||||
Integer storeNo = entity.getStoreNo();
|
||||
List<String> partNumbers = items.stream()
|
||||
.map(DocumentMaterial::getPartNumber)
|
||||
.distinct()
|
||||
.toList();
|
||||
|
||||
LambdaQueryWrapper<Stock> stockWrapper = new LambdaQueryWrapper<>();
|
||||
stockWrapper.eq(Stock::getStoreNo, storeNo)
|
||||
.in(Stock::getPartNumber, partNumbers);
|
||||
List<Stock> stockList = stockMapper.selectList(stockWrapper);
|
||||
Map<String, Stock> stockMap = stockList.stream()
|
||||
.collect(Collectors.toMap(Stock::getPartNumber, s -> s));
|
||||
|
||||
for (DocumentMaterial item : items) {
|
||||
Stock stock = stockMap.get(item.getPartNumber());
|
||||
if (stock != null) {
|
||||
stock.setProductCount(stock.getProductCount() + item.getProductCount());
|
||||
stock.setUpdateDate(LocalDateTime.now());
|
||||
stock.setUpdateUserId(SecurityUtils.getUserId());
|
||||
stock.setUpdateUserName(SecurityUtils.getUserName());
|
||||
stockMapper.updateById(stock);
|
||||
} else {
|
||||
Stock newStock = new Stock();
|
||||
newStock.setPartNumber(item.getPartNumber());
|
||||
newStock.setProductCount(item.getProductCount());
|
||||
newStock.setStoreNo(storeNo);
|
||||
newStock.setCreateDate(LocalDateTime.now());
|
||||
newStock.setCreateUserId(SecurityUtils.getUserId());
|
||||
newStock.setCreateUserName(SecurityUtils.getUserName());
|
||||
newStock.setStatus(0);
|
||||
stockMapper.insert(newStock);
|
||||
}
|
||||
}
|
||||
|
||||
entity.setFormStatus(FormStatus.NO_APPROVE);
|
||||
entity.setUpdateDate(LocalDateTime.now());
|
||||
entity.setUpdateUserId(SecurityUtils.getUserId());
|
||||
entity.setUpdateUserName(SecurityUtils.getUserName());
|
||||
this.baseMapper.updateById(entity);
|
||||
|
||||
LambdaUpdateWrapper<Device> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(Device::getDocumentNo, id)
|
||||
.set(Device::getOutStatus, false)
|
||||
.set(Device::getOutProductDate, (LocalDateTime) null)
|
||||
.set(Device::getUpdateDate, LocalDateTime.now())
|
||||
.set(Device::getUpdateUserId, SecurityUtils.getUserId())
|
||||
.set(Device::getUpdateUserName, SecurityUtils.getUserName());
|
||||
deviceMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceShipmentDto> getDetail(long id) {
|
||||
LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(Device::getDocumentNo, id);
|
||||
List<Device> items = deviceMapper.selectList(wrapper);
|
||||
return finishedProductShipmentConverter.toDeviceShipmentDtoList(items);
|
||||
}
|
||||
public List<FinishedProductShipmentItemDto> getDetail(long id) {
|
||||
LambdaQueryWrapper<DocumentMaterial> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(DocumentMaterial::getDocumentNo, id);
|
||||
List<DocumentMaterial> items = documentMaterialMapper.selectList(wrapper);
|
||||
|
||||
@Override
|
||||
public List<DeviceShipmentDto> importItems(MultipartFile file) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.file_empty");
|
||||
List<String> partNumbers = items.stream()
|
||||
.map(DocumentMaterial::getPartNumber)
|
||||
.filter(StringUtils::hasText)
|
||||
.distinct()
|
||||
.toList();
|
||||
|
||||
if (!partNumbers.isEmpty()) {
|
||||
LambdaQueryWrapper<WarehouseItem> itemWrapper = new LambdaQueryWrapper<>();
|
||||
itemWrapper.in(WarehouseItem::getPartNumber, partNumbers);
|
||||
List<WarehouseItem> warehouseItems = warehouseItemMapper.selectList(itemWrapper);
|
||||
Map<String, String> specsMap = warehouseItems.stream()
|
||||
.collect(Collectors.toMap(WarehouseItem::getPartNumber, WarehouseItem::getProductSpecs, (a, b) -> a));
|
||||
|
||||
return items.stream()
|
||||
.map(item -> {
|
||||
FinishedProductShipmentItemDto dto = finishedProductShipmentConverter.toItemDto(item);
|
||||
return new FinishedProductShipmentItemDto(
|
||||
dto.id(),
|
||||
dto.partNumber(),
|
||||
specsMap.getOrDefault(dto.partNumber(), ""),
|
||||
dto.productCount(),
|
||||
dto.productMark()
|
||||
);
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
try (Workbook workbook = WorkbookFactory.create(file.getInputStream())) {
|
||||
Sheet sheet = workbook.getSheetAt(0);
|
||||
List<DeviceShipmentDto> items = new ArrayList<>();
|
||||
|
||||
for (int i = 1; i <= sheet.getLastRowNum(); i++) {
|
||||
Row row = sheet.getRow(i);
|
||||
if (row == null) continue;
|
||||
|
||||
String productType = getCellValueAsString(row.getCell(0));
|
||||
String productSn = getCellValueAsString(row.getCell(1));
|
||||
String mac = getCellValueAsString(row.getCell(2));
|
||||
String serialNum = getCellValueAsString(row.getCell(3));
|
||||
String softVersion = getCellValueAsString(row.getCell(4));
|
||||
String alVersion = getCellValueAsString(row.getCell(5));
|
||||
String alNum = getCellValueAsString(row.getCell(6));
|
||||
String alTxt = getCellValueAsString(row.getCell(7));
|
||||
String manufacturingDate = getCellValueAsString(row.getCell(8));
|
||||
String mark = getCellValueAsString(row.getCell(9));
|
||||
|
||||
if (!StringUtils.hasText(productSn)) continue;
|
||||
|
||||
DeviceShipmentDto item = new DeviceShipmentDto(
|
||||
null, null, null, null, null, null, null, null,
|
||||
null, productType, productSn, mac, serialNum, softVersion,
|
||||
alVersion, alNum, null, null, mark, null, null, null, null, null
|
||||
);
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
} catch (IOException e) {
|
||||
throw new BusinessException("production.finished_product_shipment.exception.import_failed");
|
||||
}
|
||||
return finishedProductShipmentConverter.toItemDtoList(items);
|
||||
}
|
||||
|
||||
private String getCellValueAsString(Cell cell) {
|
||||
if (cell == null) {
|
||||
return "";
|
||||
}
|
||||
return switch (cell.getCellType()) {
|
||||
case STRING -> cell.getStringCellValue().trim();
|
||||
case NUMERIC -> String.valueOf((long) cell.getNumericCellValue());
|
||||
case BOOLEAN -> String.valueOf(cell.getBooleanCellValue());
|
||||
default -> "";
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user