| | |
| | | import com.ruoyi.production.mapper.ProductionProductMainMapper; |
| | | import com.ruoyi.production.bean.dto.ProductionAccountDto; |
| | | import com.ruoyi.production.bean.dto.ProductionProductMainDto; |
| | | import com.ruoyi.production.enums.MajorCategoryEnum; |
| | | import com.ruoyi.production.pojo.ProductionAccount; |
| | | import com.ruoyi.technology.mapper.TechnologyOperationMapper; |
| | | import com.ruoyi.technology.pojo.TechnologyOperation; |
| | |
| | | /** |
| | | * 汇总员工当月月时间合计。 |
| | | * 规则: |
| | | * 1. 小提琴 / 大提琴 / 贝斯:月产折合小提琴数量 / 工序标准数量 × 8 + 修补理工时 |
| | | * 1. 小提琴 / 中提琴 / 大提琴 / 贝斯:月产折合小提琴数量 / 工序标准数量 × 8 + 修补理工时 |
| | | * 2. 其他产品:当月实际产量 / 对应产品标准数量 × 8 + 修补理工时 |
| | | * 最终结果就是工资表里的月时间合计。 |
| | | */ |
| | |
| | | java.math.BigDecimal productStandardQuantity = toDecimal(item.get("productStandardQuantity")); |
| | | java.math.BigDecimal violinFactor = toDecimal(item.get("violinFactor")); |
| | | java.math.BigDecimal violaFactor = toDecimal(item.get("violaFactor")); |
| | | java.math.BigDecimal midViolinFactor = toDecimal(item.get("midViolinFactor")); |
| | | java.math.BigDecimal bassFactor = toDecimal(item.get("bassFactor")); |
| | | String productName = item.get("productName") == null ? null : String.valueOf(item.get("productName")); |
| | | // 归类依据用报工时已归集好的大类,不再拿产品名称做字符串比较 |
| | | String majorCategory = item.get("majorCategory") == null ? null : String.valueOf(item.get("majorCategory")); |
| | | java.math.BigDecimal rowTotal = calculateOperationTime( |
| | | operationType, |
| | | productName, |
| | | majorCategory, |
| | | finishedNum, |
| | | workHour, |
| | | repairWorkHour, |
| | |
| | | productStandardQuantity, |
| | | violinFactor, |
| | | violaFactor, |
| | | midViolinFactor, |
| | | bassFactor |
| | | ); |
| | | total = total.add(rowTotal).setScale(2, java.math.RoundingMode.HALF_UP); |
| | |
| | | /** |
| | | * 计算单条工序的折算工时。 |
| | | * 这里是月时间合计的核心分支: |
| | | * - 小提琴 / 大提琴 / 贝斯:月产折合小提琴数量 / 工序标准数量 × 8 + 修补理工时; |
| | | * - 其他产品:当月实际产量 / 对应产品标准数量 × 8 + 修补理工时。 |
| | | * - 小提琴 / 中提琴 / 大提琴 / 贝斯:月产折合小提琴数量 / 工序标准数量 × 8 + 修补理工时; |
| | | * - 其他产品(含未归类报工):当月实际产量 / 对应产品标准数量 × 8 + 修补理工时。 |
| | | */ |
| | | private java.math.BigDecimal calculateOperationTime(Integer operationType, |
| | | String productName, |
| | | String majorCategory, |
| | | java.math.BigDecimal finishedNum, |
| | | java.math.BigDecimal workHour, |
| | | java.math.BigDecimal repairWorkHour, |
| | |
| | | java.math.BigDecimal productStandardQuantity, |
| | | java.math.BigDecimal violinFactor, |
| | | java.math.BigDecimal violaFactor, |
| | | java.math.BigDecimal midViolinFactor, |
| | | java.math.BigDecimal bassFactor) { |
| | | if (isInstrumentProduct(productName)) { |
| | | java.math.BigDecimal foldedQuantity = calculateFoldedQuantity( |
| | | finishedNum, |
| | | resolveInstrumentFactor(productName, violinFactor, violaFactor, bassFactor) |
| | | ); |
| | | java.math.BigDecimal instrumentFactor = resolveInstrumentFactor( |
| | | majorCategory, violinFactor, violaFactor, midViolinFactor, bassFactor); |
| | | if (instrumentFactor != null) { |
| | | java.math.BigDecimal foldedQuantity = calculateFoldedQuantity(finishedNum, instrumentFactor); |
| | | if (standardQuantity.compareTo(java.math.BigDecimal.ZERO) <= 0) { |
| | | return java.math.BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP); |
| | | } |
| | |
| | | } |
| | | |
| | | /** |
| | | * 按产品名称和配置系数折算产量。 |
| | | * 只对小提琴、大提琴、贝斯三类产品生效, |
| | | * 返回的是可用于后续工序标准数量换算的统一折合产量。 |
| | | * 按产量与折算率折算。是否属于乐器由调用方用 {@link MajorCategoryEnum} 判定, |
| | | * 这里只做乘法,返回的是可用于后续工序标准数量换算的统一折合产量。 |
| | | */ |
| | | private java.math.BigDecimal calculateFoldedQuantity(java.math.BigDecimal quantity, |
| | | java.math.BigDecimal factor) { |
| | |
| | | return quantity.multiply(factor).setScale(2, java.math.RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private boolean isInstrumentProduct(String productName) { |
| | | return "小提琴".equals(productName) |
| | | || "大提琴".equals(productName) |
| | | || "贝斯".equals(productName); |
| | | /** |
| | | * 判断报工大类是否属于乐器。未归类({@code major_category} 为 null, |
| | | * 如零件/原料类工序产出)返回 false,由调用方走“其他产品”分支。 |
| | | */ |
| | | private boolean isInstrumentCategory(String majorCategory) { |
| | | return MajorCategoryEnum.isInstrument(majorCategory); |
| | | } |
| | | |
| | | private java.math.BigDecimal resolveInstrumentFactor(String productName, |
| | | /** |
| | | * 按报工大类取对应折算率。 |
| | | * |
| | | * @return {@code null} 表示不是乐器大类(含未归类),调用方据此走“其他产品”分支 |
| | | */ |
| | | private java.math.BigDecimal resolveInstrumentFactor(String majorCategory, |
| | | java.math.BigDecimal violinFactor, |
| | | java.math.BigDecimal violaFactor, |
| | | java.math.BigDecimal midViolinFactor, |
| | | java.math.BigDecimal bassFactor) { |
| | | if ("小提琴".equals(productName)) { |
| | | MajorCategoryEnum category = MajorCategoryEnum.of(majorCategory); |
| | | if (category == null) { |
| | | return null; |
| | | } |
| | | switch (category) { |
| | | case VIOLIN: |
| | | return violinFactor; |
| | | } |
| | | if ("大提琴".equals(productName)) { |
| | | case VIOLA: |
| | | return midViolinFactor; |
| | | case CELLO: |
| | | // violaFactor 的列名沿用了 viola(中提琴),历史语义实为【大提琴】折算率,勿改 |
| | | return violaFactor; |
| | | } |
| | | if ("贝斯".equals(productName)) { |
| | | case BASS: |
| | | return bassFactor; |
| | | default: |
| | | return null; |
| | | } |
| | | return java.math.BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private String formatEntryDate(java.util.Date entryDate) { |
| | |
| | | |
| | | Map<String, List<ProductionProductMainDto>> grouped = accountList.stream() |
| | | .filter(item -> item != null && item.getSchedulingUserName() != null) |
| | | .filter(item -> instrumentSheet == isInstrumentProduct(item.getProductName())) |
| | | .filter(item -> instrumentSheet == isInstrumentCategory(item.getMajorCategory())) |
| | | .sorted(java.util.Comparator |
| | | .comparing(ProductionProductMainDto::getSchedulingUserName, java.util.Comparator.nullsLast(String::compareTo)) |
| | | .thenComparing(item -> StringUtils.isEmpty(item.getProductName()) ? "" : item.getProductName()) |
| | |
| | | Map<String, java.math.BigDecimal> convertedMap = new LinkedHashMap<>(); |
| | | Map<String, java.math.BigDecimal> foldedMap = new LinkedHashMap<>(); |
| | | Map<String, java.math.BigDecimal> violinQuantityMap = new LinkedHashMap<>(); |
| | | Map<String, java.math.BigDecimal> violaQuantityMap = new LinkedHashMap<>(); |
| | | // 变量名按实际乐器命名:midViolin=中提琴、cello=大提琴(注意勿与历史列名 viola_factor 混淆) |
| | | Map<String, java.math.BigDecimal> midViolinQuantityMap = new LinkedHashMap<>(); |
| | | Map<String, java.math.BigDecimal> celloQuantityMap = new LinkedHashMap<>(); |
| | | Map<String, java.math.BigDecimal> bassQuantityMap = new LinkedHashMap<>(); |
| | | for (Map<String, Object> column : columns) { |
| | | String key = String.valueOf(column.get("key")); |
| | |
| | | convertedMap.put(key, java.math.BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP)); |
| | | foldedMap.put(key, java.math.BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP)); |
| | | violinQuantityMap.put(key, java.math.BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP)); |
| | | violaQuantityMap.put(key, java.math.BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP)); |
| | | midViolinQuantityMap.put(key, java.math.BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP)); |
| | | celloQuantityMap.put(key, java.math.BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP)); |
| | | bassQuantityMap.put(key, java.math.BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP)); |
| | | } |
| | | for (ProductionProductMainDto item : staffItems) { |
| | |
| | | foldedMap.merge(key, foldedQty, java.math.BigDecimal::add); |
| | | convertedMap.merge(key, convertedHours, java.math.BigDecimal::add); |
| | | if (instrumentSheet) { |
| | | if ("小提琴".equals(item.getProductName())) { |
| | | MajorCategoryEnum category = MajorCategoryEnum.of(item.getMajorCategory()); |
| | | if (category == MajorCategoryEnum.VIOLIN) { |
| | | violinQuantityMap.merge(key, quantity, java.math.BigDecimal::add); |
| | | } else if ("大提琴".equals(item.getProductName())) { |
| | | violaQuantityMap.merge(key, quantity, java.math.BigDecimal::add); |
| | | } else if ("贝斯".equals(item.getProductName())) { |
| | | } else if (category == MajorCategoryEnum.VIOLA) { |
| | | midViolinQuantityMap.merge(key, quantity, java.math.BigDecimal::add); |
| | | } else if (category == MajorCategoryEnum.CELLO) { |
| | | celloQuantityMap.merge(key, quantity, java.math.BigDecimal::add); |
| | | } else if (category == MajorCategoryEnum.BASS) { |
| | | bassQuantityMap.merge(key, quantity, java.math.BigDecimal::add); |
| | | } |
| | | } |
| | |
| | | createDisplayNumberCell(qtyRow, dataCol, null, numStyle); |
| | | |
| | | if (instrumentSheet) { |
| | | Row violaRow = sheet.createRow(rowIdx++); |
| | | violaRow.setHeightInPoints(24f); |
| | | createEdgeCell(sheet.getWorkbook(), violaRow, 0, "", numStyle, false, false, true, true); |
| | | createTextCell(violaRow, 1, "月产大", numStyle); |
| | | Row midViolinRow = sheet.createRow(rowIdx++); |
| | | midViolinRow.setHeightInPoints(24f); |
| | | createEdgeCell(sheet.getWorkbook(), midViolinRow, 0, "", numStyle, false, false, true, true); |
| | | createTextCell(midViolinRow, 1, "月产中", numStyle); |
| | | dataCol = 2; |
| | | for (Map<String, Object> column : columns) { |
| | | String key = String.valueOf(column.get("key")); |
| | | createDisplayNumberCell(violaRow, dataCol++, violaQuantityMap.getOrDefault(key, java.math.BigDecimal.ZERO), numStyle); |
| | | createDisplayNumberCell(midViolinRow, dataCol++, midViolinQuantityMap.getOrDefault(key, java.math.BigDecimal.ZERO), numStyle); |
| | | } |
| | | createDisplayNumberCell(violaRow, dataCol++, null, numStyle); |
| | | createDisplayNumberCell(violaRow, dataCol, null, numStyle); |
| | | createDisplayNumberCell(midViolinRow, dataCol++, null, numStyle); |
| | | createDisplayNumberCell(midViolinRow, dataCol, null, numStyle); |
| | | |
| | | Row celloRow = sheet.createRow(rowIdx++); |
| | | celloRow.setHeightInPoints(24f); |
| | | createEdgeCell(sheet.getWorkbook(), celloRow, 0, "", numStyle, false, false, true, true); |
| | | createTextCell(celloRow, 1, "月产大", numStyle); |
| | | dataCol = 2; |
| | | for (Map<String, Object> column : columns) { |
| | | String key = String.valueOf(column.get("key")); |
| | | createDisplayNumberCell(celloRow, dataCol++, celloQuantityMap.getOrDefault(key, java.math.BigDecimal.ZERO), numStyle); |
| | | } |
| | | createDisplayNumberCell(celloRow, dataCol++, null, numStyle); |
| | | createDisplayNumberCell(celloRow, dataCol, null, numStyle); |
| | | |
| | | Row bassRow = sheet.createRow(rowIdx++); |
| | | bassRow.setHeightInPoints(24f); |
| | |
| | | if (product == null || StringUtils.isEmpty(product.getProductName())) { |
| | | continue; |
| | | } |
| | | if (isInstrumentProduct(product.getProductName())) { |
| | | // 乐器类产品归到“成品部门”sheet,不在这里作为琴盒部等的列 |
| | | if (MajorCategoryEnum.match(product.getProductName()) != null) { |
| | | continue; |
| | | } |
| | | String key = product.getProductName(); |
| | |
| | | return java.math.BigDecimal.ZERO; |
| | | } |
| | | java.math.BigDecimal quantity = item.getQuantity() == null ? java.math.BigDecimal.ZERO : item.getQuantity(); |
| | | String productName = item.getProductName(); |
| | | if ("小提琴".equals(productName)) { |
| | | return operation.getViolinFactor() == null ? java.math.BigDecimal.ZERO : quantity.multiply(operation.getViolinFactor()); |
| | | } |
| | | if ("大提琴".equals(productName)) { |
| | | return operation.getViolaFactor() == null ? java.math.BigDecimal.ZERO : quantity.multiply(operation.getViolaFactor()); |
| | | } |
| | | if ("贝斯".equals(productName)) { |
| | | return operation.getBassFactor() == null ? java.math.BigDecimal.ZERO : quantity.multiply(operation.getBassFactor()); |
| | | } |
| | | MajorCategoryEnum category = MajorCategoryEnum.of(item.getMajorCategory()); |
| | | if (category == null) { |
| | | return java.math.BigDecimal.ZERO; |
| | | } |
| | | switch (category) { |
| | | case VIOLIN: |
| | | return operation.getViolinFactor() == null ? java.math.BigDecimal.ZERO : quantity.multiply(operation.getViolinFactor()); |
| | | case VIOLA: |
| | | return operation.getMidViolinFactor() == null ? java.math.BigDecimal.ZERO : quantity.multiply(operation.getMidViolinFactor()); |
| | | case CELLO: |
| | | // violaFactor 的列名沿用了 viola(中提琴),历史语义实为【大提琴】系数,勿改 |
| | | return operation.getViolaFactor() == null ? java.math.BigDecimal.ZERO : quantity.multiply(operation.getViolaFactor()); |
| | | case BASS: |
| | | return operation.getBassFactor() == null ? java.math.BigDecimal.ZERO : quantity.multiply(operation.getBassFactor()); |
| | | default: |
| | | return java.math.BigDecimal.ZERO; |
| | | } |
| | | } |
| | | |
| | | private Map<String, java.math.BigDecimal> buildStandardQuantityMap(List<String> operationNames) { |
| | | Map<String, java.math.BigDecimal> map = new LinkedHashMap<>(); |