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 519aa8e..9eaed44 100644 --- a/src/main/java/cn/palmte/work/controller/backend/ProcessController.java +++ b/src/main/java/cn/palmte/work/controller/backend/ProcessController.java @@ -1,6 +1,7 @@ package cn.palmte.work.controller.backend; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; import org.springframework.beans.BeanUtils; import org.springframework.data.domain.Example; @@ -36,6 +37,7 @@ import java.util.Map; import java.util.stream.Collectors; import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; import javax.validation.Valid; import javax.validation.constraints.NotNull; @@ -50,6 +52,7 @@ import cn.palmte.work.model.enums.ProcessStatus; import cn.palmte.work.model.enums.ProcessType; import cn.palmte.work.model.enums.ProjectType; import cn.palmte.work.model.enums.SealType; +import cn.palmte.work.model.process.ProcessAttachment; import cn.palmte.work.model.process.ProcurementContract; import cn.palmte.work.model.process.ProjectProcess; import cn.palmte.work.model.process.ProjectProcessRepository; @@ -59,6 +62,8 @@ import cn.palmte.work.model.process.form.ProcessQueryForm; import cn.palmte.work.model.process.form.SaleContractDetailForm; import cn.palmte.work.model.process.form.SaleContractProcessForm; import cn.palmte.work.service.ProjectBudgetService; +import cn.palmte.work.service.ProjectInstanceService; +import cn.palmte.work.service.ProjectProcessService; import cn.palmte.work.utils.InterfaceUtil; import lombok.Builder; import lombok.Data; @@ -82,6 +87,8 @@ public class ProcessController { private final EntityManager entityManager; private final ProjectProcessRepository repository; + private final ProjectInstanceService projectInstanceService; + private final ProjectProcessService processService; static class FormMetadata { // 部门 @@ -132,8 +139,41 @@ public class ProcessController { return "/admin/business/process-review"; } - @GetMapping("/detail") - public String detail(Model model) { + @GetMapping("/detail/{id}") + public String detail(@PathVariable int id, Model model) { + ProjectProcess process = repository.findOne(id); + model.addAttribute("process", process); + + Project project = projectRepository.findById(process.getProjectId()); + model.addAttribute("project", project); + model.addAttribute("projectType", Enumerable.of(ProjectType.class, project.getType()).getDescription()); + model.addAttribute("cooperationType", Enumerable.of(CooperationType.class, project.getCooperateType()).getDescription()); + List attachments = JSONArray.parseArray(process.getAttachmentUri(), ProcessAttachment.class); + model.addAttribute("attachments", attachments); + + if (process.getProcessType() != null) { + switch (process.getProcessType()) { + case sale_contract: { + TypedQuery query = entityManager.createQuery( + "from SaleContract where processId=:processId", SaleContract.class); + query.setParameter("processId", process.getId()); + SaleContract contract = query.getSingleResult(); + model.addAttribute("contract", contract); + break; + } + case business_procurement: { + TypedQuery query = entityManager.createQuery( + "from ProcurementContract where processId=:processId", ProcurementContract.class); + query.setParameter("processId", process.getId()); + ProcurementContract contract = query.getSingleResult(); + model.addAttribute("contract", contract); + break; + } + default: + throw new UnsupportedOperationException("还不支持"); + } + } + return "/admin/business/process-detail"; } @@ -170,6 +210,8 @@ public class ProcessController { // 合同金额 public BigDecimal contractAmount; + public String terminalCustomer; + public List incomeDetails; // FIXME 垫资 @@ -198,6 +240,7 @@ public class ProcessController { .projectNo(project.getProjectNo()) .applyPersonName(admin.getRealName()) .contractAmount(project.getContractAmount()) + .terminalCustomer(project.getTerminalCustomer()) .projectType(Enumerable.of(ProjectType.class, project.getType()).getDescription()) .cooperationType(Enumerable.of(CooperationType.class, project.getCooperateType()).getDescription()) .build(); @@ -208,15 +251,15 @@ public class ProcessController { @ResponseBody @PostMapping @Transactional - public void post(@RequestBody @Valid SaleContractProcessForm form) { + public void post(@RequestBody @Valid SaleContractProcessForm form) throws Exception { ProjectProcess entity = new ProjectProcess(); - BeanUtils.copyProperties(form, entity, "sealTypes", "applyDate", "applyDept", "attachmentUri"); + BeanUtils.copyProperties(form, entity, "sealTypes", "applyDate", "applyDept", "attachments"); entity.setApplyDate(LocalDate.parse(form.getApplyDate(), formatter)); entity.setSealTypes(SealTypeArray.of(form.getSealTypes())); entity.setApplyDept(String.join(",", form.getApplyDept())); Admin admin = InterfaceUtil.getAdmin(); entity.setApplyPersonId(admin.getId()); - entity.setAttachmentUri(JSON.toJSONString(form.getAttachmentUri())); + entity.setAttachmentUri(JSON.toJSONString(form.getAttachments())); if (entity.getStatus() == null) { entity.setStatus(ProcessStatus.to_be_audit); @@ -224,17 +267,34 @@ public class ProcessController { entityManager.persist(entity); + HashMap variables = new HashMap<>(); if (entity.getProcessType() != null) { switch (entity.getProcessType()) { case sale_contract: SaleContract saleContract = SaleContract.from(form); saleContract.setProcessId(entity.getId()); entityManager.persist(saleContract); + variables.put("contract", saleContract); break; case business_procurement: ProcurementContract procurementContract = ProcurementContract.from(form); procurementContract.setProcessId(entity.getId()); entityManager.persist(procurementContract); + variables.put("contract", procurementContract); + break; + default: + throw new UnsupportedOperationException("还不支持"); + } + } + + if (entity.getStatus() == ProcessStatus.to_be_audit) { + variables.put("process", entity); + switch (entity.getProcessType()) { + case sale_contract: + projectInstanceService.startSaleContractProcess(entity.getId(), variables); + break; + case business_procurement: + projectInstanceService.startBusinessPurchaseProcess(entity.getId(), variables); break; default: throw new UnsupportedOperationException("还不支持"); @@ -302,21 +362,25 @@ public class ProcessController { @ResponseBody @PostMapping("/audit") public void audit(@RequestBody @Valid AuditForm form) { - - } - - @ResponseBody - @GetMapping("/detail/{id}") - public ProjectProcess get(@PathVariable("id") int id, Model model) { -// model.addAttribute(); - return entityManager.find(ProjectProcess.class, id); + ProjectProcess process = repository.findOne(form.processId); + // 2-通过 3-不通过 + int approveType = form.processStatus == ProcessStatus.audit_passed ? 2 : + form.processStatus == ProcessStatus.audit_not_passed ? 3 : -1; + switch (process.getProcessType()) { + case business_procurement: + projectInstanceService.completeBusinessPurchaseTask(process.getId(), approveType, form.auditOpinion); + break; + case sale_contract: + projectInstanceService.completeSaleContractTask(process.getId(), approveType, form.auditOpinion); + break; + } } @ResponseBody @PostMapping("/revoke/{id}") public void revoke(@PathVariable("id") int id) { // TODO 发起申请的人,在第一个人还没审批的情况下可以撤回 - jdbcTemplate.update("update project_process set `status` =? where id =? ", ProcessStatus.draft.getValue(), id); + processService.updateProcessStatus(id, ProcessStatus.draft); } @ResponseBody diff --git a/src/main/java/cn/palmte/work/model/process/ProcessAttachment.java b/src/main/java/cn/palmte/work/model/process/ProcessAttachment.java new file mode 100644 index 0000000..1324a4f --- /dev/null +++ b/src/main/java/cn/palmte/work/model/process/ProcessAttachment.java @@ -0,0 +1,15 @@ +package cn.palmte.work.model.process; + +import lombok.Data; + +/** + * @author Harry Yang + * @since 2.0 2022/12/22 17:50 + */ +@Data +public class ProcessAttachment { + + private String name; + private String uri; + +} 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 da4a23d..2a7044b 100644 --- a/src/main/java/cn/palmte/work/model/process/ProjectProcess.java +++ b/src/main/java/cn/palmte/work/model/process/ProjectProcess.java @@ -79,6 +79,9 @@ public class ProjectProcess { // 当前审核人 private String currentAudit; + // 当前审核人ID + private String currentAuditId; + // 最后更新时间 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") diff --git a/src/main/java/cn/palmte/work/model/process/SealTypeArray.java b/src/main/java/cn/palmte/work/model/process/SealTypeArray.java index 0f90d38..9f0c150 100644 --- a/src/main/java/cn/palmte/work/model/process/SealTypeArray.java +++ b/src/main/java/cn/palmte/work/model/process/SealTypeArray.java @@ -5,6 +5,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import javax.persistence.Convert; @@ -37,6 +38,13 @@ public class SealTypeArray { this.sealTypes.addAll(sealTypes); } + @Override + public String toString() { + return sealTypes.stream() + .map(SealType::getDescription) + .collect(Collectors.joining(",")); + } + // public static SealTypeArray of(SealType... sealTypes) { diff --git a/src/main/java/cn/palmte/work/model/process/form/SaleContractProcessForm.java b/src/main/java/cn/palmte/work/model/process/form/SaleContractProcessForm.java index de25338..2bb95a6 100644 --- a/src/main/java/cn/palmte/work/model/process/form/SaleContractProcessForm.java +++ b/src/main/java/cn/palmte/work/model/process/form/SaleContractProcessForm.java @@ -8,6 +8,7 @@ import javax.validation.constraints.NotNull; import cn.palmte.work.model.enums.ProcessStatus; import cn.palmte.work.model.enums.ProcessType; import cn.palmte.work.model.enums.ProcurementMode; +import cn.palmte.work.model.process.ProcessAttachment; import lombok.Data; /** @@ -76,5 +77,5 @@ public class SaleContractProcessForm { private String supplierName; - private List attachmentUri; + private List attachments; } diff --git a/src/main/java/cn/palmte/work/service/ProjectProcessService.java b/src/main/java/cn/palmte/work/service/ProjectProcessService.java new file mode 100644 index 0000000..3a44f4c --- /dev/null +++ b/src/main/java/cn/palmte/work/service/ProjectProcessService.java @@ -0,0 +1,64 @@ +package cn.palmte.work.service; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; + +import cn.palmte.work.model.Admin; +import cn.palmte.work.model.enums.ProcessStatus; +import lombok.RequiredArgsConstructor; + +/** + * @author Harry Yang + * @since 2.0 2022/12/23 09:39 + */ +@Service +@RequiredArgsConstructor +public class ProjectProcessService { + + private final JdbcTemplate jdbcTemplate; + private final EntityManager entityManager; + + /** + * 更新流程 审批人,和状态 + * + * @param processId 流程Id + * @param auditId 审批人ID + * @param status 流程状态 可以为空,为空的时候不修改 + */ + public void updateAudit(int processId, ProcessStatus status, List auditId) { + String currentAudit = getCurrentAudit(auditId); + String currentAuditId = auditId.stream().map(String::valueOf).collect(Collectors.joining(",")); + if (status != null) { + if (!CollectionUtils.isEmpty(auditId)) { + jdbcTemplate.update( + "update project_process set current_audit=?,current_audit_id=?,status=? where id=?", currentAudit, currentAuditId, status.getValue(), processId); + } + } + else { + jdbcTemplate.update("update project_process set current_audit=?,current_audit_id=? where id=?", currentAudit, currentAuditId, processId); + } + } + + private String getCurrentAudit(List auditId) { + TypedQuery query = entityManager.createQuery("from Admin where id in (:ids)", Admin.class); + query.setParameter("ids", auditId); + List resultList = query.getResultList(); + return resultList.stream().map(Admin::getRealName) + .collect(Collectors.joining(",")); + } + + /** + * 只更新状态 + */ + public void updateProcessStatus(int processId, ProcessStatus status) { + jdbcTemplate.update("update project_process set `status`=? where id=?", status.getValue(), processId); + } + +} diff --git a/src/main/resources/sql/2.0.sql b/src/main/resources/sql/2.0.sql index 0d8511c..d4f36b9 100644 --- a/src/main/resources/sql/2.0.sql +++ b/src/main/resources/sql/2.0.sql @@ -22,6 +22,7 @@ create table project_process attachment_uri text null comment '附件 JSON Array', current_audit varchar(255) null comment '当前审核人', + current_audit_id varchar(255) null comment '当前审核人ID逗号分割', create_at datetime default CURRENT_TIMESTAMP comment '创建时间', last_update_at datetime default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP comment '最后更新时间' @@ -29,7 +30,7 @@ create table project_process ); alter table project_process - add attachment_uri text null comment '附件 JSON Array'; + modify current_audit_id varchar(255) null comment '当前审核人ID逗号分割'; # 采购合同 create table procurement_contract diff --git a/src/main/resources/templates/admin/business/process-completed.ftl b/src/main/resources/templates/admin/business/process-completed.ftl index 6518124..058f36e 100644 --- a/src/main/resources/templates/admin/business/process-completed.ftl +++ b/src/main/resources/templates/admin/business/process-completed.ftl @@ -96,7 +96,7 @@ {{scope.row.status | processStatus}} - + @@ -186,7 +186,7 @@ showDetail(row, scope) { console.log(row) console.log(scope) - + window.location = "${base}/process/detail/" + row.id; }, editProcess(row, scope) { diff --git a/src/main/resources/templates/admin/business/process-detail.ftl b/src/main/resources/templates/admin/business/process-detail.ftl new file mode 100644 index 0000000..2fc5f78 --- /dev/null +++ b/src/main/resources/templates/admin/business/process-detail.ftl @@ -0,0 +1,648 @@ +<#assign base=request.contextPath /> +<#import "../../common/defaultLayout.ftl" as defaultLayout> +<@defaultLayout.layout> +<#-- --> + + + +
+
+
+
业务应用 / + 流程详情
+
+ + <#-- 新增销售合同流程 --> + +
+ + +
+ + + ${process.projectNo} + + + + + ${process.projectTitle} + + + + + ${process.applyDate} + + + + ${projectType} + + + + ${cooperationType} + + +
+ +
+ + + ${process.applyDept} + + + + ${process.applyPersonName} + + + + ${process.applyDeptLeaderName} + + + + ${contract.applyPersonPhone} + + +
+ +
+ + + ${process.contractNo} + + + + ${process.contractName} + + + + ${project.contractAmount} + + +
+ +
+ + ${contract.clientName} + + + + ${project.terminalCustomer} + +
+ +
+ + ${process.sealTypes} + +
+ +
+ + + ${process.taxRate} + + + + ${process.isPrepaid} + + + + ${process.repaidAmount} + + + + ${process.budgetGrossMargin} + + +
+ +
+ + + ${process.paymentTerms} + + +
+ +
+ + + ${process.remark} + + +
+ +
+ + <#list attachments as attachment> + ${attachment.name} + + +
+ +
+ + <#-- --> + + 返回上一级 + 保存草稿 + 提交 + + +
+ +
+ +
+ + + + + + + + + diff --git a/src/main/resources/templates/admin/business/process-new.ftl b/src/main/resources/templates/admin/business/process-new.ftl index 142aff2..9092b3c 100644 --- a/src/main/resources/templates/admin/business/process-new.ftl +++ b/src/main/resources/templates/admin/business/process-new.ftl @@ -157,7 +157,7 @@ <#--TODO 最终用户名称--> - {{processForm.finalUserName}} + {{processForm.terminalCustomer}} 未选择项目 @@ -751,7 +751,10 @@ ...this.processForm, processType: 'sale_contract', projectTitle: this.projectTitle, - attachmentUri: fileList.map(file => (file.response.data.url)), + attachments: fileList.map(file => ({ + uri: file.response.data.url, + name: file.response.data.originName + })), incomeDetails: this.incomeDetails.map(detail => ({ id: detail.id, expirationDate: detail.expirationDate })) diff --git a/src/main/resources/templates/admin/business/process-review.ftl b/src/main/resources/templates/admin/business/process-review.ftl index 274c5da..570325a 100644 --- a/src/main/resources/templates/admin/business/process-review.ftl +++ b/src/main/resources/templates/admin/business/process-review.ftl @@ -85,7 +85,7 @@ {{scope.row.status | processStatus}}
- + @@ -175,7 +175,7 @@ showDetail(row, scope) { console.log(row) console.log(scope) - + window.location = "${base}/process/detail/" + row.id; }, auditProcess(row, scope) { this.auditForm = { diff --git a/src/test/java/cn/palmte/work/service/ProjectProcessServiceTests.java b/src/test/java/cn/palmte/work/service/ProjectProcessServiceTests.java new file mode 100644 index 0000000..6da307b --- /dev/null +++ b/src/test/java/cn/palmte/work/service/ProjectProcessServiceTests.java @@ -0,0 +1,27 @@ +package cn.palmte.work.service; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Arrays; + +/** + * @author Harry Yang + * @since 2.0 2022/12/23 10:42 + */ +@SpringBootTest +@RunWith(SpringRunner.class) +public class ProjectProcessServiceTests { + + @Autowired + ProjectProcessService projectProcessService; + +// @Test + public void testUpdateAudit() { + projectProcessService.updateAudit(2, null, Arrays.asList(93, 94)); + } + +} \ No newline at end of file