| | |
| | | import com.ruoyi.basic.mapper.ProductModelMapper; |
| | | import com.ruoyi.basic.pojo.ProductModel; |
| | | import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.procurementrecord.utils.StockUtils; |
| | |
| | | import com.ruoyi.sales.service.ISalesLedgerProductProcessBindService; |
| | | import com.ruoyi.sales.service.ISalesLedgerProductService; |
| | | import com.ruoyi.stock.mapper.StockInventoryMapper; |
| | | import com.ruoyi.stock.mapper.StockInRecordMapper; |
| | | import com.ruoyi.stock.dto.StockInventoryDto; |
| | | import com.ruoyi.stock.pojo.StockInRecord; |
| | | import com.ruoyi.stock.pojo.StockInventory; |
| | | import lombok.AllArgsConstructor; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | private ShippingInfoServiceImpl shippingInfoService; |
| | | |
| | | private StockUtils stockUtils; |
| | | |
| | | private StockInRecordMapper stockInRecordMapper; |
| | | |
| | | private final ISalesLedgerProductProcessBindService salesLedgerProductProcessBindService; |
| | | |
| | |
| | | result = salesLedgerProductMapper.insert(salesLedgerProduct); |
| | | addProductionData(salesLedgerProduct); |
| | | } else { |
| | | SalesLedgerProduct dbBefore = salesLedgerProductMapper.selectById(salesLedgerProduct.getId()); |
| | | if (dbBefore == null) { |
| | | throw new RuntimeException("销售产品不存在,无法编辑"); |
| | | } |
| | | // 不能把订单数量改到小于已发货数量,否则账实不一致 |
| | | BigDecimal shipped = dbBefore.getShippedQuantity() == null ? BigDecimal.ZERO : dbBefore.getShippedQuantity(); |
| | | BigDecimal newOrderQty = salesLedgerProduct.getQuantity() == null ? BigDecimal.ZERO : salesLedgerProduct.getQuantity(); |
| | | if (newOrderQty.compareTo(shipped) < 0) { |
| | | throw new RuntimeException("编辑失败,订单数量不能小于已发货数量"); |
| | | } |
| | | //查询原本的产品型号id |
| | | salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity()); |
| | | result = salesLedgerProductMapper.updateById(salesLedgerProduct); |
| | | |
| | | // 允许“多入库”:当订单数量被下调时,只回退“下调差额”对应的入库数量 |
| | | // 例:原订单100,已入库120;改为50 -> 只回退50,最终已入库70(不强压到50) |
| | | BigDecimal oldOrderQty = dbBefore.getQuantity() == null ? BigDecimal.ZERO : dbBefore.getQuantity(); |
| | | BigDecimal stocked = dbBefore.getStockedQuantity() == null ? BigDecimal.ZERO : dbBefore.getStockedQuantity(); |
| | | BigDecimal reduced = oldOrderQty.subtract(newOrderQty); |
| | | if (reduced.compareTo(BigDecimal.ZERO) > 0) { |
| | | BigDecimal rollbackQty = stocked.min(reduced); |
| | | if (rollbackQty.compareTo(BigDecimal.ZERO) > 0) { |
| | | rollbackExcessStockIn(dbBefore, rollbackQty); |
| | | } |
| | | } |
| | | |
| | | /*删除对应的生产数据并重新新增*/ |
| | | deleteProductionData(Arrays.asList(salesLedgerProduct.getId())); |
| | | // 删除生产核算数据 |
| | |
| | | |
| | | // 清空销售产品绑定的加工 |
| | | salesLedgerProductProcessBindService.updateProductProcessBind(salesLedgerProduct.getSalesProductProcessList(), salesLedgerProduct.getId()); |
| | | |
| | | // 新增/编辑产品后,刷新销售主单入库状态(避免因新增未入库行导致状态不准) |
| | | refreshSalesLedgerStockStatus(salesLedgerId); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private void rollbackExcessStockIn(SalesLedgerProduct dbBefore, BigDecimal rollbackQtyTotal) { |
| | | if (dbBefore == null || rollbackQtyTotal == null || rollbackQtyTotal.compareTo(BigDecimal.ZERO) <= 0) { |
| | | return; |
| | | } |
| | | if (dbBefore.getProductModelId() == null) { |
| | | throw new RuntimeException("回退入库失败,产品规格未维护"); |
| | | } |
| | | Long productId = dbBefore.getId(); |
| | | // 倒序回退:优先回退“扫码入库”,再回退“手动入库” |
| | | List<String> recordTypes = Arrays.asList( |
| | | StockInQualifiedRecordTypeEnum.SALE_SCAN_STOCK_IN.getCode(), |
| | | StockInQualifiedRecordTypeEnum.SALE_STOCK_IN.getCode() |
| | | ); |
| | | List<StockInRecord> records = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>() |
| | | .eq(StockInRecord::getSalesLedgerProductId, productId) |
| | | .eq(StockInRecord::getType, "0") |
| | | .in(StockInRecord::getRecordType, recordTypes) |
| | | .orderByDesc(StockInRecord::getCreateTime)); |
| | | BigDecimal remaining = rollbackQtyTotal; |
| | | for (StockInRecord r : records) { |
| | | if (remaining.compareTo(BigDecimal.ZERO) <= 0) { |
| | | break; |
| | | } |
| | | BigDecimal inNum = r.getStockInNum() == null ? BigDecimal.ZERO : r.getStockInNum(); |
| | | if (inNum.compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | BigDecimal rollbackQty = inNum.min(remaining); |
| | | |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | | stockInventoryDto.setProductModelId(dbBefore.getProductModelId()); |
| | | stockInventoryDto.setQualitity(rollbackQty); |
| | | int affectRows = stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto); |
| | | if (affectRows <= 0) { |
| | | throw new RuntimeException("回退入库失败,当前库存不足,无法扣回超入库数量"); |
| | | } |
| | | |
| | | BigDecimal newInNum = inNum.subtract(rollbackQty); |
| | | if (newInNum.compareTo(BigDecimal.ZERO) <= 0) { |
| | | stockInRecordMapper.deleteById(r.getId()); |
| | | } else { |
| | | r.setStockInNum(newInNum); |
| | | stockInRecordMapper.updateById(r); |
| | | } |
| | | remaining = remaining.subtract(rollbackQty); |
| | | } |
| | | if (remaining.compareTo(BigDecimal.ZERO) > 0) { |
| | | throw new RuntimeException("回退入库失败,未找到足够的入库记录用于扣回超入库数量"); |
| | | } |
| | | |
| | | // 回写产品行已入库数量与状态 |
| | | SalesLedgerProduct fresh = salesLedgerProductMapper.selectById(dbBefore.getId()); |
| | | if (fresh == null) { |
| | | return; |
| | | } |
| | | BigDecimal newStocked = (fresh.getStockedQuantity() == null ? BigDecimal.ZERO : fresh.getStockedQuantity()).subtract(rollbackQtyTotal); |
| | | if (newStocked.compareTo(BigDecimal.ZERO) < 0) { |
| | | newStocked = BigDecimal.ZERO; |
| | | } |
| | | BigDecimal orderQty = fresh.getQuantity() == null ? BigDecimal.ZERO : fresh.getQuantity(); |
| | | int stockStatus; |
| | | if (newStocked.compareTo(BigDecimal.ZERO) <= 0) stockStatus = 0; |
| | | else if (orderQty.compareTo(BigDecimal.ZERO) > 0 && newStocked.compareTo(orderQty) < 0) stockStatus = 1; |
| | | else stockStatus = 2; |
| | | fresh.setStockedQuantity(newStocked); |
| | | fresh.setProductStockStatus(stockStatus); |
| | | fresh.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.updateById(fresh); |
| | | } |
| | | |
| | | private void refreshSalesLedgerStockStatus(Long salesLedgerId) { |
| | | if (salesLedgerId == null) { |
| | | return; |
| | | } |
| | | SalesLedger ledger = salesLedgerMapper.selectById(salesLedgerId); |
| | | if (ledger == null) { |
| | | return; |
| | | } |
| | | List<SalesLedgerProduct> allProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>() |
| | | .eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId) |
| | | .eq(SalesLedgerProduct::getType, 1)); |
| | | if (CollectionUtils.isEmpty(allProducts)) { |
| | | ledger.setStockStatus(0); |
| | | salesLedgerMapper.updateById(ledger); |
| | | return; |
| | | } |
| | | boolean anyInbound = allProducts.stream().anyMatch(p -> { |
| | | BigDecimal sq = p.getStockedQuantity(); |
| | | return sq != null && sq.compareTo(BigDecimal.ZERO) > 0; |
| | | }); |
| | | boolean allFull = allProducts.stream().allMatch(p -> Objects.equals(p.getProductStockStatus(), 2)); |
| | | ledger.setStockStatus(allFull ? 2 : (anyInbound ? 1 : 0)); |
| | | salesLedgerMapper.updateById(ledger); |
| | | } |
| | | |
| | | /** |
| | | * 新增生产数据 |
| | | */ |