feat: 场地使用申请表(单位/个人 + 场地快照 + 8 条条款)#55
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
package com.gxwebsoft.approval.doc.venue;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.gxwebsoft.approval.constant.ApprovalConstants;
|
||||
import com.gxwebsoft.approval.document.AbstractApprovalDocumentType;
|
||||
import com.gxwebsoft.approval.document.ApprovalDocumentParam;
|
||||
import com.gxwebsoft.approval.entity.ApprovalInstance;
|
||||
import com.gxwebsoft.approval.entity.ApprovalVenueForm;
|
||||
import com.gxwebsoft.approval.mapper.ApprovalVenueFormMapper;
|
||||
import com.gxwebsoft.approval.param.ApprovalVenueParam;
|
||||
import com.gxwebsoft.approval.vo.ApprovalDetail;
|
||||
import com.gxwebsoft.common.core.exception.BusinessException;
|
||||
import com.gxwebsoft.common.system.entity.User;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 场地使用申请表(ADR 0009):报送部门负责人 → 分管领导(取报送部门)→ 总经理 →
|
||||
* 报送人存档 → 归档。
|
||||
*
|
||||
* <p>申请单位(人)是外部签署方,不占审批节点、不设系统账号,仅作检索主语。
|
||||
* 场地在另一个服务(modules)的场地主数据中,本服务只快照 id 与名称;
|
||||
* 主数据改名不影响历史单据。</p>
|
||||
*
|
||||
* <p>模板上的 8 条费用与安全条款是固定签约文本,只在详情里渲染(term1..term8),
|
||||
* 不落库、不逐条勾选;第 1 条把场地名与活动费用渲染进去。</p>
|
||||
*/
|
||||
@Component
|
||||
public class VenueDocumentType extends AbstractApprovalDocumentType {
|
||||
|
||||
static final String NODES_JSON = "["
|
||||
+ "{\"key\":\"deptLeader\",\"type\":\"APPROVE\",\"resolver\":\"reporterOrgLeader\",\"name\":\"报送部门负责人\"},"
|
||||
+ "{\"key\":\"deputyLeader\",\"type\":\"APPROVE\",\"resolver\":\"reporterOrgDeputy\",\"name\":\"分管领导\"},"
|
||||
+ "{\"key\":\"generalManager\",\"type\":\"APPROVE\",\"resolver\":\"roleGeneralManager\",\"name\":\"总经理\"},"
|
||||
+ "{\"key\":\"confirm\",\"type\":\"CONFIRM\",\"resolver\":\"reporter\",\"name\":\"报送人存档\"},"
|
||||
+ "{\"key\":\"archive\",\"type\":\"ARCHIVE\",\"resolver\":\"archivist\",\"name\":\"归档\"}"
|
||||
+ "]";
|
||||
|
||||
/** 申请单位(人)类型:单位。 */
|
||||
public static final String APPLICANT_TYPE_ORG = "ORG";
|
||||
/** 申请单位(人)类型:个人。 */
|
||||
public static final String APPLICANT_TYPE_PERSON = "PERSON";
|
||||
|
||||
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Resource
|
||||
private ApprovalVenueFormMapper venueFormMapper;
|
||||
|
||||
@Override
|
||||
public String flowCode() {
|
||||
return ApprovalConstants.FLOW_VENUE;
|
||||
}
|
||||
|
||||
/** doc_type 与 flow_code 同值(本单只有一个流程);复用流程常量避免两处写字面量。 */
|
||||
@Override
|
||||
public String docType() {
|
||||
return ApprovalConstants.FLOW_VENUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String flowName() {
|
||||
return "场地使用申请表";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String nodesJson() {
|
||||
return NODES_JSON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String noPrefix() {
|
||||
return ApprovalConstants.NO_PREFIX_VENUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ApprovalDocumentParam> paramClass() {
|
||||
return ApprovalVenueParam.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(ApprovalDocumentParam param, User user) {
|
||||
ApprovalVenueParam venue = cast(param);
|
||||
requireText("申请单位(人)", venue.getApplicantName(), 100);
|
||||
requireApplicantType(venue.getApplicantType());
|
||||
requireUseTime(venue.getUseStartTime(), venue.getUseEndTime());
|
||||
if (venue.getSiteId() == null || venue.getSiteId() <= 0) {
|
||||
throw new BusinessException("请选择场地");
|
||||
}
|
||||
requireText("场地名称", venue.getSiteName(), 100);
|
||||
requireText("用途说明", venue.getPurpose(), 1000);
|
||||
requireFee(venue.getActivityFee());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long persist(Long instanceId, Long bizId, ApprovalDocumentParam param, User user) {
|
||||
ApprovalVenueParam venue = cast(param);
|
||||
ApprovalVenueForm form = bizId == null || bizId <= 0 ? null : venueFormMapper.selectById(bizId);
|
||||
if (form == null) {
|
||||
form = new ApprovalVenueForm();
|
||||
form.setInstanceId(instanceId);
|
||||
}
|
||||
form.setApplicantName(venue.getApplicantName().trim());
|
||||
form.setApplicantType(venue.getApplicantType().trim());
|
||||
form.setUseStartTime(venue.getUseStartTime());
|
||||
form.setUseEndTime(venue.getUseEndTime());
|
||||
form.setSiteId(venue.getSiteId());
|
||||
form.setSiteName(venue.getSiteName().trim());
|
||||
form.setPurpose(venue.getPurpose().trim());
|
||||
form.setActivityFee(venue.getActivityFee());
|
||||
if (form.getId() == null) {
|
||||
venueFormMapper.insert(form);
|
||||
} else {
|
||||
venueFormMapper.updateById(form);
|
||||
}
|
||||
return form.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(ApprovalInstance instance, ApprovalDetail detail) {
|
||||
ApprovalVenueForm form = findByInstance(instance.getId());
|
||||
if (form == null) {
|
||||
return;
|
||||
}
|
||||
detail.addField("applicantName", "申请单位(人)", form.getApplicantName());
|
||||
detail.addField("applicantType", "申请单位(人)类型", applicantTypeName(form.getApplicantType()));
|
||||
detail.addField("useStartTime", "使用开始时间", timeText(form.getUseStartTime()));
|
||||
detail.addField("useEndTime", "使用结束时间", timeText(form.getUseEndTime()));
|
||||
detail.addField("siteName", "拟申请场地", form.getSiteName());
|
||||
detail.addField("purpose", "用途说明", form.getPurpose());
|
||||
detail.addField("activityFee", "活动费用(元)", feeText(form.getActivityFee()));
|
||||
List<String> terms = VenueTerms.clauses(form.getSiteName(), form.getActivityFee());
|
||||
for (int i = 0; i < terms.size(); i++) {
|
||||
detail.addField("term" + (i + 1), "条款" + (i + 1), terms.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String title(ApprovalInstance instance) {
|
||||
ApprovalVenueForm form = findByInstance(instance.getId());
|
||||
return form == null ? null : form.getApplicantName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchText(ApprovalInstance instance) {
|
||||
ApprovalVenueForm form = findByInstance(instance.getId());
|
||||
if (form == null) {
|
||||
return null;
|
||||
}
|
||||
return join(form.getApplicantName(), form.getSiteName(), form.getPurpose());
|
||||
}
|
||||
|
||||
/** 申请单位(人)类型展示名:单位/个人。 */
|
||||
public static String applicantTypeName(String applicantType) {
|
||||
if (APPLICANT_TYPE_ORG.equals(applicantType)) {
|
||||
return "单位";
|
||||
}
|
||||
if (APPLICANT_TYPE_PERSON.equals(applicantType)) {
|
||||
return "个人";
|
||||
}
|
||||
return applicantType;
|
||||
}
|
||||
|
||||
private void requireApplicantType(String applicantType) {
|
||||
String value = applicantType == null ? "" : applicantType.trim();
|
||||
if (value.isEmpty()) {
|
||||
throw new BusinessException("申请单位(人)类型不能为空");
|
||||
}
|
||||
if (!APPLICANT_TYPE_ORG.equals(value) && !APPLICANT_TYPE_PERSON.equals(value)) {
|
||||
throw new BusinessException("申请单位(人)类型只能是单位或个人");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单次时段:结束必须晚于开始,且起止为同一自然日。
|
||||
*
|
||||
* <p>两条规则分别报错,便于前端把提示落到对应输入项。</p>
|
||||
*/
|
||||
private void requireUseTime(LocalDateTime start, LocalDateTime end) {
|
||||
if (start == null) {
|
||||
throw new BusinessException("使用开始时间不能为空");
|
||||
}
|
||||
if (end == null) {
|
||||
throw new BusinessException("使用结束时间不能为空");
|
||||
}
|
||||
if (!end.isAfter(start)) {
|
||||
throw new BusinessException("使用结束时间必须晚于使用开始时间");
|
||||
}
|
||||
if (!end.toLocalDate().equals(start.toLocalDate())) {
|
||||
throw new BusinessException("使用时间不能跨自然日,请按单日时段填写");
|
||||
}
|
||||
}
|
||||
|
||||
private void requireFee(BigDecimal fee) {
|
||||
if (fee == null) {
|
||||
throw new BusinessException("活动费用不能为空");
|
||||
}
|
||||
if (fee.scale() > 2 || fee.compareTo(BigDecimal.ZERO) < 0
|
||||
|| fee.compareTo(ApprovalConstants.MAX_FEE) > 0) {
|
||||
throw new BusinessException("活动费用必须为0到99999999.99之间的两位小数");
|
||||
}
|
||||
}
|
||||
|
||||
private ApprovalVenueForm findByInstance(Long instanceId) {
|
||||
List<ApprovalVenueForm> forms = venueFormMapper.selectList(
|
||||
new LambdaQueryWrapper<ApprovalVenueForm>()
|
||||
.eq(ApprovalVenueForm::getInstanceId, instanceId)
|
||||
.last("LIMIT 1"));
|
||||
return forms.isEmpty() ? null : forms.get(0);
|
||||
}
|
||||
|
||||
private String timeText(LocalDateTime time) {
|
||||
return time == null ? null : TIME_FORMAT.format(time);
|
||||
}
|
||||
|
||||
private String feeText(BigDecimal fee) {
|
||||
return fee == null ? null : fee.setScale(2, java.math.RoundingMode.HALF_UP).toPlainString();
|
||||
}
|
||||
|
||||
private String join(String... parts) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String part : parts) {
|
||||
if (part == null || part.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(part.trim());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private ApprovalVenueParam cast(ApprovalDocumentParam param) {
|
||||
if (!(param instanceof ApprovalVenueParam)) {
|
||||
throw new BusinessException("单据类型不匹配");
|
||||
}
|
||||
return (ApprovalVenueParam) param;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.gxwebsoft.approval.doc.venue;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 场地使用申请表模板上的 8 条费用与安全条款(固定签约文本,只展示不填报)。
|
||||
*
|
||||
* <p>原文取自《广西体育中心场地使用申请表》;第 1 条把场地名称与活动费用渲染进去,
|
||||
* 其余条款原样输出。条款是合同内容,不是待办清单,不做逐条勾选(ADR 0009)。</p>
|
||||
*/
|
||||
public final class VenueTerms {
|
||||
|
||||
/** 第 1 条附带的收款账户(模板原文)。 */
|
||||
private static final String ACCOUNT_GROUP =
|
||||
"账户信息如下:单位名称:南宁威宁资产经营集团有限责任公司;"
|
||||
+ "开户行:中国建设银行股份有限公司南宁淡村路支行;"
|
||||
+ "银行账号:4505 0160 4952 0900 0033。";
|
||||
|
||||
/** 第 8 条附带的空调费/停车票收款账户(模板原文)。 */
|
||||
private static final String ACCOUNT_CULTURE =
|
||||
"转账账户信息如下:单位名称:南宁威宁文化体育发展有限公司;"
|
||||
+ "开户行:中国建设银行股份有限公司南宁淡村路支行;"
|
||||
+ "银行账号:4505 0160 4952 0900 0003。";
|
||||
|
||||
/** 第 2~7 条(不含第 1、8 条的账户段)。 */
|
||||
private static final List<String> REST = Collections.unmodifiableList(Arrays.asList(
|
||||
"费用交付完成后方可进行布场。",
|
||||
"使用方已对体育场地的状况进行了充分了解,愿意按场地的现状使用。",
|
||||
"使用方入场前应对所有进场人员的身体状况等进行核实,确认其身体状况符合进场运动、工作的条件。"
|
||||
+ "如使用方组织的人员因故意、疏忽等原因导致进场人员的身体状况出现问题的,由使用方承担全部法律责任,"
|
||||
+ "由此导致管理方遭受损失的,管理方有权追偿。",
|
||||
"对场地的使用和车辆进出、停放及人员进出须遵守管理方的规定,并服从管理方的管理。"
|
||||
+ "使用方人员参加活动期间不得乱扔垃圾,除运动垃圾外,厨余垃圾、广告垃圾清理费另行结算。",
|
||||
"如需使用空调,应另行与南宁威宁文化体育发展有限公司现场签单结算,收费标准为2000元/小时,"
|
||||
+ "使用不满1小时的,按1小时结算。",
|
||||
"广西体育中心停车前三小时免费,如需使用停车票,应与南宁威宁文化体育发展有限公司另行结算,"
|
||||
+ "收费标准为5元/天/车。"
|
||||
));
|
||||
|
||||
private VenueTerms() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染 8 条条款:第 1 条为场地 + 活动费用 + 收款账户,第 8 条为附加费用账户。
|
||||
*
|
||||
* @param siteName 场地名称快照,可为空(草稿未选场地时按空串渲染)
|
||||
* @param activityFee 活动费用,可为空
|
||||
*/
|
||||
public static List<String> clauses(String siteName, BigDecimal activityFee) {
|
||||
return Arrays.asList(
|
||||
clause1(siteName, activityFee),
|
||||
REST.get(0),
|
||||
REST.get(1),
|
||||
REST.get(2),
|
||||
REST.get(3),
|
||||
REST.get(4),
|
||||
REST.get(5),
|
||||
"如产生空调费以及停车票费用," + ACCOUNT_CULTURE
|
||||
);
|
||||
}
|
||||
|
||||
/** 第 1 条:模板原文「使用___(场地),活动费用为___元,账户信息如下:…」。 */
|
||||
public static String clause1(String siteName, BigDecimal activityFee) {
|
||||
String site = siteName == null || siteName.trim().isEmpty() ? "(未选场地)" : siteName.trim();
|
||||
return "使用" + site + "(场地),活动费用为" + feeText(activityFee) + "元," + ACCOUNT_GROUP;
|
||||
}
|
||||
|
||||
/** 金额展示:统一两位小数;空值显示为「待定」。 */
|
||||
private static String feeText(BigDecimal fee) {
|
||||
if (fee == null) {
|
||||
return "待定";
|
||||
}
|
||||
return fee.setScale(2, RoundingMode.HALF_UP).toPlainString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.gxwebsoft.approval.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 场地使用申请表。
|
||||
*
|
||||
* <p>场地来自 modules 服务的场地主数据,本服务只快照 site_id 与 site_name:
|
||||
* 主数据改名不影响历史单据(ADR 0009)。申请单位(人)是外部签署方,
|
||||
* 不占审批节点、不设系统账号,只作检索主语。</p>
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(description = "场地使用申请表")
|
||||
@TableName("approval_venue_form")
|
||||
public class ApprovalVenueForm implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private Integer tenantId;
|
||||
|
||||
private Long instanceId;
|
||||
|
||||
@ApiModelProperty("申请单位(人)名称")
|
||||
private String applicantName;
|
||||
|
||||
@ApiModelProperty("申请单位(人)类型:ORG 单位 / PERSON 个人")
|
||||
private String applicantType;
|
||||
|
||||
@ApiModelProperty("使用开始时间")
|
||||
private LocalDateTime useStartTime;
|
||||
|
||||
@ApiModelProperty("使用结束时间")
|
||||
private LocalDateTime useEndTime;
|
||||
|
||||
@ApiModelProperty("场地 id(来自场地主数据)")
|
||||
private Integer siteId;
|
||||
|
||||
@ApiModelProperty("场地名称快照")
|
||||
private String siteName;
|
||||
|
||||
@ApiModelProperty("用途说明")
|
||||
private String purpose;
|
||||
|
||||
@ApiModelProperty("活动费用(元)")
|
||||
private BigDecimal activityFee;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.gxwebsoft.approval.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.gxwebsoft.approval.entity.ApprovalVenueForm;
|
||||
|
||||
/**
|
||||
* 场地使用申请表Mapper。
|
||||
*/
|
||||
public interface ApprovalVenueFormMapper extends BaseMapper<ApprovalVenueForm> {
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.gxwebsoft.approval.param;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.gxwebsoft.approval.document.ApprovalDocumentParam;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 场地使用申请表草稿参数;id 为审批实例id,更新草稿时传入。
|
||||
*
|
||||
* <p>场地名称由前端从场地主数据选中后随 siteId 一并提交,服务端只做快照,
|
||||
* 不反向查询主数据(主数据在 modules 服务,不在本库)。</p>
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApprovalVenueParam extends ApprovalDocumentParam {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("申请单位(人)名称")
|
||||
private String applicantName;
|
||||
|
||||
@ApiModelProperty("申请单位(人)类型:ORG 单位 / PERSON 个人")
|
||||
private String applicantType;
|
||||
|
||||
@ApiModelProperty("使用开始时间,yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime useStartTime;
|
||||
|
||||
@ApiModelProperty("使用结束时间,yyyy-MM-dd HH:mm:ss,须晚于开始时间且与开始时间为同一天")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime useEndTime;
|
||||
|
||||
@ApiModelProperty("场地id(来自场地主数据)")
|
||||
private Integer siteId;
|
||||
|
||||
@ApiModelProperty("场地名称快照(随场地主数据选择带出)")
|
||||
private String siteName;
|
||||
|
||||
@ApiModelProperty("用途说明")
|
||||
private String purpose;
|
||||
|
||||
@ApiModelProperty("活动费用(元),0~99999999.99")
|
||||
private BigDecimal activityFee;
|
||||
}
|
||||
@@ -0,0 +1,443 @@
|
||||
package com.gxwebsoft.approval;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.gxwebsoft.support.ApprovalTestData;
|
||||
import com.gxwebsoft.support.TestAuthentication;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* 场地使用申请表(#55):字段/时段校验、场地快照、8 条条款渲染、列表检索与五节点闭环。
|
||||
*
|
||||
* <p>不开启测试事务:提交与审批各自提交,校验跨库的组织/角色解析;数据由
|
||||
* {@link ApprovalTestData#cleanup()} 与本地 {@code approval_venue_form} 清理。</p>
|
||||
*/
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles({"gxtyzx-test", "test"})
|
||||
class ApprovalVenueIT {
|
||||
|
||||
/** 独立租户:角色成员按 (tenant_id, role_code) 匹配,专属租户避免与其它测试类串味。 */
|
||||
private static final int TENANT = 10026;
|
||||
private static final String FLOW = "venue";
|
||||
private static final String LIST = "approval:instance:list";
|
||||
private static final String SUBMIT = "approval:instance:submit";
|
||||
private static final String APPROVE = "approval:instance:approve";
|
||||
private static final String ARCHIVE = "approval:instance:archive";
|
||||
|
||||
private static final String SITE_NAME = "广西体育中心体育场";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
private ApprovalTestData data;
|
||||
private ApprovalTestData.TestUser reporter;
|
||||
private Integer organizationId;
|
||||
private final List<Long> instanceIds = new ArrayList<>();
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
data = new ApprovalTestData(dataSource);
|
||||
organizationId = data.createOrganization("场地报送部门" + data.uniqueSuffix(), 136, TENANT);
|
||||
reporter = data.createUser("场地报送人" + data.uniqueSuffix(), organizationId, TENANT);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
for (Long instanceId : instanceIds) {
|
||||
data.master().update("DELETE FROM approval_venue_form WHERE instance_id = ?", instanceId);
|
||||
}
|
||||
instanceIds.clear();
|
||||
data.cleanup();
|
||||
}
|
||||
|
||||
@Test
|
||||
void completesFiveNodeFlowWithVenueSnapshot() throws Exception {
|
||||
ApprovalTestData.TestUser deptLeader = grantDeptRole("dept_leader_", "部门负责人");
|
||||
ApprovalTestData.TestUser deputy = grantDeptRole("dept_deputy_", "分管领导");
|
||||
ApprovalTestData.TestUser generalManager = grantRole("approval_general_manager", "总经理");
|
||||
ApprovalTestData.TestUser archivist = grantRole("approval_archivist", "收文员");
|
||||
|
||||
long instanceId = saveVenue("广西某某文化传媒有限公司", "ORG", "2026-11-08 09:00:00",
|
||||
"2026-11-08 18:00:00", "举办企业运动会", "1234.5");
|
||||
|
||||
// 草稿:标题=申请单位(人),无单号,场地快照落库
|
||||
assertThat(instanceStatus(instanceId)).isEqualTo("DRAFT");
|
||||
assertThat(bizNo(instanceId)).isNull();
|
||||
assertThat(data.queryMaster("SELECT doc_type FROM approval_instance WHERE id = ?",
|
||||
String.class, instanceId)).isEqualTo("venue");
|
||||
assertThat(data.queryMaster("SELECT flow_code FROM approval_instance WHERE id = ?",
|
||||
String.class, instanceId)).isEqualTo("venue");
|
||||
assertThat(data.queryMaster("SELECT title FROM approval_instance WHERE id = ?",
|
||||
String.class, instanceId)).isEqualTo("广西某某文化传媒有限公司");
|
||||
assertThat(data.queryMaster("SELECT applicant_type FROM approval_venue_form WHERE instance_id = ?",
|
||||
String.class, instanceId)).isEqualTo("ORG");
|
||||
assertThat(data.queryMaster("SELECT site_id FROM approval_venue_form WHERE instance_id = ?",
|
||||
Integer.class, instanceId)).isEqualTo(88001);
|
||||
assertThat(data.queryMaster("SELECT site_name FROM approval_venue_form WHERE instance_id = ?",
|
||||
String.class, instanceId)).isEqualTo(SITE_NAME);
|
||||
assertThat(data.queryMaster("SELECT activity_fee FROM approval_venue_form WHERE instance_id = ?",
|
||||
java.math.BigDecimal.class, instanceId)).isEqualByComparingTo("1234.50");
|
||||
|
||||
// 节点定义:五个节点按顺序发布,存档节点为报送人(JSON 列会重排空格,按关键片段断言)
|
||||
String nodes = data.queryMaster("SELECT nodes_json FROM approval_flow_definition "
|
||||
+ "WHERE tenant_id = ? AND flow_code = 'venue' ORDER BY version DESC LIMIT 1", String.class, TENANT);
|
||||
assertThat(nodes).contains("reporterOrgLeader").contains("reporterOrgDeputy")
|
||||
.contains("roleGeneralManager").contains("archivist");
|
||||
assertThat(nodes.indexOf("deptLeader")).isLessThan(nodes.indexOf("deputyLeader"));
|
||||
assertThat(nodes.indexOf("deputyLeader")).isLessThan(nodes.indexOf("generalManager"));
|
||||
assertThat(nodes.indexOf("generalManager")).isLessThan(nodes.indexOf("confirm"));
|
||||
assertThat(nodes.indexOf("confirm")).isLessThan(nodes.indexOf("archive"));
|
||||
|
||||
uploadAttachment(instanceId);
|
||||
mockMvc.perform(authed(post("/api/approval/instance/" + instanceId + "/submit"), reporter, organizationId, SUBMIT))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.status").value("PENDING"))
|
||||
.andExpect(jsonPath("$.data.currentNodeName").value("报送部门负责人"))
|
||||
.andExpect(jsonPath("$.data.attachments.length()").value(1));
|
||||
assertThat(bizNo(instanceId)).matches("CD\\d{8}-\\d{4,}");
|
||||
|
||||
approve(instanceId, deptLeader, "分管领导", "同意使用");
|
||||
approve(instanceId, deputy, "总经理", "同意");
|
||||
approve(instanceId, generalManager, "报送人存档", "批准");
|
||||
|
||||
// 存档节点:报送人确认后才进入归档
|
||||
long confirmTask = pendingTaskId(instanceId, reporter.userId);
|
||||
mockMvc.perform(authed(post("/api/approval/task/" + confirmTask + "/confirm"), reporter, organizationId, APPROVE))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.status").value("APPROVED"))
|
||||
.andExpect(jsonPath("$.data.statusName").value("审批完成"))
|
||||
.andExpect(jsonPath("$.data.currentNodeName").value("归档"));
|
||||
|
||||
long archiveTask = pendingTaskId(instanceId, archivist.userId);
|
||||
mockMvc.perform(authed(post("/api/approval/task/" + archiveTask + "/archive"), archivist, organizationId, ARCHIVE))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.status").value("ARCHIVED"))
|
||||
.andExpect(jsonPath("$.data.statusName").value("已归档"))
|
||||
.andExpect(jsonPath("$.data.archivistName").value(archivist.username));
|
||||
|
||||
assertThat(data.countMaster("SELECT COUNT(*) FROM approval_record WHERE instance_id = ? "
|
||||
+ "AND action = 'APPROVE'", instanceId)).isEqualTo(3);
|
||||
assertThat(data.countMaster("SELECT COUNT(*) FROM approval_record WHERE instance_id = ? "
|
||||
+ "AND action = 'CONFIRM'", instanceId)).isEqualTo(1);
|
||||
assertThat(data.countMaster("SELECT COUNT(*) FROM approval_record WHERE instance_id = ? "
|
||||
+ "AND action = 'ARCHIVE'", instanceId)).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsCrossDayAndReversedUseTime() throws Exception {
|
||||
// 跨自然日:起止不在同一天
|
||||
mockMvc.perform(authed(post("/api/approval/instance/" + FLOW), reporter, organizationId, SUBMIT)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(body("跨天单位", "ORG", "2026-11-08 09:00:00", "2026-11-09 18:00:00",
|
||||
SITE_NAME, "跨天活动", "100.00")))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(1))
|
||||
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("不能跨自然日")));
|
||||
|
||||
// 结束早于开始:同一自然日但时间倒挂
|
||||
mockMvc.perform(authed(post("/api/approval/instance/" + FLOW), reporter, organizationId, SUBMIT)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(body("倒挂单位", "ORG", "2026-11-08 18:00:00", "2026-11-08 09:00:00",
|
||||
SITE_NAME, "倒挂活动", "100.00")))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(1))
|
||||
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("必须晚于使用开始时间")));
|
||||
|
||||
// 起止相同也算不晚于
|
||||
mockMvc.perform(authed(post("/api/approval/instance/" + FLOW), reporter, organizationId, SUBMIT)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(body("同刻单位", "ORG", "2026-11-08 09:00:00", "2026-11-08 09:00:00",
|
||||
SITE_NAME, "同刻活动", "100.00")))
|
||||
.andExpect(jsonPath("$.code").value(1))
|
||||
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("必须晚于使用开始时间")));
|
||||
|
||||
assertThat(data.countMaster("SELECT COUNT(*) FROM approval_venue_form "
|
||||
+ "WHERE applicant_name IN ('跨天单位', '倒挂单位', '同刻单位')")).isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
void validatesVenueFields() throws Exception {
|
||||
expectSaveFailure(body("", "ORG", "2026-11-08 09:00:00", "2026-11-08 18:00:00",
|
||||
SITE_NAME, "用途", "100.00"), "申请单位(人)不能为空");
|
||||
expectSaveFailure(body("单位", null, "2026-11-08 09:00:00", "2026-11-08 18:00:00",
|
||||
SITE_NAME, "用途", "100.00"), "申请单位(人)类型不能为空");
|
||||
expectSaveFailure(body("单位", "COMPANY", "2026-11-08 09:00:00", "2026-11-08 18:00:00",
|
||||
SITE_NAME, "用途", "100.00"), "申请单位(人)类型只能是单位或个人");
|
||||
expectSaveFailure(body("单位", "ORG", null, "2026-11-08 18:00:00",
|
||||
SITE_NAME, "用途", "100.00"), "使用开始时间不能为空");
|
||||
expectSaveFailure(body("单位", "ORG", "2026-11-08 09:00:00", null,
|
||||
SITE_NAME, "用途", "100.00"), "使用结束时间不能为空");
|
||||
expectSaveFailure(body("单位", "ORG", "2026-11-08 09:00:00", "2026-11-08 18:00:00",
|
||||
SITE_NAME, "用途", "-1"), "活动费用必须为0到99999999.99之间的两位小数");
|
||||
expectSaveFailure(body("单位", "ORG", "2026-11-08 09:00:00", "2026-11-08 18:00:00",
|
||||
SITE_NAME, "用途", "100000000"), "活动费用必须为0到99999999.99之间的两位小数");
|
||||
expectSaveFailure(body("单位", "ORG", "2026-11-08 09:00:00", "2026-11-08 18:00:00",
|
||||
SITE_NAME, "用途", "1.234"), "活动费用必须为0到99999999.99之间的两位小数");
|
||||
expectSaveFailure(body("单位", "ORG", "2026-11-08 09:00:00", "2026-11-08 18:00:00",
|
||||
"", "用途", "100.00"), "场地名称不能为空");
|
||||
expectSaveFailure(body("单位", "ORG", "2026-11-08 09:00:00", "2026-11-08 18:00:00",
|
||||
SITE_NAME, "", "100.00"), "用途说明不能为空");
|
||||
|
||||
// 场地 id 必填
|
||||
mockMvc.perform(authed(post("/api/approval/instance/" + FLOW), reporter, organizationId, SUBMIT)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"applicantName\":\"单位\",\"applicantType\":\"ORG\","
|
||||
+ "\"useStartTime\":\"2026-11-08 09:00:00\",\"useEndTime\":\"2026-11-08 18:00:00\","
|
||||
+ "\"siteName\":\"" + SITE_NAME + "\",\"purpose\":\"用途\",\"activityFee\":100.00}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(1))
|
||||
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("请选择场地")));
|
||||
|
||||
// 个人申请合法落库
|
||||
long instanceId = saveVenue("张三", "PERSON", "2026-11-08 09:00:00", "2026-11-08 12:00:00",
|
||||
"个人健身", "0");
|
||||
assertThat(data.queryMaster("SELECT applicant_type FROM approval_venue_form WHERE instance_id = ?",
|
||||
String.class, instanceId)).isEqualTo("PERSON");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersApplicantTypeAndEightTermsInDetail() throws Exception {
|
||||
long instanceId = saveVenue("广西某某体育俱乐部", "ORG", "2026-11-08 09:00:00",
|
||||
"2026-11-08 18:00:00", "举办篮球邀请赛", "8888");
|
||||
|
||||
Map<String, String> fields = detailFields(instanceId);
|
||||
|
||||
// 审批人能从详情看出是单位还是个人
|
||||
assertThat(fields).containsEntry("applicantType", "单位");
|
||||
assertThat(fields).containsEntry("applicantName", "广西某某体育俱乐部");
|
||||
assertThat(fields).containsEntry("siteName", SITE_NAME);
|
||||
assertThat(fields).containsEntry("activityFee", "8888.00");
|
||||
|
||||
// 8 条条款逐条输出,第 1 条渲染场地名与活动费用
|
||||
for (int i = 1; i <= 8; i++) {
|
||||
assertThat(fields).as("条款" + i).containsKey("term" + i);
|
||||
assertThat(fields.get("term" + i)).isNotBlank();
|
||||
}
|
||||
assertThat(fields.get("term1")).contains(SITE_NAME).contains("8888.00元");
|
||||
assertThat(fields.get("term2")).contains("费用交付完成");
|
||||
assertThat(fields.get("term8")).contains("空调费");
|
||||
|
||||
// 个人申请在详情显示「个人」
|
||||
long personInstance = saveVenue("李四", "PERSON", "2026-11-08 09:00:00",
|
||||
"2026-11-08 18:00:00", "个人活动", "100");
|
||||
assertThat(detailFields(personInstance)).containsEntry("applicantType", "个人");
|
||||
}
|
||||
|
||||
@Test
|
||||
void listFindsByApplicantNameKeywords() throws Exception {
|
||||
saveVenue("广西甲体育馆运营有限公司", "ORG", "2026-11-08 09:00:00", "2026-11-08 18:00:00",
|
||||
"甲方活动", "100");
|
||||
long target = saveVenue("南宁乙文化传播有限公司", "PERSON", "2026-11-09 09:00:00",
|
||||
"2026-11-09 18:00:00", "乙方活动", "200");
|
||||
|
||||
mockMvc.perform(authed(get("/api/approval/mine/page"), reporter, organizationId, LIST)
|
||||
.param("keywords", "乙文化"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.count").value(1))
|
||||
.andExpect(jsonPath("$.data.list[0].id").value((int) target))
|
||||
.andExpect(jsonPath("$.data.list[0].title").value("南宁乙文化传播有限公司"))
|
||||
.andExpect(jsonPath("$.data.list[0].docTypeName").value("场地使用申请表"));
|
||||
|
||||
mockMvc.perform(authed(get("/api/approval/mine/page"), reporter, organizationId, LIST)
|
||||
.param("keywords", "甲体育馆"))
|
||||
.andExpect(jsonPath("$.data.count").value(1))
|
||||
.andExpect(jsonPath("$.data.list[0].title").value("广西甲体育馆运营有限公司"));
|
||||
|
||||
mockMvc.perform(authed(get("/api/approval/instance/page"), reporter, organizationId, LIST)
|
||||
.param("keywords", "乙文化"))
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.count").value(1))
|
||||
.andExpect(jsonPath("$.data.list[0].id").value((int) target));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsSubmitWithoutAttachment() throws Exception {
|
||||
grantDeptRole("dept_leader_", "部门负责人");
|
||||
grantDeptRole("dept_deputy_", "分管领导");
|
||||
grantRole("approval_general_manager", "总经理");
|
||||
grantRole("approval_archivist", "收文员");
|
||||
|
||||
long instanceId = saveVenue("无附件单位", "ORG", "2026-11-08 09:00:00",
|
||||
"2026-11-08 18:00:00", "无附件活动", "100");
|
||||
|
||||
mockMvc.perform(authed(post("/api/approval/instance/" + instanceId + "/submit"), reporter, organizationId, SUBMIT))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(1))
|
||||
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("请至少上传一张附件")));
|
||||
|
||||
assertThat(instanceStatus(instanceId)).isEqualTo("DRAFT");
|
||||
assertThat(bizNo(instanceId)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsSubmitWhenDeputyLeaderMissing() throws Exception {
|
||||
grantDeptRole("dept_leader_", "部门负责人");
|
||||
grantRole("approval_archivist", "收文员");
|
||||
long instanceId = saveVenue("缺分管单位", "ORG", "2026-11-08 09:00:00",
|
||||
"2026-11-08 18:00:00", "缺分管活动", "100");
|
||||
uploadAttachment(instanceId);
|
||||
|
||||
mockMvc.perform(authed(post("/api/approval/instance/" + instanceId + "/submit"), reporter, organizationId, SUBMIT))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(1))
|
||||
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("报送部门分管领导角色缺配")));
|
||||
|
||||
assertThat(instanceStatus(instanceId)).isEqualTo("DRAFT");
|
||||
}
|
||||
|
||||
// ---------- helpers ----------
|
||||
|
||||
private void expectSaveFailure(String body, String expectedMessage) throws Exception {
|
||||
mockMvc.perform(authed(post("/api/approval/instance/" + FLOW), reporter, organizationId, SUBMIT)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(body))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(1))
|
||||
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString(expectedMessage)));
|
||||
}
|
||||
|
||||
private long saveVenue(String applicantName, String applicantType, String start, String end,
|
||||
String purpose, String activityFee) throws Exception {
|
||||
String response = mockMvc.perform(authed(post("/api/approval/instance/" + FLOW),
|
||||
reporter, organizationId, SUBMIT)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(body(applicantName, applicantType, start, end, SITE_NAME, purpose, activityFee)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andReturn().getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
long instanceId = objectMapper.readTree(response).path("data").asLong();
|
||||
data.trackInstance(instanceId);
|
||||
instanceIds.add(instanceId);
|
||||
return instanceId;
|
||||
}
|
||||
|
||||
private void approve(long instanceId, ApprovalTestData.TestUser approver,
|
||||
String expectedNextNodeName, String opinion) throws Exception {
|
||||
long taskId = pendingTaskId(instanceId, approver.userId);
|
||||
mockMvc.perform(authed(post("/api/approval/task/" + taskId + "/approve"), approver, organizationId, APPROVE)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"opinion\":" + quote(opinion) + "}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.currentNodeName").value(expectedNextNodeName));
|
||||
}
|
||||
|
||||
private Map<String, String> detailFields(long instanceId) throws Exception {
|
||||
String response = mockMvc.perform(authed(get("/api/approval/instance/" + instanceId),
|
||||
reporter, organizationId, LIST))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andReturn().getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
JsonNode fields = objectMapper.readTree(response).path("data").path("document").path("fields");
|
||||
Map<String, String> result = new LinkedHashMap<>();
|
||||
for (JsonNode field : fields) {
|
||||
result.put(field.path("key").asText(), field.path("value").asText());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private ApprovalTestData.TestUser grantDeptRole(String prefix, String roleName) {
|
||||
String roleCode = prefix + data.organizationCode(organizationId);
|
||||
ApprovalTestData.TestRole role = data.createRole(roleCode, roleName, TENANT);
|
||||
ApprovalTestData.TestUser member = data.createUser(roleName + data.uniqueSuffix(), organizationId, TENANT);
|
||||
data.bindTenant(member.userId, role.roleId, TENANT);
|
||||
return member;
|
||||
}
|
||||
|
||||
private ApprovalTestData.TestUser grantRole(String roleCode, String roleName) {
|
||||
ApprovalTestData.TestRole role = data.createRole(roleCode, roleName, TENANT);
|
||||
ApprovalTestData.TestUser member = data.createUser(roleName + data.uniqueSuffix(), organizationId, TENANT);
|
||||
data.bindTenant(member.userId, role.roleId, TENANT);
|
||||
return member;
|
||||
}
|
||||
|
||||
private void uploadAttachment(long instanceId) throws Exception {
|
||||
MockMultipartFile file = new MockMultipartFile("file", "quote.png", "image/png",
|
||||
new byte[]{(byte) 0x89, 'P', 'N', 'G', 0x0D, 0x0A, 0x1A, 0x0A});
|
||||
mockMvc.perform(multipart("/api/approval/attachment/upload")
|
||||
.file(file)
|
||||
.param("instanceId", String.valueOf(instanceId))
|
||||
.param("category", "OTHER")
|
||||
.header("tenantId", TENANT)
|
||||
.with(authentication(TestAuthentication.user(reporter.userId, reporter.username,
|
||||
organizationId, TENANT, SUBMIT))))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0));
|
||||
}
|
||||
|
||||
private long pendingTaskId(long instanceId, int userId) {
|
||||
Long taskId = data.queryMaster("SELECT id FROM approval_task WHERE instance_id = ? "
|
||||
+ "AND assignee_id = ? AND status = 'PENDING' LIMIT 1", Long.class, instanceId, userId);
|
||||
assertThat(taskId).as("待办任务应存在").isNotNull();
|
||||
return taskId;
|
||||
}
|
||||
|
||||
private MockHttpServletRequestBuilder authed(MockHttpServletRequestBuilder builder,
|
||||
ApprovalTestData.TestUser user, Integer org,
|
||||
String... authorities) {
|
||||
return builder.header("tenantId", TENANT)
|
||||
.with(authentication(TestAuthentication.user(user.userId, user.username, org, TENANT, authorities)));
|
||||
}
|
||||
|
||||
private String body(String applicantName, String applicantType, String start, String end,
|
||||
String siteName, String purpose, String activityFee) {
|
||||
return "{\"applicantName\":" + quote(applicantName)
|
||||
+ ",\"applicantType\":" + quote(applicantType)
|
||||
+ ",\"useStartTime\":" + quote(start)
|
||||
+ ",\"useEndTime\":" + quote(end)
|
||||
+ ",\"siteId\":88001"
|
||||
+ ",\"siteName\":" + quote(siteName)
|
||||
+ ",\"purpose\":" + quote(purpose)
|
||||
+ ",\"activityFee\":" + activityFee
|
||||
+ "}";
|
||||
}
|
||||
|
||||
private String quote(String value) {
|
||||
if (value == null) {
|
||||
return "null";
|
||||
}
|
||||
return "\"" + value.replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
|
||||
}
|
||||
|
||||
private String instanceStatus(long instanceId) {
|
||||
return data.queryMaster("SELECT status FROM approval_instance WHERE id = ?", String.class, instanceId);
|
||||
}
|
||||
|
||||
private String bizNo(long instanceId) {
|
||||
return data.queryMaster("SELECT biz_no FROM approval_instance WHERE id = ?", String.class, instanceId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user