新增业务采购合同流程

master
Harry Yang 2022-12-26 18:03:45 +08:00
parent ba4675994d
commit f8ec2260f9
12 changed files with 249 additions and 114 deletions

View File

@ -63,7 +63,7 @@ import cn.palmte.work.model.process.SaleContract;
import cn.palmte.work.model.process.SealTypeArray;
import cn.palmte.work.model.process.form.ProcessQueryForm;
import cn.palmte.work.model.process.form.ProcessUpdateForm;
import cn.palmte.work.model.process.form.SaleContractProcessForm;
import cn.palmte.work.model.process.form.ProcessCreationForm;
import cn.palmte.work.service.ProjectBudgetService;
import cn.palmte.work.service.ProjectInstanceService;
import cn.palmte.work.service.ProjectProcessService;
@ -182,7 +182,7 @@ public class ProcessController {
model.addAttribute("contract", contract);
break;
}
case business_procurement: {
case procurement_contract: {
TypedQuery<ProcurementContract> query = entityManager.createQuery(
"from ProcurementContract where processId=:processId", ProcurementContract.class);
query.setParameter("processId", process.getId());
@ -296,7 +296,7 @@ public class ProcessController {
contract = processService.findSaleContract(process.getId());
break;
}
case business_procurement: {
case procurement_contract: {
contract = processService.findProcurementContract(process.getId());
break;
}
@ -329,7 +329,7 @@ public class ProcessController {
@ResponseBody
@PostMapping
@Transactional(rollbackFor = Exception.class)
public void post(@RequestBody @Valid SaleContractProcessForm form) throws Exception {
public void post(@RequestBody @Valid ProcessCreationForm form) throws Exception {
ProjectProcess entity = new ProjectProcess();
BeanUtils.copyProperties(form, entity, "sealTypes", "applyDate", "applyDept", "attachments");
entity.setApplyDate(LocalDate.parse(form.getApplyDate(), formatter));
@ -348,7 +348,7 @@ public class ProcessController {
saleContract.setProcessId(entity.getId());
entityManager.persist(saleContract);
break;
case business_procurement:
case procurement_contract:
ProcurementContract procurementContract = ProcurementContract.from(form);
procurementContract.setProcessId(entity.getId());
entityManager.persist(procurementContract);
@ -391,7 +391,7 @@ public class ProcessController {
entityManager.merge(contract);
break;
}
case business_procurement: {
case procurement_contract: {
ProcurementContract contract = processService.findProcurementContract(form.getId());
contract.setMode(form.getProcurementMode());
contract.setPaymentTerms(form.getPaymentTerms());
@ -456,7 +456,7 @@ public class ProcessController {
ActApproveTypeEnum approveType = form.processStatus == ProcessStatus.audit_passed ? ActApproveTypeEnum.APPROVAL_PASSED :
ActApproveTypeEnum.APPROVAL_UN_PASS;
switch (process.getProcessType()) {
case business_procurement:
case procurement_contract:
projectInstanceService.completeTaskByProjectId(process.getId(), ActProjectTypeEnum.BUSINESS_PURCHASE, approveType, form.auditOpinion);
break;
case sale_contract:

View File

@ -6,7 +6,7 @@ package cn.palmte.work.model.enums;
*/
public enum ProcessType implements Enumerable<String> {
sale_contract("销售合同流程"),
business_procurement("业务采购流程");
procurement_contract("业务采购流程");
private final String description;

View File

@ -11,7 +11,7 @@ import javax.persistence.Id;
import javax.persistence.Table;
import cn.palmte.work.model.enums.ProcurementMode;
import cn.palmte.work.model.process.form.SaleContractProcessForm;
import cn.palmte.work.model.process.form.ProcessCreationForm;
import lombok.Data;
/**
@ -39,7 +39,7 @@ public class ProcurementContract implements Serializable {
private Integer processId;
public static ProcurementContract from(SaleContractProcessForm form) {
public static ProcurementContract from(ProcessCreationForm form) {
ProcurementContract contract = new ProcurementContract();
contract.setMode(form.getProcurementMode());
contract.setPaymentTerms(form.getPaymentTerms());

View File

@ -10,7 +10,7 @@ import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import cn.palmte.work.model.process.form.SaleContractProcessForm;
import cn.palmte.work.model.process.form.ProcessCreationForm;
import lombok.Data;
/**
@ -40,7 +40,7 @@ public class SaleContract implements Serializable {
private Integer processId;
public static SaleContract from(SaleContractProcessForm form) {
public static SaleContract from(ProcessCreationForm form) {
SaleContract contract = new SaleContract();
contract.setClientName(form.getClientName());
contract.setPaymentTerms(form.getPaymentTerms());

View File

@ -0,0 +1,26 @@
package cn.palmte.work.model.process;
import javax.persistence.Entity;
import javax.persistence.Table;
import lombok.Data;
/**
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
* @since 2.0 2022/12/26 17:34
*/
@Data
@Entity
@Table(name = "project_process_supplier_material")
public class SupplierMaterial {
private String companyName;
private String totalAmount;
private String serviceTerms;
private String paymentTerms;
private String taxRate;
private String remark;
private ProcessAttachment attachment;
}

View File

@ -8,16 +8,17 @@ 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 cn.palmte.work.model.process.SupplierMaterial;
import lombok.Data;
/**
*
*
*
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
* @since 2.0 2022/12/14 17:05
*/
@Data
public class SaleContractProcessForm {
public class ProcessCreationForm {
@NotNull
private Integer projectId;
@ -71,6 +72,7 @@ public class SaleContractProcessForm {
private ProcessStatus status;
@NotNull(message = "流程类型不能为空")
private ProcessType processType;
private List<SaleContractDetailForm> incomeDetails;
@ -80,4 +82,7 @@ public class SaleContractProcessForm {
private String supplierName;
private List<ProcessAttachment> attachments;
private List<SupplierMaterial> supplierMaterials;
}

View File

@ -177,7 +177,7 @@ public class ProjectProcessService {
case sale_contract:
projectInstanceService.startProcessByProjectId(entity.getId(), ActProjectTypeEnum.SALE_CONTRACT, variables);
break;
case business_procurement:
case procurement_contract:
projectInstanceService.startProcessByProjectId(entity.getId(), ActProjectTypeEnum.BUSINESS_PURCHASE, variables);
break;
default:

View File

@ -51,5 +51,15 @@ create table sale_contract
payment_terms text null comment '收款条件',
process_id int null comment '流程ID'
);
create table procurement_contract_supplier_material
(
id int auto_increment primary key comment 'ID',
company_name varchar(255) null comment '公司名称',
total_amount varchar(255) null comment '合计金额',
service_terms varchar(255) null comment '服务条款',
payment_terms varchar(255) null comment '付款条件',
taxRate varchar(255) null comment '税率',
remark varchar(255) null comment '备注',
attachment varchar(1000) null comment '附件'
);

View File

@ -388,7 +388,7 @@
return this.mode === BUTTON
},
isBusinessProcurementContractProcessMode() {
return this.mode === newBusinessProcurementContractProcess
return this.mode === procurementContractProcess
},
isSalesContractProcessMode() {
return this.mode === saleContractProcess
@ -404,7 +404,7 @@
return "新增销售合同流程"
case saleContractDetail:
return "销售合同清单明细"
case newBusinessProcurementContractProcess:
case procurementContractProcess:
return "新增业务采购合同流程"
}
}

View File

@ -73,7 +73,7 @@
<el-form-item label="采购模式" v-if="isProcurementContractMode">
<el-select v-model="processForm.procurementMode" placeholder="请选择采购模式">
<#list procurementMode as item>
<el-option label="${item.description}" value="${sealType.name()}"></el-option>
<el-option label="${item.description}" value="${item.name()}"></el-option>
</#list>
</el-select>
</el-form-item>
@ -221,7 +221,6 @@
</el-form-item>
</div>
<div v-if="isProcurementContractMode">
供应商比选材料
<div class="am-u-sm-12 am-u-md-12" v-if="isProcurementContractMode">
@ -331,6 +330,7 @@
<script>
const newBusinessProcurementContractProcess = "newBusinessProcurementContractProcess"
const newBusinessProcurementContractDetail = "newBusinessProcurementContractDetail"
const saleContractProcess = "saleContractProcess"
const saleContractDetail = "saleContractDetail"
const BUTTON = "btn"

View File

@ -13,7 +13,7 @@
}
#newBusinessProcurementContractProcess {
#procurementContractProcess {
overflow: auto;
}
@ -40,6 +40,18 @@
.el-checkbox {
margin-right: 10px;
}
.supplierChoose {
margin-bottom: 20px;
}
.el-input-number--mini .el-input-number__decrease, .el-input-number--mini .el-input-number__increase {
height: 93%;
}
.el-input-number i {
line-height: unset;
}
</style>
<div class="admin-content" id="app">
@ -55,7 +67,7 @@
<img src="${base}/assets/process/销售合同流程@3x.png" width="36"/>
销售合同流程
</button>
<button type="button" class="am-btn" @click="businessProcurementProcessClick">
<button type="button" class="am-btn" @click="newProcurementContractClick">
<img src="${base}/assets/process/业务采购流程@3x.png" width="39"/>
业务采购流程
</button>
@ -78,8 +90,8 @@
<#-- 新增销售合同流程 -->
<div class="am-u-sm-12 am-u-md-12" v-if="isSalesContractProcessMode">
<el-form :inline="true" ref="saleContractProcessForm" :model="processForm" label-position="right" label-width="100px">
<div class="am-u-sm-12 am-u-md-12" v-if="isSalesContractMode || isProcurementContractMode">
<el-form :inline="true" ref="saleContractProcessForm" :model="processForm" label-position="right" label-width="110px">
<div class="am-form-inline">
<el-tooltip :disabled="projectSelected" effect="light" content="项目编号或名称,支持模糊查询" placement="top-end">
@ -103,7 +115,16 @@
<span v-else>未选择项目</span>
</el-form-item>
<el-form-item label="项目类型">
<el-form-item :rules="[{ required: true, message: '采购模式不能为空'}]"
label="采购模式" prop="procurementMode" v-if="isProcurementContractMode">
<el-select v-model="processForm.procurementMode" placeholder="请选择采购模式">
<#list procurementMode as item>
<el-option label="${item.description}" value="${item.name()}"></el-option>
</#list>
</el-select>
</el-form-item>
<el-form-item label="项目类型" v-if="isSalesContractMode">
<span v-if="projectSelected">{{processForm.projectType}}</span>
<span v-else>未选择项目</span>
</el-form-item>
@ -143,10 +164,17 @@
<el-input placeholder="请输入合同编号" v-model="processForm.contractNo"></el-input>
</el-form-item>
<el-form-item label="合同名称" :rules="[{ required: true, message: '合同名称不能为空'}]" prop="contractName">
<el-form-item :rules="[{ required: true, message: '合同名称不能为空'}]"
label="合同名称" prop="contractName" v-if="isSalesContractMode">
<el-input placeholder="请输入合同名称" v-model="processForm.contractName"></el-input>
</el-form-item>
<el-form-item v-if="isProcurementContractMode" label="采购合同名称"
:rules="[{ required: true, message: '采购合同名称不能为空'}]" prop="contractName">
<el-input placeholder="请输入采购合同名称" v-model="processForm.contractName"></el-input>
</el-form-item>
<el-form-item label="合同金额">
<span v-if="projectSelected">{{processForm.contractAmount}}元</span>
<span v-else>未选择项目</span>
@ -155,10 +183,14 @@
</div>
<div>
<el-form-item label="客户名称" :rules="[{ required: true, message: '客户名称不能为空'}]">
<el-form-item v-if="isSalesContractMode" label="客户名称" :rules="[{ required: true, message: '客户名称不能为空'}]">
<el-input placeholder="请输入客户名称" v-model="processForm.clientName"></el-input>
</el-form-item>
<el-form-item v-if="isProcurementContractMode" label="供应商名称" :rules="[{ required: true, message: '供应商名称不能为空'}]">
<el-input placeholder="请输入供应商" v-model="processForm.supplierName"></el-input>
</el-form-item>
<el-form-item label="最终用户名称">
<#--TODO 最终用户名称-->
<span v-if="projectSelected">{{processForm.terminalCustomer}}</span>
@ -204,10 +236,17 @@
</div>
<div>
<el-form-item label="收款条件" :rules="[{ required: true, message: '收款条件不能为空'}]" prop="paymentTerms">
<el-form-item v-if="isSalesContractMode" label="收款条件" :rules="[{ required: true, message: '收款条件不能为空'}]"
prop="paymentTerms">
<el-input type="textarea" :autosize="{ minRows: 3, maxRows: 10}" cols="90" maxlength="5000" show-word-limit
v-model="processForm.paymentTerms" placeholder="请输入收款条件限制5000字"></el-input>
</el-form-item>
<el-form-item v-if="isProcurementContractMode" label="付款条件" :rules="[{ required: true, message: '付款条件不能为空'}]"
prop="paymentTerms">
<el-input type="textarea" :autosize="{ minRows: 3, maxRows: 10}" cols="90" maxlength="5000" show-word-limit
v-model="processForm.paymentTerms" placeholder="请输入付款条件限制5000字"></el-input>
</el-form-item>
</div>
<div>
@ -235,20 +274,88 @@
<div>
<el-form-item label="合同清单明细">
<el-button type="text" @click="goToSaleContractDetail">详细清单</el-button>
<el-button type="text" @click="goToContractDetail">详细清单</el-button>
</el-form-item>
</div>
</el-form>
<#-- <el-row justify="space-around" type="flex" class="row-bg">-->
<el-row>
<div class="am-u-sm-12 am-u-md-12 supplierChoose" v-if="isProcurementContractMode">
<el-alert title="供应商比选材料" type="success" center :closable="false"></el-alert>
<el-table style="width: 100%" border :data="supplierMaterialsForm" v-model="supplierMaterialsForm" empty-text="暂无">
<el-table-column type="index" :index="1" label="序号" fixed></el-table-column>
<el-table-column prop="companyName" label="公司名称" width="180" align="center">
<template slot-scope="scope">
<el-input size="mini" placeholder="请输入公司名称" v-model="scope.row.companyName"></el-input>
</template>
</el-table-column>
<el-table-column prop="totalAmount" label="合计金额" width="180" align="center">
<template slot-scope="scope">
<el-input-number size="mini" :precision="2" :step="0.1" :max="100" :min="0"
v-model="scope.row.totalAmount"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="serviceTerms" label="服务条款" width="180" align="center">
<template slot-scope="scope">
<el-input size="mini" placeholder="请输入服务条款" v-model="scope.row.serviceTerms"></el-input>
</template>
</el-table-column>
<el-table-column prop="paymentTerms" label="付款条件" align="center">
<template slot-scope="scope">
<el-input size="mini" placeholder="请输入付款条件" v-model="scope.row.paymentTerms"></el-input>
</template>
</el-table-column>
<el-table-column prop="taxRate" label="税率(%" width="180" align="center">
<template slot-scope="scope">
<el-input-number size="mini" :precision="2" :step="0.1" :max="100" :min="0"
v-model="scope.row.taxRate"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" align="center">
<template slot-scope="scope">
<#--
<el-input type="textarea" size="mini" maxlength="100"
v-model="scope.row.remark" placeholder="请输入备注限制100字" cols="90"></el-input>
-->
<el-input size="mini" placeholder="请输入备注"
v-model="scope.row.remark"></el-input>
</template>
</el-table-column>
<el-table-column prop="attachment" label="附件" align="center" width="150">
<template slot-scope="scope">
<el-tag size="small" v-if="scope.row.attachment">
<a :href="scope.row.attachment.uri">
<i class="el-icon-document"></i> {{scope.row.attachment.name}}
</a>
</el-tag>
<el-upload v-else class="upload-demo"
action="${base}/file/upload"
name="files[]"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:on-success="handleFileUploaded"
:limit="1"
size="mini">
<el-button size="small" type="text">上传附件</el-button>
</el-upload>
</template>
</el-table-column>
</el-table>
<el-button type="primary" icon="el-icon-plus" circle size="mini" @click="addSupplierRow"
style="float: right;margin-top: 10px;"></el-button>
</div>
<el-row class="am-u-sm-12 am-u-md-12">
<el-button type="info" @click="goToHome">返回上一级</el-button>
<el-button type="primary" @click="saveDraft">保存草稿</el-button>
<el-button type="success" @click="submitForm">提交</el-button>
</el-row>
</div>
<#-- 销售合同清单明细 -->
@ -286,73 +393,9 @@
<#-- 新增业务采购合同流程 -->
<div class="am-u-sm-12 am-u-md-12" id="newBusinessProcurementContractProcess" v-if="isBusinessProcurementContractProcessMode">
<form role="form" id="newBusinessProcurementContractProcessForm">
<div class="am-form-inline">
<div class="am-form-group">
<label class="am-u-md-3 am-form-label">项目编号</label>
<el-autocomplete v-model="processForm.serialNumber" :fetch-suggestions="queryProject"
placeholder="请输入内容" @select="handleSelectProject"></el-autocomplete>
</div>
<div class="am-form-group">
<label class="am-u-md-3 am-form-label">项目标题</label>
<el-input placeholder="请输入内容" v-model="processForm.title" clearable></el-input>
</div>
<div class="am-form-group">
<label class="am-u-md-3 am-form-label">申请时间</label>
<input type="text" class="am-form-field am-u-sm-2" :value="processForm.time"/>
</div>
<div class="am-form-group">
<label class="am-u-sm-3 am-form-label">采购模式</label>
<input type="text" class="am-form-field" :value="processForm.time"/>
</div>
<div class="am-form-group">
<label class="am-u-md-3 am-form-label">合作类型</label>
<input type="text" class="am-form-field" :value="processForm.time"/>
</div>
</div>
<div class="am-form-inline">
<div class="am-form-group am-u-md-4">
<label class="am-form-label">申请部门</label>
<input type="text" class="am-form-field" :value="processForm.title"/>
<input type="text" class="am-form-field" :value="processForm.time"/>
<input type="text" class="am-form-field" :value="processForm.time"/>
</div>
<div class="am-form-group am-u-md-4">
<label class="am-form-label">申请人</label>
<input type="text" class="am-form-field" value="周瑾"/>
</div>
<div class="am-form-group am-u-md-4">
<label class="am-form-label">申请部门领导</label>
<input type="text" class="am-form-field" value="尹浩"/>
</div>
</div>
<div class="am-form-inline">
</div>
<div class="am-form-inline">
<button type="submit" class="am-btn am-btn-default">登录</button>
</div>
</form>
</div>
<#-- 选择 业务采购清单明细 -->
<div class="am-u-sm-12 am-u-md-12" v-if="isBusinessProcurementContractProcessMode">
<div class="am-u-sm-12 am-u-md-12" v-if="isProcurementContractDetailMode">
<el-table style="width: 100%" border>
<el-table-column prop="fee" label="费用项目" width="180"></el-table-column>
@ -395,7 +438,8 @@
<script>
const newBusinessProcurementContractProcess = "newBusinessProcurementContractProcess"
const procurementContractProcess = "procurementContractProcess"
const procurementContractDetail = "procurementContractDetail"
const saleContractProcess = "saleContractProcess"
const saleContractDetail = "saleContractDetail"
const BUTTON = "btn"
@ -418,10 +462,11 @@
const data = () => {
return {
mode: "btn", // btn , newBusinessProcurementContractProcess
mode: "btn", // btn , procurementContractProcess
processForm: {
sealTypes: [],
},
supplierMaterialsForm: [],
projectSelected: false,
applySectorOptions: [
{
@ -625,8 +670,7 @@
fileList: [],
// 销售合同收入明细
incomeDetails: [],
attachmentUri: [],
attachmentMap: {}
processType: ""
}
}
@ -635,8 +679,9 @@
this.mode = mode
},
businessProcurementProcessClick() {
const that = this
newProcurementContractClick() {
this.changeMode(procurementContractProcess)
this.processType = 'procurement_contract'
},
goToHome() {
@ -645,8 +690,11 @@
goToSaleContractProcess() {
this.changeMode(saleContractProcess)
this.processType = 'sale_contract'
},
goToSaleContractDetail() {
goToContractDetail() {
// TODO 分情况展示
const { projectId } = this.processForm
if (projectId) {
this.changeMode(saleContractDetail)
@ -744,11 +792,47 @@
this.$refs["saleContractProcessForm"].validate((valid) => {
if (valid) {
const fileList = this.fileList
console.log(fileList)
if (fileList.length === 0) {
this.$message.error("未上传附件");
return false
}
// 采购合同需要验证 供应商比选材料
const processType = this.processType
const processForm = this.processForm
if (processType === 'procurement_contract') {
const { procurementMode } = processForm
// specify_purchase("指定采购"),
// simple_price_comparison("简单比价"),
// price_comparison("比价"),
// competitive_evaluation("竞争性评估");
// 当“采购模式”为“指定采购”“简单比价”时,本模块为非必填模块,当为“比价”“竞争性评估”时,本模块为必填项(“备注”除外)
if (procurementMode === 'price_comparison'
|| procurementMode === 'competitive_evaluation') {
for (const item in this.supplierMaterialsForm) {
for (const [key, value] of Object.entries(item)) {
if (value) {
if (typeof value === 'string') {
if (isBlank(value)) {
this.$message.error("有未填写的表单,请检查表单");
return false
}
}
}
else {
// 没有值
if (key !== 'remark') {
this.$message.error("有未填写的表单,请检查表单");
}
}
}
}
}
}
const loading = this.$loading({
lock: true,
text: '正在提交',
@ -757,13 +841,14 @@
})
const form = {
...this.processForm,
processType: 'sale_contract',
...processForm,
processType,
projectTitle: this.projectTitle,
attachments: fileList.map(file => ({
uri: file.response.data.url,
name: file.response.data.originName
})),
supplierMaterials: this.supplierMaterialsForm,
incomeDetails: this.incomeDetails.map(detail => ({
id: detail.id, expirationDate: detail.expirationDate
}))
@ -824,7 +909,12 @@
indexMethod(index) {
return index * 1;
}
},
addSupplierRow() {
this.supplierMaterialsForm.push({})
},
}
new Vue({
@ -841,10 +931,13 @@
isButtonMode() {
return this.mode === BUTTON
},
isBusinessProcurementContractProcessMode() {
return this.mode === newBusinessProcurementContractProcess
isProcurementContractMode() {
return this.mode === procurementContractProcess
},
isSalesContractProcessMode() {
isProcurementContractDetailMode() {
return this.mode === procurementContractDetail
},
isSalesContractMode() {
return this.mode === saleContractProcess
},
isSaleContractDetailMode() {
@ -858,7 +951,7 @@
return "新增销售合同流程"
case saleContractDetail:
return "销售合同清单明细"
case newBusinessProcurementContractProcess:
case procurementContractProcess:
return "新增业务采购合同流程"
}
}
@ -867,6 +960,7 @@
methods,
mounted() {
// this.newProcurementContractClick();
this.handleSelectProject({ id: 135, name: '' })
},
})

View File

@ -295,7 +295,7 @@
return this.mode === BUTTON
},
isBusinessProcurementContractProcessMode() {
return this.mode === newBusinessProcurementContractProcess
return this.mode === procurementContractProcess
},
isSalesContractProcessMode() {
return this.mode === saleContractProcess
@ -311,7 +311,7 @@
return "新增销售合同流程"
case saleContractDetail:
return "销售合同清单明细"
case newBusinessProcurementContractProcess:
case procurementContractProcess:
return "新增业务采购合同流程"
}
}