From c09d100111702fc9eb69d64adc24188b9136b074 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Thu, 5 Jan 2023 16:36:50 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=87=87=E8=B4=AD=E5=90=88?= =?UTF-8?q?=E5=90=8C=E6=B5=81=E7=A8=8B=E9=A2=84=E7=AE=97=E9=87=87=E8=B4=AD?= =?UTF-8?q?=E6=98=8E=E7=BB=86=E7=9A=84=E6=95=B0=E9=87=8F=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=EF=BC=8C=E6=9F=A5=E8=AF=A2=E7=AC=A6=E5=90=88=E8=A7=84=E5=AE=9A?= =?UTF-8?q?=E7=9A=84=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/backend/ProcessController.java | 71 ++++++++------- .../model/process/BudgetPurchaseAmount.java | 16 ++-- .../work/model/process/ProjectProcess.java | 2 +- .../work/model/process/QueryProject.java | 1 + .../work/service/ProjectProcessService.java | 87 ++++++++++++------- src/main/resources/sql/2.0.sql | 23 +++-- .../admin/business/process-detail.ftl | 8 +- .../templates/admin/business/process-edit.ftl | 51 ++++++----- .../templates/admin/business/process-new.ftl | 63 +++++++------- 9 files changed, 191 insertions(+), 131 deletions(-) diff --git a/src/main/java/cn/palmte/work/controller/backend/ProcessController.java b/src/main/java/cn/palmte/work/controller/backend/ProcessController.java index 11ea8c5..1352815 100644 --- a/src/main/java/cn/palmte/work/controller/backend/ProcessController.java +++ b/src/main/java/cn/palmte/work/controller/backend/ProcessController.java @@ -41,6 +41,7 @@ import java.util.Objects; import java.util.stream.Collectors; import javax.persistence.EntityManager; +import javax.persistence.Query; import javax.persistence.TypedQuery; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Predicate; @@ -442,9 +443,7 @@ public class ProcessController { // 草稿模式也不允许为空 (基础数据) Assert.notNull(amountForm.amount, "合同明细填写不完整"); Assert.notNull(amountForm.budgetCostId, "合同明细填写不完整"); - - // 已经采购的数量 要么是数据库存在的值要么是0 ,数据库获取已经采购数目 - BigDecimal amountAlready = processService.getAmountAlready(amountForm.budgetCostId); + Assert.notNull(amountForm.amountCurrent, "合同明细填写不完整"); // 新建 BudgetPurchaseAmount purchaseAmount = new BudgetPurchaseAmount(); @@ -453,20 +452,10 @@ public class ProcessController { purchaseAmount.setAmount(amountForm.amount); purchaseAmount.setBudgetCostId(amountForm.budgetCostId); purchaseAmount.setAmountCurrent(amountForm.amountCurrent); - // 更新到数据库 - purchaseAmount.setAmountAlready(amountAlready); - // TODO 提交模式才计算 剩余 if (form.getStatus() == ProcessStatus.to_be_audit) { - // 当前的必须填写 - Assert.notNull(amountForm.amountCurrent, "合同明细填写不完整"); - - // 提交的时候 更新(计算)已经采购的数量 = 已经采购的数量 + 本次采购数量 - amountAlready = amountAlready.add(amountForm.amountCurrent); - purchaseAmount.setAmountAlready(amountAlready); // 更新数据库 - // amountForm.amount 和数据库的一致 剩余的未采购数量 = 总数 - 已经采购数量 - BigDecimal amountLeft = amountForm.amount.subtract(amountAlready); - purchaseAmount.setAmountLeft(amountLeft); + // 提交时该次数量条目生效,撤回的时候 取消该状态 + purchaseAmount.setSubmit(true); } entityManager.persist(purchaseAmount); @@ -556,13 +545,10 @@ public class ProcessController { if (!CollectionUtils.isEmpty(form.purchaseAmount)) { for (BudgetPurchaseAmountModel amountForm : form.purchaseAmount) { // 草稿模式也不允许为空 (基础数据), 更新ID不能为空 - Assert.notNull(amountForm.amountId, "合同明细填写不完整"); Assert.notNull(amountForm.amount, "合同明细填写不完整"); + Assert.notNull(amountForm.amountId, "合同明细填写不完整"); Assert.notNull(amountForm.budgetCostId, "合同明细填写不完整"); - // 已经采购的数量 要么是数据库存在的值要么是0 ,数据库获取已经采购数目 - BigDecimal amountAlready = processService.getAmountAlready(amountForm.budgetCostId); - // 新建 BudgetPurchaseAmount purchaseAmount = new BudgetPurchaseAmount(); purchaseAmount.setId(amountForm.amountId); @@ -571,20 +557,12 @@ public class ProcessController { purchaseAmount.setAmount(amountForm.amount); purchaseAmount.setBudgetCostId(amountForm.budgetCostId); purchaseAmount.setAmountCurrent(amountForm.amountCurrent); - // 更新到数据库 - purchaseAmount.setAmountAlready(amountAlready); // TODO 提交模式才计算 剩余 if (form.getStatus() == ProcessStatus.to_be_audit) { // 当前的必须填写 Assert.notNull(amountForm.amountCurrent, "合同明细填写不完整"); - - // 提交的时候 更新(计算)已经采购的数量 = 已经采购的数量 + 本次采购数量 - amountAlready = amountAlready.add(amountForm.amountCurrent); - purchaseAmount.setAmountAlready(amountAlready); // 更新数据库 - // amountForm.amount 和数据库的一致 剩余的未采购数量 = 总数 - 已经采购数量 - BigDecimal amountLeft = amountForm.amount.subtract(amountAlready); - purchaseAmount.setAmountLeft(amountLeft); + purchaseAmount.setSubmit(true); } entityManager.merge(purchaseAmount); @@ -733,13 +711,42 @@ public class ProcessController { @ResponseBody @DeleteMapping("/{id}") + @Transactional public void delete(@PathVariable("id") int id) { - Admin admin = getLoginUser(); - Integer applyUserId = admin.getId(); - int update = jdbcTemplate.update("delete from project_process where id =? and apply_person_id=?", id, applyUserId); - if (update != 1) { + ProjectProcess process = obtainProjectProcess(id); + Integer applyUserId = getLoginUser().getId(); + if (!Objects.equals(process.getApplyPersonId(), applyUserId)) { throw ErrorMessageException.failed("删除的流程不存在或者不属于自己"); } + + if (process.getProcessType() == ProcessType.sale_contract) { + Query query = entityManager.createQuery("delete from SaleContract where processId=:processId"); + query.setParameter("processId", id); + query.executeUpdate(); + } + else if (process.getProcessType() == ProcessType.procurement_contract) { + Query query = entityManager.createQuery("delete from ProcurementContract where processId=:processId"); + query.setParameter("processId", id); + query.executeUpdate(); + + query = entityManager.createQuery("delete from SupplierMaterial where processId=:processId"); + query.setParameter("processId", id); + query.executeUpdate(); + + query = entityManager.createQuery("delete from BudgetPurchaseAmount where processId=:processId"); + query.setParameter("processId", id); + query.executeUpdate(); + + query = entityManager.createQuery("delete from BudgetPurchaseDetail where processId=:processId"); + query.setParameter("processId", id); + query.executeUpdate(); + + } + + Query query = entityManager.createQuery("delete from ProjectProcess where id=:processId"); + query.setParameter("processId", id); + query.executeUpdate(); + } /** diff --git a/src/main/java/cn/palmte/work/model/process/BudgetPurchaseAmount.java b/src/main/java/cn/palmte/work/model/process/BudgetPurchaseAmount.java index 3b55d35..377e084 100644 --- a/src/main/java/cn/palmte/work/model/process/BudgetPurchaseAmount.java +++ b/src/main/java/cn/palmte/work/model/process/BudgetPurchaseAmount.java @@ -10,6 +10,7 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; +import javax.persistence.Transient; import lombok.Data; @@ -17,6 +18,9 @@ import lombok.Data; * 采购合同流程预算采购明细的数量记录 *

* 一个 BudgetPurchaseAmount 对应 多个 BudgetPurchaseDetail + *

+ * 相同的 budgetCostId 下的 amountAlready amountLeft 分别都一样, + * amountCurrent 代表当前的提交审核后本次采购的数目 * * @author Harry Yang * @since 2.0 2022/12/28 14:15 @@ -36,14 +40,11 @@ public class BudgetPurchaseAmount implements Serializable { // 所有的 private BigDecimal amount; - // 已采购数量 - private BigDecimal amountAlready; - // '本次采购数量' private BigDecimal amountCurrent; - // 未采购数量 - private BigDecimal amountLeft; + // 该流程是否提交,提交了才计算到已采购数量 + private Boolean submit; // 流程ID private Integer processId; @@ -54,4 +55,9 @@ public class BudgetPurchaseAmount implements Serializable { // 成本ID private Integer budgetCostId; + @Transient + public boolean isSubmitted() { + return submit != null && submit; + } + } diff --git a/src/main/java/cn/palmte/work/model/process/ProjectProcess.java b/src/main/java/cn/palmte/work/model/process/ProjectProcess.java index ab3c84a..8ad8030 100644 --- a/src/main/java/cn/palmte/work/model/process/ProjectProcess.java +++ b/src/main/java/cn/palmte/work/model/process/ProjectProcess.java @@ -63,7 +63,7 @@ public class ProjectProcess implements Serializable { // 申请部门 部门1,部门2,部门3 (逗号分割) private String applyDept; - // 申请部门ID(逗号分割) + // 申请部门ID(逗号分割) find_in_set private String applyDeptId; // 申请部门领导ID diff --git a/src/main/java/cn/palmte/work/model/process/QueryProject.java b/src/main/java/cn/palmte/work/model/process/QueryProject.java index 6ad345f..cfb5ab0 100644 --- a/src/main/java/cn/palmte/work/model/process/QueryProject.java +++ b/src/main/java/cn/palmte/work/model/process/QueryProject.java @@ -17,4 +17,5 @@ public class QueryProject { private ProcessType processType; + private Integer creatorId; } diff --git a/src/main/java/cn/palmte/work/service/ProjectProcessService.java b/src/main/java/cn/palmte/work/service/ProjectProcessService.java index d3d521a..bd6c58d 100644 --- a/src/main/java/cn/palmte/work/service/ProjectProcessService.java +++ b/src/main/java/cn/palmte/work/service/ProjectProcessService.java @@ -5,7 +5,10 @@ import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import java.math.BigDecimal; import java.sql.PreparedStatement; @@ -16,13 +19,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.function.Predicate; import java.util.stream.Collectors; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.TypedQuery; +import cn.palmte.work.ErrorMessageException; import cn.palmte.work.config.activiti.ActConstant; import cn.palmte.work.config.activiti.ActProjectTypeEnum; import cn.palmte.work.model.Admin; @@ -30,7 +33,6 @@ import cn.palmte.work.model.AdminRepository; import cn.palmte.work.model.Dept; import cn.palmte.work.model.DeptRepository; import cn.palmte.work.model.ProcurementType; -import cn.palmte.work.model.ProcurementTypeRepository; import cn.palmte.work.model.Project; import cn.palmte.work.model.ProjectBudgetCostDetail; import cn.palmte.work.model.ProjectRepository; @@ -59,13 +61,12 @@ public class ProjectProcessService { private final JdbcTemplate jdbcTemplate; private final EntityManager entityManager; - private final ProjectInstanceService projectInstanceService; - private final ProjectRepository projectRepository; private final ProjectService projectService; + private final ProjectInstanceService projectInstanceService; private final DeptRepository deptRepository; private final AdminRepository userRepository; - private final ProcurementTypeRepository procurementTypeRepository; + private final ProjectRepository projectRepository; public List queryProjects(String q, ProcessType processType, Admin loginUser) { List projects = Collections.emptyList(); @@ -73,43 +74,40 @@ public class ProjectProcessService { projects = projectRepository.findBudgetPassedProjects(q); } else if (processType == ProcessType.sale_contract) { - List queryProjects = jdbcTemplate.query("select distinct p.id, p.name, p.project_no projectNo, pp.process_type processType " + + List queryProjects = jdbcTemplate.query( + "select distinct p.id, p.name, p.project_no projectNo, pp.process_type processType,p.creator_id creatorId " + " from project p left join project_process pp on p.id = pp.project_id " + "where (p.`status` > 5 or (p.`status` = 5 and p.approve_status_budget = 2)) " + " and (p.`project_no` like concat('%', ?, '%') or p.`name` like concat('%', ?, '%'))", new Object[] { q, q }, BeanPropertyRowMapper.newInstance(QueryProject.class)); + MultiValueMap idMap = new LinkedMultiValueMap<>(); + + for (QueryProject queryProject : queryProjects) { + idMap.computeIfAbsent(queryProject.getId(), s -> new ArrayList<>()) + .add(queryProject); + } + projects = queryProjects.stream().filter(queryProject -> { - ProcessType processTypeToTest = queryProject.getProcessType(); - if (processTypeToTest == null) { - return true; - } - else { - // 如果已经存在销售合同,就排除 - if (processTypeToTest == ProcessType.sale_contract) { - return false; - } - else { - // 一个项目可能有采购合同,但是要去判断是不是存在销售合同,存在就排除 - Predicate predicate = query -> { - return Objects.equals(query.getId(), queryProject.getId()) - && query.getProcessType() == ProcessType.sale_contract; - }; - return queryProjects.stream().noneMatch(predicate); - } - } + List projectList = idMap.get(queryProject.getId()); + return projectList.stream().noneMatch(this::isSaleContract); }).map(queryProject -> { Project project = new Project(); project.setId(queryProject.getId()); project.setName(queryProject.getName()); project.setProjectNo(queryProject.getProjectNo()); + project.setCreatorId(queryProject.getCreatorId()); return project; }).collect(Collectors.toList()); } return projectService.visibleProjects(projects, loginUser); } + private boolean isSaleContract(QueryProject queryProject) { + return queryProject.getProcessType() == ProcessType.sale_contract; + } + @Data static class DeptReturnValue { @@ -229,9 +227,19 @@ public class ProjectProcessService { * * @param processId 撤回的ID */ + @Transactional public void revoke(int processId) { jdbcTemplate.update("update project_process set current_audit=?, current_audit_id=?, `status`=? where id=?", null, null, ProcessStatus.draft.getValue(), processId); + ProjectProcess process = obtain(processId); + if (process.getProcessType() == ProcessType.procurement_contract) { + // 撤回的时候要删除对应的采购数量 + List purchaseAmount = getProcessPurchaseAmount(processId); + for (BudgetPurchaseAmount amount : purchaseAmount) { + amount.setSubmit(false); + entityManager.merge(amount); + } + } } /** @@ -289,13 +297,15 @@ public class ProjectProcessService { detail.setPurchaseDetails(purchaseDetails); detail.setBudgetCostId(costDetail.getId()); detail.setCategory(getCategory(costDetail)); - detail.setAmountLeft(amount.getAmountLeft()); - BigDecimal amountAlready = amount.getAmountAlready(); - if (amountAlready == null) { - amountAlready = getAmountAlready(amount.getBudgetCostId()); - } + detail.setAmountId(amountId); + BigDecimal amountAlready = getAmountAlready(amount.getBudgetCostId()); detail.setAmountAlready(amountAlready); + BigDecimal allAmount = amount.getAmount(); + if (allAmount == null) { + allAmount = costDetail.getAmount(); + } + detail.setAmountLeft(allAmount.subtract(amountAlready)); detail.setAmountCurrent(amount.getAmountCurrent()); ret.add(detail); } @@ -309,9 +319,12 @@ public class ProjectProcessService { BigDecimal amountAlready = getAmountAlready(costDetail.getId()); detail.setAmountAlready(amountAlready); + BigDecimal allAmount = costDetail.getAmount(); + detail.setAmountLeft(allAmount.subtract(amountAlready)); + detail.setAmount(allAmount); + // TODO 查询太频繁 detail.setCategory(getCategory(costDetail)); - detail.setBudgetCostId(costDetail.getId()); ret.add(detail); } @@ -389,9 +402,13 @@ public class ProjectProcessService { return amountQuery.getResultList(); } + /** + * 计算当前已经提交的采购数量 + */ public BigDecimal getAmountAlready(int budgetCostId) { return getPurchaseAmountList(budgetCostId).stream() - .map(BudgetPurchaseAmount::getAmountAlready) + .filter(BudgetPurchaseAmount::isSubmitted) + .map(BudgetPurchaseAmount::getAmountCurrent) .filter(Objects::nonNull) .reduce(BigDecimal.ZERO, BigDecimal::add); } @@ -400,6 +417,14 @@ public class ProjectProcessService { return entityManager.find(ProjectProcess.class, id); } + public ProjectProcess obtain(int id) { + ProjectProcess projectProcess = getById(id); + if (projectProcess == null) { + throw ErrorMessageException.failed("流程不存在"); + } + return projectProcess; + } + /** * 更新 销售合同 的 质保期 */ diff --git a/src/main/resources/sql/2.0.sql b/src/main/resources/sql/2.0.sql index 5028cca..1444a65 100644 --- a/src/main/resources/sql/2.0.sql +++ b/src/main/resources/sql/2.0.sql @@ -72,14 +72,12 @@ create table procurement_contract_supplier_material create table procurement_contract_budget_purchase_amount ( id int auto_increment primary key comment 'ID', - amount decimal(11, 2) comment '总共要采购数量', - amount_current decimal(11, 2) comment '本次采购数量', - amount_already decimal(11, 2) comment '已采购数量', - amount_left decimal(11, 2) comment '未采购数量', - - process_id int not null comment '流程ID', - contract_id int not null comment '采购合同ID', - budget_cost_id int not null comment '成本ID', + amount decimal(11, 2) not null comment '总共要采购数量', + amount_current decimal(11, 2) not null comment '本次采购数量', + submit bit default 0 not null comment '该流程是否提交,提交了才计算到已采购数量', + process_id int not null comment '流程ID', + contract_id int not null comment '采购合同ID', + budget_cost_id int not null comment '成本ID', UNIQUE key (process_id, budget_cost_id) ) comment '采购合同流程预算采购明细的数量记录'; @@ -103,4 +101,11 @@ create table procurement_contract_budget_purchase_detail amount_id int not null comment '记录数量表的ID', budget_cost_id int not null comment '成本ID' -) comment '采购合同流程预算采购明细的详情'; \ No newline at end of file +) comment '采购合同流程预算采购明细的详情'; + +alter table procurement_contract_budget_purchase_amount + drop amount_left; + +alter table procurement_contract_budget_purchase_amount + add submit bit default 0 not null comment '该流程是否提交,提交了才计算到已采购数量' +; \ No newline at end of file diff --git a/src/main/resources/templates/admin/business/process-detail.ftl b/src/main/resources/templates/admin/business/process-detail.ftl index e30bade..a09fd48 100644 --- a/src/main/resources/templates/admin/business/process-detail.ftl +++ b/src/main/resources/templates/admin/business/process-detail.ftl @@ -126,23 +126,23 @@ {{contract.paymentTerms|ellipsis}} -

{{contract.paymentTerms}}
+ + {{contract.paymentTerms|ellipsis}} -
{{contract.paymentTerms}}
+
{{process.remark|ellipsis}} -
{{process.remark}}
+
- diff --git a/src/main/resources/templates/admin/business/process-edit.ftl b/src/main/resources/templates/admin/business/process-edit.ftl index dd27c8c..c48ed8e 100644 --- a/src/main/resources/templates/admin/business/process-edit.ftl +++ b/src/main/resources/templates/admin/business/process-edit.ftl @@ -402,15 +402,15 @@ @@ -504,6 +504,15 @@ "procurementAmount" ] + const supplierMaterialProperties = [ + "companyName", + "totalAmount", + "serviceTerms", + "paymentTerms", + "taxRate", + "attachment", + ] + const fileUploadSuffix = [ ".pdf", ".doc", ".docx", @@ -887,30 +896,32 @@ return false } + const isPropertyEmpty = value => { + if (typeof value === 'string') { + return isBlank(value) + } + else if (value instanceof Array) { + return value.length === 0 + } + return value != null || value !== undefined + } + + const containsEmpty = detail => { + return isNotEmpty(supplierMaterialProperties.filter(property => isPropertyEmpty(detail[property]))) + } + let idx = 0 - for (const item in supplierMaterialsForm) { + for (const item of supplierMaterialsForm) { idx++ if (isEmptyObject(item)) { this.$message.error("供应商比选材料第'" + idx + "'行未填写,请检查表单") return false } - for (const [key, value] of Object.entries(item)) { - if (value) { - if (typeof value === 'string') { - if (isBlank(value)) { - this.$message.error("供应商比选材料第'" + idx + "'行有数据未填写,请检查表单") - return false - } - } - } - else { - // 没有值 - if (key !== 'remark') { - this.$message.error("供应商比选材料第'" + idx + "'行有数据未填写,请检查表单") - } - } - } + if (containsEmpty(item)) { + this.$message.error("供应商比选材料第'" + idx + "'行有数据未填写,请检查表单") + return false + } } } } diff --git a/src/main/resources/templates/admin/business/process-new.ftl b/src/main/resources/templates/admin/business/process-new.ftl index c78fd34..765b34f 100644 --- a/src/main/resources/templates/admin/business/process-new.ftl +++ b/src/main/resources/templates/admin/business/process-new.ftl @@ -132,15 +132,15 @@ @@ -521,15 +521,15 @@ @@ -622,6 +622,15 @@ "procurementAmount" ] + const supplierMaterialProperties = [ + "companyName", + "totalAmount", + "serviceTerms", + "paymentTerms", + "taxRate", + "attachment", + ] + const fileUploadSuffix = [ ".pdf", ".doc", ".docx", @@ -1043,36 +1052,32 @@ return false } + const isPropertyEmpty = value => { + if (typeof value === 'string') { + return isBlank(value) + } + else if (value instanceof Array) { + return value.length === 0 + } + return value != null || value !== undefined + } + + const containsEmpty = detail => { + return isNotEmpty(supplierMaterialProperties.filter(property => isPropertyEmpty(detail[property]))) + } + let idx = 0 - for (const item in supplierMaterialsForm) { + for (const item of supplierMaterialsForm) { idx++ if (isEmptyObject(item)) { this.$message.error("供应商比选材料第'" + idx + "'行未填写,请检查表单") return false } - for (const [key, value] of Object.entries(item)) { - if (value) { - if (typeof value === 'string') { - if (isBlank(value)) { - this.$message.error("供应商比选材料第'" + idx + "'行有数据未填写,请检查表单") - return false - } - } - else if (value instanceof Array) { - if (value.length === 0) { - this.$message.error("供应商比选材料第'" + idx + "'行有数据未填写,请检查表单") - return false - } - } - } - else { - // 没有值 - if (key !== 'remark') { - this.$message.error("供应商比选材料第'" + idx + "'行有数据未填写,请检查表单") - } - } - } + if (containsEmpty(item)) { + this.$message.error("供应商比选材料第'" + idx + "'行有数据未填写,请检查表单") + return false + } } } }