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 @@
+ :disabled="scope.row.amountLeft===0" size="mini"
+ :max="scope.row.amountLeft" controls-position="right">
- {{scope.row.amount - scope.row.amountAlready}}
+ {{scope.row.amountLeft}}
@@ -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 @@
+ :disabled="scope.row.amountLeft===0" size="mini"
+ :max="scope.row.amountLeft" controls-position="right">
- {{scope.row.amount - scope.row.amountAlready}}
+ {{scope.row.amountLeft}}
@@ -521,15 +521,15 @@
+ :disabled="scope.row.amountLeft===0" size="mini"
+ :max="scope.row.amountLeft" controls-position="right">
- {{scope.row.amount - scope.row.amountAlready}}
+ {{scope.row.amountLeft}}
@@ -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
+ }
}
}
}