feat(oa/erp): 初始化新增项目变更申请及预算变更明细功能

- 项目计划变更(erp_project_change、erp_project_change_budget、erp_project_change_progress)
- 实现项目预算变更明细的增删改查接口与服务层逻辑
- 实现项目变更申请的完整流程控制接口,包括提交审批功能
- 完成项目变更模块的权限配置与基础数据校验规则
dev
zangch@mesnac.com 1 month ago
parent 9e39fa2e8a
commit a5db8b62c7

@ -0,0 +1,93 @@
package org.dromara.oa.crm.domain.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO
* Excel
*
* @author Yinq
* @date 2025-10-30
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class QuoteTemplateDto {
/**
*
*/
private String customerContactName;
/**
* ()
*/
private String title;
/**
*
*/
private String quoteDate;
/**
*
*/
private String taxIncludedInfo;
/**
*
*/
private String paymentMethod;
/**
*
*/
private String deliveryPeriod;
/**
*
*/
private String deliveryMethod;
/**
*
*/
private String validDays;
/**
*
*/
private String totalBeforeTax;
/**
*
*/
private String totalTax;
/**
*
*/
private String totalIncludingTax;
/**
*
*/
private String totalInChinese;
/**
*
*/
private String supplierContactName;
/**
*
*/
private String supplierContactPhone;
/**
*
*/
private String supplierContactEmail;
}

@ -0,0 +1,51 @@
package org.dromara.oa.crm.domain.dto;
import cn.idev.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* DTO
* EasyExcel
*
* @author Yinq
* @date 2025-10-29
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class QuoteTemplateItemDto implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/** 序号 */
private Long seq;
/** 产品名称 */
private String productName;
/** 型号/说明 */
private String modelDesc;
/** 数量 */
private BigDecimal quantity;
/** 单位 */
private String unit;
/** 单价(含税) */
private BigDecimal price;
/** 小计(含税) */
private BigDecimal subtotal;
/** 备注 */
private String remark;
}

@ -0,0 +1,58 @@
package org.dromara.oa.crm.domain.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO
* Excel
*
* @author Yinq
* @date 2025-10-30
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class QuoteTemplateMaterialDto {
/**
*
*/
private String seq;
/**
* /
*/
private String productName;
/**
* /
*/
private String modelDesc;
/**
*
*/
private String quantity;
/**
*
*/
private String unit;
/**
*
*/
private String price;
/**
* ()
*/
private String subtotal;
/**
*
*/
private String remark;
}

@ -0,0 +1,116 @@
package org.dromara.oa.erp.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeBudgetVo;
import org.dromara.oa.erp.domain.bo.ErpProjectChangeBudgetBo;
import org.dromara.oa.erp.service.IErpProjectChangeBudgetService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
*
* 访:/oa/erp/erpProjectChangeBudget
*
* @author Yinq
* @date 2025-11-10
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/erpProjectChangeBudget")
public class ErpProjectChangeBudgetController extends BaseController {
private final IErpProjectChangeBudgetService erpProjectChangeBudgetService;
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChangeBudget:list")
@GetMapping("/list")
public TableDataInfo<ErpProjectChangeBudgetVo> list(ErpProjectChangeBudgetBo bo, PageQuery pageQuery) {
return erpProjectChangeBudgetService.queryPageList(bo, pageQuery);
}
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChangeBudget:export")
@Log(title = "项目预算变更明细", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ErpProjectChangeBudgetBo bo, HttpServletResponse response) {
List<ErpProjectChangeBudgetVo> list = erpProjectChangeBudgetService.queryList(bo);
ExcelUtil.exportExcel(list, "项目预算变更明细", ErpProjectChangeBudgetVo.class, response);
}
/**
*
*
* @param changeBudgetId
*/
@SaCheckPermission("oa/erp:erpProjectChangeBudget:query")
@GetMapping("/{changeBudgetId}")
public R<ErpProjectChangeBudgetVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable("changeBudgetId") Long changeBudgetId) {
return R.ok(erpProjectChangeBudgetService.queryById(changeBudgetId));
}
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChangeBudget:add")
@Log(title = "项目预算变更明细", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpProjectChangeBudgetBo bo) {
return toAjax(erpProjectChangeBudgetService.insertByBo(bo));
}
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChangeBudget:edit")
@Log(title = "项目预算变更明细", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpProjectChangeBudgetBo bo) {
return toAjax(erpProjectChangeBudgetService.updateByBo(bo));
}
/**
*
*
* @param changeBudgetIds
*/
@SaCheckPermission("oa/erp:erpProjectChangeBudget:remove")
@Log(title = "项目预算变更明细", businessType = BusinessType.DELETE)
@DeleteMapping("/{changeBudgetIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable("changeBudgetIds") Long[] changeBudgetIds) {
return toAjax(erpProjectChangeBudgetService.deleteWithValidByIds(List.of(changeBudgetIds), true));
}
/**
*
*/
@GetMapping("/getErpProjectChangeBudgetList")
public R<List<ErpProjectChangeBudgetVo>> getErpProjectChangeBudgetList(ErpProjectChangeBudgetBo bo) {
List<ErpProjectChangeBudgetVo> list = erpProjectChangeBudgetService.queryList(bo);
return R.ok(list);
}
}

@ -0,0 +1,139 @@
package org.dromara.oa.erp.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeVo;
import org.dromara.oa.erp.domain.bo.ErpProjectChangeBo;
import org.dromara.oa.erp.service.IErpProjectChangeService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
*
* 访:/oa/erp/erpProjectChange
*
* @author Yinq
* @date 2025-11-10
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/erp/erpProjectChange")
public class ErpProjectChangeController extends BaseController {
private final IErpProjectChangeService erpProjectChangeService;
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChange:list")
@GetMapping("/list")
public TableDataInfo<ErpProjectChangeVo> list(ErpProjectChangeBo bo, PageQuery pageQuery) {
return erpProjectChangeService.queryPageList(bo, pageQuery);
}
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChange:export")
@Log(title = "项目变更申请", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ErpProjectChangeBo bo, HttpServletResponse response) {
List<ErpProjectChangeVo> list = erpProjectChangeService.queryList(bo);
ExcelUtil.exportExcel(list, "项目变更申请", ErpProjectChangeVo.class, response);
}
/**
*
*
* @param projectChangeId
*/
@SaCheckPermission("oa/erp:erpProjectChange:query")
@GetMapping("/{projectChangeId}")
public R<ErpProjectChangeVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable("projectChangeId") Long projectChangeId) {
return R.ok(erpProjectChangeService.queryById(projectChangeId));
}
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChange:add")
@Log(title = "项目变更申请", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpProjectChangeBo bo) {
return toAjax(erpProjectChangeService.insertByBo(bo));
}
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChange:edit")
@Log(title = "项目变更申请", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpProjectChangeBo bo) {
return toAjax(erpProjectChangeService.updateByBo(bo));
}
/**
*
*
* @param projectChangeIds
*/
@SaCheckPermission("oa/erp:erpProjectChange:remove")
@Log(title = "项目变更申请", businessType = BusinessType.DELETE)
@DeleteMapping("/{projectChangeIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable("projectChangeIds") Long[] projectChangeIds) {
return toAjax(erpProjectChangeService.deleteWithValidByIds(List.of(projectChangeIds), true));
}
/**
*
*/
@GetMapping("/getErpProjectChangeList")
public R<List<ErpProjectChangeVo>> getErpProjectChangeList(ErpProjectChangeBo bo) {
List<ErpProjectChangeVo> list = erpProjectChangeService.queryList(bo);
return R.ok(list);
}
/**
* ID
*
* @param projectId ID
*/
@SaCheckPermission("oa/erp:erpProjectChange:query")
@GetMapping("/prepareWithInfo/{projectId}")
public R<ErpProjectChangeVo> prepareWithInfo(@NotNull(message = "项目ID不能为空")
@PathVariable("projectId") Long projectId) {
return R.ok(erpProjectChangeService.prepareByProjectWithInfo(projectId));
}
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChange:add")
@Log(title = "项目变更申请", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/submitAndFlowStart")
public R<ErpProjectChangeVo> submitAndFlowStart(@Validated(AddGroup.class) @RequestBody ErpProjectChangeBo bo) {
return R.ok(erpProjectChangeService.projectChangeSubmitAndFlowStart(bo));
}
}

@ -0,0 +1,116 @@
package org.dromara.oa.erp.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeProgressVo;
import org.dromara.oa.erp.domain.bo.ErpProjectChangeProgressBo;
import org.dromara.oa.erp.service.IErpProjectChangeProgressService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
*
* 访:/oa/erp/erpProjectChangeProgress
*
* @author Yinq
* @date 2025-11-10
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/erpProjectChangeProgress")
public class ErpProjectChangeProgressController extends BaseController {
private final IErpProjectChangeProgressService erpProjectChangeProgressService;
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChangeProgress:list")
@GetMapping("/list")
public TableDataInfo<ErpProjectChangeProgressVo> list(ErpProjectChangeProgressBo bo, PageQuery pageQuery) {
return erpProjectChangeProgressService.queryPageList(bo, pageQuery);
}
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChangeProgress:export")
@Log(title = "项目进度变更明细", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ErpProjectChangeProgressBo bo, HttpServletResponse response) {
List<ErpProjectChangeProgressVo> list = erpProjectChangeProgressService.queryList(bo);
ExcelUtil.exportExcel(list, "项目进度变更明细", ErpProjectChangeProgressVo.class, response);
}
/**
*
*
* @param changeProgressId
*/
@SaCheckPermission("oa/erp:erpProjectChangeProgress:query")
@GetMapping("/{changeProgressId}")
public R<ErpProjectChangeProgressVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable("changeProgressId") Long changeProgressId) {
return R.ok(erpProjectChangeProgressService.queryById(changeProgressId));
}
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChangeProgress:add")
@Log(title = "项目进度变更明细", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpProjectChangeProgressBo bo) {
return toAjax(erpProjectChangeProgressService.insertByBo(bo));
}
/**
*
*/
@SaCheckPermission("oa/erp:erpProjectChangeProgress:edit")
@Log(title = "项目进度变更明细", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpProjectChangeProgressBo bo) {
return toAjax(erpProjectChangeProgressService.updateByBo(bo));
}
/**
*
*
* @param changeProgressIds
*/
@SaCheckPermission("oa/erp:erpProjectChangeProgress:remove")
@Log(title = "项目进度变更明细", businessType = BusinessType.DELETE)
@DeleteMapping("/{changeProgressIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable("changeProgressIds") Long[] changeProgressIds) {
return toAjax(erpProjectChangeProgressService.deleteWithValidByIds(List.of(changeProgressIds), true));
}
/**
*
*/
@GetMapping("/getErpProjectChangeProgressList")
public R<List<ErpProjectChangeProgressVo>> getErpProjectChangeProgressList(ErpProjectChangeProgressBo bo) {
List<ErpProjectChangeProgressVo> list = erpProjectChangeProgressService.queryList(bo);
return R.ok(list);
}
}

@ -0,0 +1,149 @@
package org.dromara.oa.erp.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* erp_project_change
*
* @author Yinq
* @date 2025-11-10
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("erp_project_change")
public class ErpProjectChange extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "project_change_id", type = IdType.ASSIGN_ID)
private Long projectChangeId;
/**
* ID
*/
private Long projectId;
/**
*
*/
private String projectCode;
/**
*
*/
private String projectName;
/**
* 1 2 3 4
*/
private String projectCategory;
/**
* 1 2 3 4 5
*/
private String changeType;
/**
*
*/
private Integer changeNumber;
/**
* ID
*/
private Long projectManagerId;
/**
*
*/
private String projectManagerName;
/**
* ID
*/
private Long deptHeadId;
/**
*
*/
private String deptHeadName;
/**
* ID
*/
private Long responsibleVpId;
/**
*
*/
private String responsibleVpName;
/**
*
*/
private Date applyChangeDate;
/**
*
*/
private BigDecimal contractAmount;
/**
*
*/
private BigDecimal contractNetAmount;
/**
*
*/
private String currentStatus;
/**
*
*/
private String changeReason;
/**
*
*/
private String followUpWork;
/**
* (1 2 3)
*/
private String projectChangeStatus;
/**
*
*/
private String flowStatus;
/**
*
*/
private String remark;
/**
* 1 0
*/
private String activeFlag;
/**
* 0 1
*/
@TableLogic
private String delFlag;
}

@ -0,0 +1,85 @@
package org.dromara.oa.erp.domain;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
import java.math.BigDecimal;
import java.io.Serial;
/**
* erp_project_change_budget
*
* @author Yinq
* @date 2025-11-10
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("erp_project_change_budget")
public class ErpProjectChangeBudget extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "change_budget_id", type = IdType.AUTO)
private Long changeBudgetId;
/**
* ID
*/
private Long projectChangeId;
/**
* ID
*/
private Long budgetDetailId;
/**
*
*/
private String subjectName;
/**
*
*/
private BigDecimal budgetBefore;
/**
*
*/
private BigDecimal budgetAfter;
/**
* 使
*/
private BigDecimal amountUsed;
/**
*
*/
private String adjustmentReason;
/**
*
*/
private Long sortOrder;
/**
*
*/
private String remark;
/**
* 0 1
*/
@TableLogic
private String delFlag;
}

@ -0,0 +1,97 @@
package org.dromara.oa.erp.domain;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.common.tenant.core.TenantEntity;
import java.io.Serial;
/**
* erp_project_change_progress
*
* @author Yinq
* @date 2025-11-10
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("erp_project_change_progress")
public class ErpProjectChangeProgress extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "change_progress_id", type = IdType.AUTO)
private Long changeProgressId;
/**
* ID
*/
private Long projectChangeId;
/**
* ID
*/
private Long planStageId;
/**
* project_phases
*/
@TableField(exist = false)
private String projectPhases;
/**
*
*/
private String milestoneName;
/**
*
*/
private Date originalStart;
/**
*
*/
private Date originalEnd;
/**
*
*/
private Date changedStart;
/**
*
*/
private Date changedEnd;
/**
*
*/
private BigDecimal completionDegree;
/**
*
*/
private Long sortOrder;
/**
*
*/
private String remark;
/**
* 0 1
*/
@TableLogic
private String delFlag;
}

@ -0,0 +1,195 @@
package org.dromara.oa.erp.domain.bo;
import cn.hutool.core.util.ObjectUtil;
import org.dromara.oa.erp.domain.ErpProjectChange;
import org.dromara.oa.erp.domain.ErpProjectChangeBudget;
import org.dromara.oa.erp.domain.ErpProjectChangeProgress;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.util.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.workflow.api.domain.RemoteFlowInstanceBizExt;
/**
* erp_project_change
*
* @author Yinq
* @date 2025-11-10
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = ErpProjectChange.class, reverseConvertGenerate = false)
public class ErpProjectChangeBo extends BaseEntity {
/**
* ID
*/
@NotNull(message = "项目变更ID不能为空", groups = { EditGroup.class })
private Long projectChangeId;
/**
* ID
*/
@NotNull(message = "项目ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long projectId;
/**
*
*/
private String projectCode;
/**
*
*/
private String projectName;
/**
* 1 2 3 4
*/
private String projectCategory;
/**
* 1 2 3 4 5
*/
private String changeType;
/**
*
*/
private Integer changeNumber;
/**
* ID
*/
private Long projectManagerId;
/**
*
*/
private String projectManagerName;
/**
* ID
*/
private Long deptHeadId;
/**
*
*/
private String deptHeadName;
/**
* ID
*/
private Long responsibleVpId;
/**
*
*/
private String responsibleVpName;
/**
*
*/
@NotNull(message = "申请变更时间不能为空", groups = { AddGroup.class, EditGroup.class })
private Date applyChangeDate;
/**
*
*/
private BigDecimal contractAmount;
/**
*
*/
private BigDecimal contractNetAmount;
/**
*
*/
private String currentStatus;
/**
*
*/
private String changeReason;
/**
*
*/
private String followUpWork;
/**
* (1 2 3)
*/
private String projectChangeStatus;
/**
*
*/
private String flowStatus;
/**
*
*/
private String remark;
/**
* 1 0
*/
private String activeFlag;
/**
*
*/
private List<ErpProjectChangeBudget> budgetList;
/**
*
*/
private List<ErpProjectChangeProgress> progressList;
/**
*
*/
private String flowCode;
/**
*
*/
private String handler;
/**
* {'entity': {}}
*/
private Map<String, Object> variables;
/**
*
*/
private RemoteFlowInstanceBizExt bizExt;
public Map<String, Object> getVariables() {
if (variables == null) {
return new HashMap<>(16);
}
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
return variables;
}
public RemoteFlowInstanceBizExt getBizExt() {
if (ObjectUtil.isNull(bizExt)) {
bizExt = new RemoteFlowInstanceBizExt();
}
return bizExt;
}
}

@ -0,0 +1,78 @@
package org.dromara.oa.erp.domain.bo;
import org.dromara.oa.erp.domain.ErpProjectChangeBudget;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
/**
* erp_project_change_budget
*
* @author Yinq
* @date 2025-11-10
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = ErpProjectChangeBudget.class, reverseConvertGenerate = false)
public class ErpProjectChangeBudgetBo extends BaseEntity {
/**
* ID
*/
@NotNull(message = "预算变更ID不能为空", groups = { EditGroup.class })
private Long changeBudgetId;
/**
* ID
*/
@NotNull(message = "变更申请ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long projectChangeId;
/**
* ID
*/
private Long budgetDetailId;
/**
*
*/
@NotBlank(message = "科目名称(材料费、人工费、安装费、差旅费、其他费用)不能为空", groups = { AddGroup.class, EditGroup.class })
private String subjectName;
/**
*
*/
private BigDecimal budgetBefore;
/**
*
*/
private BigDecimal budgetAfter;
/**
* 使
*/
private BigDecimal amountUsed;
/**
*
*/
private String adjustmentReason;
/**
*
*/
private Long sortOrder;
/**
*
*/
private String remark;
}

@ -0,0 +1,86 @@
package org.dromara.oa.erp.domain.bo;
import org.dromara.oa.erp.domain.ErpProjectChangeProgress;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* erp_project_change_progress
*
* @author Yinq
* @date 2025-11-10
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = ErpProjectChangeProgress.class, reverseConvertGenerate = false)
public class ErpProjectChangeProgressBo extends BaseEntity {
/**
* ID
*/
@NotNull(message = "进度变更ID不能为空", groups = { EditGroup.class })
private Long changeProgressId;
/**
* ID
*/
@NotNull(message = "变更申请ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long projectChangeId;
/**
* ID
*/
@NotNull(message = "计划阶段ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long planStageId;
/**
*
*/
@NotBlank(message = "项目里程碑不能为空", groups = { AddGroup.class, EditGroup.class })
private String milestoneName;
/**
*
*/
private Date originalStart;
/**
*
*/
private Date originalEnd;
/**
*
*/
private Date changedStart;
/**
*
*/
private Date changedEnd;
/**
*
*/
private BigDecimal completionDegree;
/**
*
*/
private Long sortOrder;
/**
*
*/
private String remark;
}

@ -0,0 +1,94 @@
package org.dromara.oa.erp.domain.vo;
import java.math.BigDecimal;
import org.dromara.oa.erp.domain.ErpProjectChangeBudget;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* erp_project_change_budget
*
* @author Yinq
* @date 2025-11-10
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = ErpProjectChangeBudget.class)
public class ErpProjectChangeBudgetVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ExcelProperty(value = "预算变更ID")
private Long changeBudgetId;
/**
* ID
*/
@ExcelProperty(value = "变更申请ID")
private Long projectChangeId;
/**
* ID
*/
@ExcelProperty(value = "预算详情ID")
private Long budgetDetailId;
/**
*
*/
@ExcelProperty(value = "科目名称", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "材=料费、人工费、安装费、差旅费、其他费用")
private String subjectName;
/**
*
*/
@ExcelProperty(value = "变更前预算")
private BigDecimal budgetBefore;
/**
*
*/
@ExcelProperty(value = "变更后预算")
private BigDecimal budgetAfter;
/**
* 使
*/
@ExcelProperty(value = "已使用金额")
private BigDecimal amountUsed;
/**
*
*/
@ExcelProperty(value = "费用调整原因")
private String adjustmentReason;
/**
*
*/
@ExcelProperty(value = "排序顺序")
private Long sortOrder;
/**
*
*/
@ExcelProperty(value = "备注")
private String remark;
}

@ -0,0 +1,109 @@
package org.dromara.oa.erp.domain.vo;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.oa.erp.domain.ErpProjectChangeProgress;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* erp_project_change_progress
*
* @author Yinq
* @date 2025-11-10
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = ErpProjectChangeProgress.class)
public class ErpProjectChangeProgressVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ExcelProperty(value = "进度变更ID")
private Long changeProgressId;
/**
* ID
*/
@ExcelProperty(value = "变更申请ID")
private Long projectChangeId;
/**
* ID
*/
@ExcelProperty(value = "计划阶段ID")
private Long planStageId;
/**
* project_phases
*/
@ExcelProperty(value = "项目阶段", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "project_phases")
private String projectPhases;
/**
*
*/
@ExcelProperty(value = "项目里程碑")
private String milestoneName;
/**
*
*/
@ExcelProperty(value = "原计划时间起")
private Date originalStart;
/**
*
*/
@ExcelProperty(value = "原计划时间止")
private Date originalEnd;
/**
*
*/
@ExcelProperty(value = "变更后时间起")
private Date changedStart;
/**
*
*/
@ExcelProperty(value = "变更后时间止")
private Date changedEnd;
/**
*
*/
@ExcelProperty(value = "里程碑完成程度", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "百=分比")
private BigDecimal completionDegree;
/**
*
*/
@ExcelProperty(value = "排序顺序")
private Long sortOrder;
/**
*
*/
@ExcelProperty(value = "备注")
private String remark;
}

@ -0,0 +1,204 @@
package org.dromara.oa.erp.domain.vo;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.oa.erp.domain.ErpProjectChange;
import org.dromara.oa.erp.domain.ErpProjectChangeBudget;
import org.dromara.oa.erp.domain.ErpProjectChangeProgress;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* erp_project_change
*
* @author Yinq
* @date 2025-11-10
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = ErpProjectChange.class)
public class ErpProjectChangeVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ExcelProperty(value = "项目变更ID")
private Long projectChangeId;
/**
* ID
*/
@ExcelProperty(value = "项目ID")
private Long projectId;
/**
*
*/
@ExcelProperty(value = "项目编号")
private String projectCode;
/**
*
*/
@ExcelProperty(value = "项目名称")
private String projectName;
/**
* 1 2 3 4
*/
@ExcelProperty(value = "项目类别", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "project_category")
private String projectCategory;
/**
* 1 2 3 4 5
*/
@ExcelProperty(value = "变更类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "change_type")
private String changeType;
/**
*
*/
@ExcelProperty(value = "变更次数")
private Integer changeNumber;
/**
* ID
*/
@ExcelProperty(value = "项目经理ID")
private Long projectManagerId;
/**
*
*/
@ExcelProperty(value = "项目经理姓名")
private String projectManagerName;
/**
* ID
*/
@ExcelProperty(value = "部门负责人ID")
private Long deptHeadId;
/**
*
*/
@ExcelProperty(value = "部门负责人姓名")
private String deptHeadName;
/**
* ID
*/
@ExcelProperty(value = "分管副总ID")
private Long responsibleVpId;
/**
*
*/
@ExcelProperty(value = "分管副总姓名")
private String responsibleVpName;
/**
*
*/
@ExcelProperty(value = "申请变更时间")
private Date applyChangeDate;
/**
*
*/
@ExcelProperty(value = "项目合同额")
private BigDecimal contractAmount;
/**
*
*/
@ExcelProperty(value = "项目合同净额")
private BigDecimal contractNetAmount;
/**
*
*/
@ExcelProperty(value = "项目当前情况")
private String currentStatus;
/**
*
*/
@ExcelProperty(value = "变更原因")
private String changeReason;
/**
*
*/
@ExcelProperty(value = "后续工作")
private String followUpWork;
/**
* (1 2 3)
*/
@ExcelProperty(value = "项目变更状态(1暂存 2审批中 3可用)", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "project_change_status")
private String projectChangeStatus;
/**
*
*/
@ExcelProperty(value = "流程状态")
private String flowStatus;
/**
*
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 1 0
*/
@ExcelProperty(value = "激活标识", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "active_flag")
private String activeFlag;
/**
*
*/
@ExcelProperty(value = "创建人")
private Long createBy;
/**
*
*/
@ExcelProperty(value = "创建时间")
private Date createTime;
/**
*
*/
@TableField(exist = false)
private List<ErpProjectChangeBudget> budgetList;
/**
*
*/
@TableField(exist = false)
private List<ErpProjectChangeProgress> progressList;
}

@ -0,0 +1,113 @@
package org.dromara.oa.erp.mapper;
import java.util.List;
import java.util.Collection;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.oa.erp.domain.ErpProjectChangeBudget;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeBudgetVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* Mapper
*
* @author Yinq
* @date 2025-11-10
*/
public interface ErpProjectChangeBudgetMapper extends BaseMapperPlus<ErpProjectChangeBudget, ErpProjectChangeBudgetVo> {
/**
*
*
* @param page
* @param queryWrapper
* @return
*/
public Page<ErpProjectChangeBudgetVo> selectCustomErpProjectChangeBudgetVoList(@Param("page") Page<ErpProjectChangeBudgetVo> page, @Param(Constants.WRAPPER) MPJLambdaWrapper<ErpProjectChangeBudget> queryWrapper);
/**
*
*
* @param queryWrapper
* @return
*/
public List<ErpProjectChangeBudgetVo> selectCustomErpProjectChangeBudgetVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper<ErpProjectChangeBudget> queryWrapper);
/**
* ID
*
* @param changeBudgetId ID
* @return
*/
ErpProjectChangeBudgetVo selectCustomErpProjectChangeBudgetVoById(@Param("changeBudgetId") Long changeBudgetId);
/**
* ID
*
* @param ids ID
* @return
*/
List<ErpProjectChangeBudgetVo> selectCustomErpProjectChangeBudgetVoByIds(@Param("ids") Collection<Long> ids);
/**
*
*
* @param queryWrapper
* @return
*/
Long countCustomErpProjectChangeBudget(@Param(Constants.WRAPPER) Wrapper<ErpProjectChangeBudget> queryWrapper);
/**
*
*
* @param page
* @param queryWrapper
* @return
*/
Page<ErpProjectChangeBudgetVo> selectCustomErpProjectChangeBudgetVoPage(@Param("page") Page<ErpProjectChangeBudgetVo> page, @Param(Constants.WRAPPER) Wrapper<ErpProjectChangeBudget> queryWrapper);
/**
*
*
* @param list
* @return
*/
int batchInsertErpProjectChangeBudget(@Param("list") List<ErpProjectChangeBudget> list);
/**
*
*
* @param list
* @return
*/
int batchUpdateErpProjectChangeBudget(@Param("list") List<ErpProjectChangeBudget> list);
/**
*
*
* @param queryWrapper
* @return
*/
int deleteCustomErpProjectChangeBudget(@Param(Constants.WRAPPER) Wrapper<ErpProjectChangeBudget> queryWrapper);
/**
* ID
*
* @param ids ID
* @return
*/
int deleteCustomErpProjectChangeBudgetByIds(@Param("ids") Collection<Long> ids);
/**
*
*
* @param queryWrapper
* @return
*/
Boolean existsErpProjectChangeBudget(@Param(Constants.WRAPPER) Wrapper<ErpProjectChangeBudget> queryWrapper);
}

@ -0,0 +1,131 @@
package org.dromara.oa.erp.mapper;
import java.util.List;
import java.util.Collection;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.oa.erp.domain.ErpProjectChange;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeVo;
import org.dromara.common.mybatis.annotation.DataColumn;
import org.dromara.common.mybatis.annotation.DataPermission;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* Mapper
*
* @author Yinq
* @date 2025-11-10
*/
public interface ErpProjectChangeMapper extends BaseMapperPlus<ErpProjectChange, ErpProjectChangeVo> {
/**
*
*
* @param page
* @param queryWrapper
* @return
*/
@DataPermission({
@DataColumn(key = "deptName", value = "t.create_dept"),
@DataColumn(key = "userName", value = "t.create_by")
})
public Page<ErpProjectChangeVo> selectCustomErpProjectChangeVoList(@Param("page") Page<ErpProjectChangeVo> page, @Param(Constants.WRAPPER) MPJLambdaWrapper<ErpProjectChange> queryWrapper);
/**
*
*
* @param queryWrapper
* @return
*/
@DataPermission({
@DataColumn(key = "deptName", value = "t.create_dept"),
@DataColumn(key = "userName", value = "t.create_by")
})
public List<ErpProjectChangeVo> selectCustomErpProjectChangeVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper<ErpProjectChange> queryWrapper);
/**
* ID
*
* @param projectChangeId ID
* @return
*/
ErpProjectChangeVo selectCustomErpProjectChangeVoById(@Param("projectChangeId") Long projectChangeId);
/**
* ID
*
* @param ids ID
* @return
*/
List<ErpProjectChangeVo> selectCustomErpProjectChangeVoByIds(@Param("ids") Collection<Long> ids);
/**
*
*
* @param queryWrapper
* @return
*/
Long countCustomErpProjectChange(@Param(Constants.WRAPPER) Wrapper<ErpProjectChange> queryWrapper);
/**
*
*
* @param page
* @param queryWrapper
* @return
*/
Page<ErpProjectChangeVo> selectCustomErpProjectChangeVoPage(@Param("page") Page<ErpProjectChangeVo> page, @Param(Constants.WRAPPER) Wrapper<ErpProjectChange> queryWrapper);
/**
*
*
* @param list
* @return
*/
int batchInsertErpProjectChange(@Param("list") List<ErpProjectChange> list);
/**
*
*
* @param list
* @return
*/
int batchUpdateErpProjectChange(@Param("list") List<ErpProjectChange> list);
/**
*
*
* @param queryWrapper
* @return
*/
int deleteCustomErpProjectChange(@Param(Constants.WRAPPER) Wrapper<ErpProjectChange> queryWrapper);
/**
* ID
*
* @param ids ID
* @return
*/
int deleteCustomErpProjectChangeByIds(@Param("ids") Collection<Long> ids);
/**
*
*
* @param queryWrapper
* @return
*/
Boolean existsErpProjectChange(@Param(Constants.WRAPPER) Wrapper<ErpProjectChange> queryWrapper);
/**
* ID
*
* @param projectId ID
* @return
*/
ErpProjectChangeVo prepareByProjectId(@Param("projectId") Long projectId);
}

@ -0,0 +1,113 @@
package org.dromara.oa.erp.mapper;
import java.util.List;
import java.util.Collection;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.oa.erp.domain.ErpProjectChangeProgress;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeProgressVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* Mapper
*
* @author Yinq
* @date 2025-11-10
*/
public interface ErpProjectChangeProgressMapper extends BaseMapperPlus<ErpProjectChangeProgress, ErpProjectChangeProgressVo> {
/**
*
*
* @param page
* @param queryWrapper
* @return
*/
public Page<ErpProjectChangeProgressVo> selectCustomErpProjectChangeProgressVoList(@Param("page") Page<ErpProjectChangeProgressVo> page, @Param(Constants.WRAPPER) MPJLambdaWrapper<ErpProjectChangeProgress> queryWrapper);
/**
*
*
* @param queryWrapper
* @return
*/
public List<ErpProjectChangeProgressVo> selectCustomErpProjectChangeProgressVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper<ErpProjectChangeProgress> queryWrapper);
/**
* ID
*
* @param changeProgressId ID
* @return
*/
ErpProjectChangeProgressVo selectCustomErpProjectChangeProgressVoById(@Param("changeProgressId") Long changeProgressId);
/**
* ID
*
* @param ids ID
* @return
*/
List<ErpProjectChangeProgressVo> selectCustomErpProjectChangeProgressVoByIds(@Param("ids") Collection<Long> ids);
/**
*
*
* @param queryWrapper
* @return
*/
Long countCustomErpProjectChangeProgress(@Param(Constants.WRAPPER) Wrapper<ErpProjectChangeProgress> queryWrapper);
/**
*
*
* @param page
* @param queryWrapper
* @return
*/
Page<ErpProjectChangeProgressVo> selectCustomErpProjectChangeProgressVoPage(@Param("page") Page<ErpProjectChangeProgressVo> page, @Param(Constants.WRAPPER) Wrapper<ErpProjectChangeProgress> queryWrapper);
/**
*
*
* @param list
* @return
*/
int batchInsertErpProjectChangeProgress(@Param("list") List<ErpProjectChangeProgress> list);
/**
*
*
* @param list
* @return
*/
int batchUpdateErpProjectChangeProgress(@Param("list") List<ErpProjectChangeProgress> list);
/**
*
*
* @param queryWrapper
* @return
*/
int deleteCustomErpProjectChangeProgress(@Param(Constants.WRAPPER) Wrapper<ErpProjectChangeProgress> queryWrapper);
/**
* ID
*
* @param ids ID
* @return
*/
int deleteCustomErpProjectChangeProgressByIds(@Param("ids") Collection<Long> ids);
/**
*
*
* @param queryWrapper
* @return
*/
Boolean existsErpProjectChangeProgress(@Param(Constants.WRAPPER) Wrapper<ErpProjectChangeProgress> queryWrapper);
}

@ -0,0 +1,69 @@
package org.dromara.oa.erp.service;
import org.dromara.oa.erp.domain.ErpProjectChangeBudget;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeBudgetVo;
import org.dromara.oa.erp.domain.bo.ErpProjectChangeBudgetBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* Service
*
* @author Yinq
* @date 2025-11-10
*/
public interface IErpProjectChangeBudgetService {
/**
*
*
* @param changeBudgetId
* @return
*/
ErpProjectChangeBudgetVo queryById(Long changeBudgetId);
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
TableDataInfo<ErpProjectChangeBudgetVo> queryPageList(ErpProjectChangeBudgetBo bo, PageQuery pageQuery);
/**
*
*
* @param bo
* @return
*/
List<ErpProjectChangeBudgetVo> queryList(ErpProjectChangeBudgetBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean insertByBo(ErpProjectChangeBudgetBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean updateByBo(ErpProjectChangeBudgetBo bo);
/**
*
*
* @param ids
* @param isValid
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

@ -0,0 +1,69 @@
package org.dromara.oa.erp.service;
import org.dromara.oa.erp.domain.ErpProjectChangeProgress;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeProgressVo;
import org.dromara.oa.erp.domain.bo.ErpProjectChangeProgressBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* Service
*
* @author Yinq
* @date 2025-11-10
*/
public interface IErpProjectChangeProgressService {
/**
*
*
* @param changeProgressId
* @return
*/
ErpProjectChangeProgressVo queryById(Long changeProgressId);
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
TableDataInfo<ErpProjectChangeProgressVo> queryPageList(ErpProjectChangeProgressBo bo, PageQuery pageQuery);
/**
*
*
* @param bo
* @return
*/
List<ErpProjectChangeProgressVo> queryList(ErpProjectChangeProgressBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean insertByBo(ErpProjectChangeProgressBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean updateByBo(ErpProjectChangeProgressBo bo);
/**
*
*
* @param ids
* @param isValid
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

@ -0,0 +1,85 @@
package org.dromara.oa.erp.service;
import org.dromara.oa.erp.domain.ErpProjectChange;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeVo;
import org.dromara.oa.erp.domain.bo.ErpProjectChangeBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* Service
*
* @author Yinq
* @date 2025-11-10
*/
public interface IErpProjectChangeService {
/**
*
*
* @param projectChangeId
* @return
*/
ErpProjectChangeVo queryById(Long projectChangeId);
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
TableDataInfo<ErpProjectChangeVo> queryPageList(ErpProjectChangeBo bo, PageQuery pageQuery);
/**
*
*
* @param bo
* @return
*/
List<ErpProjectChangeVo> queryList(ErpProjectChangeBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean insertByBo(ErpProjectChangeBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean updateByBo(ErpProjectChangeBo bo);
/**
*
*
* @param ids
* @param isValid
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* ID
*
* @param projectId ID
* @return
*/
ErpProjectChangeVo prepareByProjectWithInfo(Long projectId);
/**
*
*
* @param bo
* @return
*/
ErpProjectChangeVo projectChangeSubmitAndFlowStart(ErpProjectChangeBo bo);
}

@ -0,0 +1,139 @@
package org.dromara.oa.erp.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.oa.erp.domain.bo.ErpProjectChangeBudgetBo;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeBudgetVo;
import org.dromara.oa.erp.domain.ErpProjectChangeBudget;
import org.dromara.oa.erp.mapper.ErpProjectChangeBudgetMapper;
import org.dromara.oa.erp.service.IErpProjectChangeBudgetService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* Service
*
* @author Yinq
* @date 2025-11-10
*/
@RequiredArgsConstructor
@Service
public class ErpProjectChangeBudgetServiceImpl implements IErpProjectChangeBudgetService {
private final ErpProjectChangeBudgetMapper baseMapper;
/**
*
*
* @param changeBudgetId
* @return
*/
@Override
public ErpProjectChangeBudgetVo queryById(Long changeBudgetId){
return baseMapper.selectVoById(changeBudgetId);
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<ErpProjectChangeBudgetVo> queryPageList(ErpProjectChangeBudgetBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<ErpProjectChangeBudget> lqw = buildQueryWrapper(bo);
Page<ErpProjectChangeBudgetVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @return
*/
@Override
public List<ErpProjectChangeBudgetVo> queryList(ErpProjectChangeBudgetBo bo) {
MPJLambdaWrapper<ErpProjectChangeBudget> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private MPJLambdaWrapper<ErpProjectChangeBudget> buildQueryWrapper(ErpProjectChangeBudgetBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<ErpProjectChangeBudget> lqw = JoinWrappers.lambda(ErpProjectChangeBudget.class)
.selectAll(ErpProjectChangeBudget.class)
.eq(ErpProjectChangeBudget::getDelFlag, "0")
.eq(bo.getProjectChangeId() != null, ErpProjectChangeBudget::getProjectChangeId, bo.getProjectChangeId())
.eq(bo.getBudgetDetailId() != null, ErpProjectChangeBudget::getBudgetDetailId, bo.getBudgetDetailId())
.like(StringUtils.isNotBlank(bo.getSubjectName()), ErpProjectChangeBudget::getSubjectName, bo.getSubjectName())
.eq(bo.getBudgetBefore() != null, ErpProjectChangeBudget::getBudgetBefore, bo.getBudgetBefore())
.eq(bo.getBudgetAfter() != null, ErpProjectChangeBudget::getBudgetAfter, bo.getBudgetAfter())
.eq(bo.getAmountUsed() != null, ErpProjectChangeBudget::getAmountUsed, bo.getAmountUsed())
.eq(StringUtils.isNotBlank(bo.getAdjustmentReason()), ErpProjectChangeBudget::getAdjustmentReason, bo.getAdjustmentReason())
.eq(bo.getSortOrder() != null, ErpProjectChangeBudget::getSortOrder, bo.getSortOrder());
return lqw;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean insertByBo(ErpProjectChangeBudgetBo bo) {
ErpProjectChangeBudget add = MapstructUtils.convert(bo, ErpProjectChangeBudget.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setChangeBudgetId(add.getChangeBudgetId());
}
return flag;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean updateByBo(ErpProjectChangeBudgetBo bo) {
ErpProjectChangeBudget update = MapstructUtils.convert(bo, ErpProjectChangeBudget.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
*
*/
private void validEntityBeforeSave(ErpProjectChangeBudget entity){
//TODO 做一些数据校验,如唯一约束
}
/**
*
*
* @param ids
* @param isValid
* @return
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -0,0 +1,140 @@
package org.dromara.oa.erp.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.oa.erp.domain.bo.ErpProjectChangeProgressBo;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeProgressVo;
import org.dromara.oa.erp.domain.ErpProjectChangeProgress;
import org.dromara.oa.erp.mapper.ErpProjectChangeProgressMapper;
import org.dromara.oa.erp.service.IErpProjectChangeProgressService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* Service
*
* @author Yinq
* @date 2025-11-10
*/
@RequiredArgsConstructor
@Service
public class ErpProjectChangeProgressServiceImpl implements IErpProjectChangeProgressService {
private final ErpProjectChangeProgressMapper baseMapper;
/**
*
*
* @param changeProgressId
* @return
*/
@Override
public ErpProjectChangeProgressVo queryById(Long changeProgressId){
return baseMapper.selectVoById(changeProgressId);
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<ErpProjectChangeProgressVo> queryPageList(ErpProjectChangeProgressBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<ErpProjectChangeProgress> lqw = buildQueryWrapper(bo);
Page<ErpProjectChangeProgressVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @return
*/
@Override
public List<ErpProjectChangeProgressVo> queryList(ErpProjectChangeProgressBo bo) {
MPJLambdaWrapper<ErpProjectChangeProgress> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private MPJLambdaWrapper<ErpProjectChangeProgress> buildQueryWrapper(ErpProjectChangeProgressBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<ErpProjectChangeProgress> lqw = JoinWrappers.lambda(ErpProjectChangeProgress.class)
.selectAll(ErpProjectChangeProgress.class)
.eq(ErpProjectChangeProgress::getDelFlag, "0")
.eq(bo.getProjectChangeId() != null, ErpProjectChangeProgress::getProjectChangeId, bo.getProjectChangeId())
.eq(bo.getPlanStageId() != null, ErpProjectChangeProgress::getPlanStageId, bo.getPlanStageId())
.like(StringUtils.isNotBlank(bo.getMilestoneName()), ErpProjectChangeProgress::getMilestoneName, bo.getMilestoneName())
.eq(bo.getOriginalStart() != null, ErpProjectChangeProgress::getOriginalStart, bo.getOriginalStart())
.eq(bo.getOriginalEnd() != null, ErpProjectChangeProgress::getOriginalEnd, bo.getOriginalEnd())
.eq(bo.getChangedStart() != null, ErpProjectChangeProgress::getChangedStart, bo.getChangedStart())
.eq(bo.getChangedEnd() != null, ErpProjectChangeProgress::getChangedEnd, bo.getChangedEnd())
.eq(bo.getCompletionDegree() != null, ErpProjectChangeProgress::getCompletionDegree, bo.getCompletionDegree())
.eq(bo.getSortOrder() != null, ErpProjectChangeProgress::getSortOrder, bo.getSortOrder());
return lqw;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean insertByBo(ErpProjectChangeProgressBo bo) {
ErpProjectChangeProgress add = MapstructUtils.convert(bo, ErpProjectChangeProgress.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setChangeProgressId(add.getChangeProgressId());
}
return flag;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean updateByBo(ErpProjectChangeProgressBo bo) {
ErpProjectChangeProgress update = MapstructUtils.convert(bo, ErpProjectChangeProgress.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
*
*/
private void validEntityBeforeSave(ErpProjectChangeProgress entity){
//TODO 做一些数据校验,如唯一约束
}
/**
*
*
* @param ids
* @param isValid
* @return
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -0,0 +1,445 @@
package org.dromara.oa.erp.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.enums.OAStatusEnum;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.oa.erp.domain.*;
import org.dromara.oa.erp.mapper.*;
import org.dromara.workflow.api.RemoteWorkflowService;
import org.dromara.workflow.api.domain.RemoteStartProcess;
import org.dromara.workflow.api.event.ProcessEvent;
import org.springframework.context.event.EventListener;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.stereotype.Service;
import org.dromara.oa.erp.domain.bo.ErpProjectChangeBo;
import org.dromara.oa.erp.domain.vo.ErpProjectChangeVo;
import org.dromara.oa.erp.service.IErpProjectChangeService;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
/**
* Service
*
* @author Yinq
* @date 2025-11-10
*/
@RequiredArgsConstructor
@Service
@Slf4j
public class ErpProjectChangeServiceImpl implements IErpProjectChangeService {
private final ErpProjectChangeMapper baseMapper;
private final ErpProjectChangeBudgetMapper changeBudgetMapper;
private final ErpProjectChangeProgressMapper changeProgressMapper;
private final ErpProjectInfoMapper projectInfoMapper;
private final ErpProjectPlanMapper projectPlanMapper;
private final ErpProjectPlanStageMapper planStageMapper;
@DubboReference(timeout = 30000)
private RemoteWorkflowService remoteWorkflowService;
/**
*
*
* @param projectChangeId
* @return
*/
@Override
public ErpProjectChangeVo queryById(Long projectChangeId){
// 使用自定义查询方法,连表查询用户名称
ErpProjectChangeVo projectChangeVo = baseMapper.selectCustomErpProjectChangeVoById(projectChangeId);
if (ObjectUtils.isEmpty(projectChangeVo)) {
return null;
}
// 查询预算变更明细列表
MPJLambdaWrapper<ErpProjectChangeBudget> budgetLqw = JoinWrappers.lambda(ErpProjectChangeBudget.class)
.selectAll(ErpProjectChangeBudget.class)
.eq("t.del_flag", "0")
.eq(projectChangeId != null, ErpProjectChangeBudget::getProjectChangeId, projectChangeId);
List<ErpProjectChangeBudget> budgetList = changeBudgetMapper.selectList(budgetLqw);
projectChangeVo.setBudgetList(budgetList);
// 查询进度变更明细列表连表查询项目计划阶段获取projectPhases
MPJLambdaWrapper<ErpProjectChangeProgress> progressLqw = JoinWrappers.lambda(ErpProjectChangeProgress.class)
.selectAll(ErpProjectChangeProgress.class)
.selectAs(ErpProjectPlanStage::getProjectPhases, ErpProjectChangeProgress::getProjectPhases)
.leftJoin(ErpProjectPlanStage.class, ErpProjectPlanStage::getPlanStageId, ErpProjectChangeProgress::getPlanStageId)
.eq("t.del_flag", "0")
.eq(projectChangeId != null, ErpProjectChangeProgress::getProjectChangeId, projectChangeId)
.orderByAsc(ErpProjectChangeProgress::getSortOrder);
List<ErpProjectChangeProgress> progressList = changeProgressMapper.selectList(progressLqw);
projectChangeVo.setProgressList(progressList);
return projectChangeVo;
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<ErpProjectChangeVo> queryPageList(ErpProjectChangeBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<ErpProjectChange> lqw = buildQueryWrapper(bo);
Page<ErpProjectChangeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @return
*/
@Override
public List<ErpProjectChangeVo> queryList(ErpProjectChangeBo bo) {
MPJLambdaWrapper<ErpProjectChange> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private MPJLambdaWrapper<ErpProjectChange> buildQueryWrapper(ErpProjectChangeBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<ErpProjectChange> lqw = JoinWrappers.lambda(ErpProjectChange.class)
.selectAll(ErpProjectChange.class)
.eq(ErpProjectChange::getDelFlag, "0")
.eq(bo.getProjectId() != null, ErpProjectChange::getProjectId, bo.getProjectId())
.eq(StringUtils.isNotBlank(bo.getProjectCode()), ErpProjectChange::getProjectCode, bo.getProjectCode())
.like(StringUtils.isNotBlank(bo.getProjectName()), ErpProjectChange::getProjectName, bo.getProjectName())
.eq(StringUtils.isNotBlank(bo.getProjectCategory()), ErpProjectChange::getProjectCategory, bo.getProjectCategory())
.eq(StringUtils.isNotBlank(bo.getChangeType()), ErpProjectChange::getChangeType, bo.getChangeType())
.eq(bo.getChangeNumber() != null, ErpProjectChange::getChangeNumber, bo.getChangeNumber())
.eq(bo.getProjectManagerId() != null, ErpProjectChange::getProjectManagerId, bo.getProjectManagerId())
.like(StringUtils.isNotBlank(bo.getProjectManagerName()), ErpProjectChange::getProjectManagerName, bo.getProjectManagerName())
.eq(bo.getDeptHeadId() != null, ErpProjectChange::getDeptHeadId, bo.getDeptHeadId())
.like(StringUtils.isNotBlank(bo.getDeptHeadName()), ErpProjectChange::getDeptHeadName, bo.getDeptHeadName())
.eq(bo.getResponsibleVpId() != null, ErpProjectChange::getResponsibleVpId, bo.getResponsibleVpId())
.like(StringUtils.isNotBlank(bo.getResponsibleVpName()), ErpProjectChange::getResponsibleVpName, bo.getResponsibleVpName())
.eq(bo.getApplyChangeDate() != null, ErpProjectChange::getApplyChangeDate, bo.getApplyChangeDate())
.eq(bo.getContractAmount() != null, ErpProjectChange::getContractAmount, bo.getContractAmount())
.eq(bo.getContractNetAmount() != null, ErpProjectChange::getContractNetAmount, bo.getContractNetAmount())
.eq(StringUtils.isNotBlank(bo.getCurrentStatus()), ErpProjectChange::getCurrentStatus, bo.getCurrentStatus())
.eq(StringUtils.isNotBlank(bo.getChangeReason()), ErpProjectChange::getChangeReason, bo.getChangeReason())
.eq(StringUtils.isNotBlank(bo.getFollowUpWork()), ErpProjectChange::getFollowUpWork, bo.getFollowUpWork())
.eq(StringUtils.isNotBlank(bo.getProjectChangeStatus()), ErpProjectChange::getProjectChangeStatus, bo.getProjectChangeStatus())
.eq(StringUtils.isNotBlank(bo.getFlowStatus()), ErpProjectChange::getFlowStatus, bo.getFlowStatus())
.eq(StringUtils.isNotBlank(bo.getActiveFlag()), ErpProjectChange::getActiveFlag, bo.getActiveFlag())
;
return lqw;
}
/**
*
*
* @param bo
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(ErpProjectChangeBo bo) {
ErpProjectChange add = MapstructUtils.convert(bo, ErpProjectChange.class);
validEntityBeforeSave(add);
List<ErpProjectChangeBudget> budgetList = bo.getBudgetList();
List<ErpProjectChangeProgress> progressList = bo.getProgressList();
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setProjectChangeId(add.getProjectChangeId());
// 保存预算变更明细
if (ObjectUtils.isNotEmpty(budgetList)) {
for (ErpProjectChangeBudget budget : budgetList) {
budget.setProjectChangeId(add.getProjectChangeId());
changeBudgetMapper.insert(budget);
}
}
// 保存进度变更明细
if (ObjectUtils.isNotEmpty(progressList)) {
for (ErpProjectChangeProgress progress : progressList) {
progress.setProjectChangeId(add.getProjectChangeId());
changeProgressMapper.insert(progress);
}
}
}
return flag;
}
/**
*
*
* @param bo
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(ErpProjectChangeBo bo) {
ErpProjectChange update = MapstructUtils.convert(bo, ErpProjectChange.class);
validEntityBeforeSave(update);
List<ErpProjectChangeBudget> budgetList = bo.getBudgetList();
List<ErpProjectChangeProgress> progressList = bo.getProgressList();
// 处理预算变更明细
if (budgetList != null && !budgetList.isEmpty()) {
for (ErpProjectChangeBudget budget : budgetList) {
budget.setProjectChangeId(bo.getProjectChangeId());
changeBudgetMapper.insertOrUpdate(budget);
}
// 删除前端未提交的旧数据
Set<Long> existingBudgetIds = budgetList.stream()
.map(ErpProjectChangeBudget::getChangeBudgetId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
MPJLambdaWrapper<ErpProjectChangeBudget> budgetLqw = JoinWrappers.lambda(ErpProjectChangeBudget.class);
budgetLqw.eq(ErpProjectChangeBudget::getProjectChangeId, bo.getProjectChangeId());
List<ErpProjectChangeBudget> oldBudgetList = changeBudgetMapper.selectList(budgetLqw);
oldBudgetList.stream()
.filter(budget -> !existingBudgetIds.contains(budget.getChangeBudgetId()))
.forEach(budget -> changeBudgetMapper.deleteById(budget.getChangeBudgetId()));
}
// 处理进度变更明细
if (progressList != null && !progressList.isEmpty()) {
for (ErpProjectChangeProgress progress : progressList) {
progress.setProjectChangeId(bo.getProjectChangeId());
changeProgressMapper.insertOrUpdate(progress);
}
// 删除前端未提交的旧数据
Set<Long> existingProgressIds = progressList.stream()
.map(ErpProjectChangeProgress::getChangeProgressId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
MPJLambdaWrapper<ErpProjectChangeProgress> progressLqw = JoinWrappers.lambda(ErpProjectChangeProgress.class);
progressLqw.eq(ErpProjectChangeProgress::getProjectChangeId, bo.getProjectChangeId());
List<ErpProjectChangeProgress> oldProgressList = changeProgressMapper.selectList(progressLqw);
oldProgressList.stream()
.filter(progress -> !existingProgressIds.contains(progress.getChangeProgressId()))
.forEach(progress -> changeProgressMapper.deleteById(progress.getChangeProgressId()));
}
return baseMapper.updateById(update) > 0;
}
/**
*
*/
private void validEntityBeforeSave(ErpProjectChange entity){
//TODO 做一些数据校验,如唯一约束
}
/**
*
*
* @param ids
* @param isValid
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
// 先删除子表
changeBudgetMapper.delete(Wrappers.<ErpProjectChangeBudget>lambdaQuery().in(ErpProjectChangeBudget::getProjectChangeId, ids));
changeProgressMapper.delete(Wrappers.<ErpProjectChangeProgress>lambdaQuery().in(ErpProjectChangeProgress::getProjectChangeId, ids));
// 删除主表
baseMapper.deleteByIds(ids);
//删除工作流
List<Long> businessIds = ids.stream().toList();
return remoteWorkflowService.deleteInstance(businessIds);
}
/**
* ID
*
* @param projectId ID
* @return
*/
@Override
public ErpProjectChangeVo prepareByProjectWithInfo(Long projectId) {
if (projectId == null) {
throw new ServiceException("项目ID不能为空");
}
// 若存在审批中的项目变更则禁止再次发起
long approvingCount = baseMapper.selectCount(Wrappers.<ErpProjectChange>lambdaQuery()
.eq(ErpProjectChange::getProjectId, projectId)
.eq(ErpProjectChange::getDelFlag, "0")
.eq(ErpProjectChange::getProjectChangeStatus, OAStatusEnum.APPROVING.getStatus()));// "2"审批中,"3"可用
if (approvingCount > 0) {
throw new ServiceException("该项目存在未完成的变更申请,请等待审批完成后再发起新的变更");
}
// 如果已有暂存记录,返回该记录供继续编辑
ErpProjectChange draftChange = baseMapper.selectOne(Wrappers.<ErpProjectChange>lambdaQuery()
.eq(ErpProjectChange::getProjectId, projectId)
.eq(ErpProjectChange::getDelFlag, "0")
.eq(ErpProjectChange::getProjectChangeStatus, "1")
.orderByDesc(ErpProjectChange::getCreateTime)
.last("limit 1"));
if (draftChange != null) {
return queryById(draftChange.getProjectChangeId());
}
// 通过自定义Mapper方法查询项目信息和用户名称连表查询sys_user
ErpProjectChangeVo vo = baseMapper.prepareByProjectId(projectId);
if (vo == null) {
throw new ServiceException("项目不存在");
}
// 查询项目计划信息
MPJLambdaWrapper<ErpProjectPlan> planLqw = JoinWrappers.lambda(ErpProjectPlan.class)
.eq(ErpProjectPlan::getProjectId, projectId)
.eq(ErpProjectPlan::getDelFlag, "0");
ErpProjectPlan projectPlan = projectPlanMapper.selectOne(planLqw);
if (projectPlan != null) {
// 查询项目计划阶段
MPJLambdaWrapper<ErpProjectPlanStage> stageLqw = JoinWrappers.lambda(ErpProjectPlanStage.class)
.eq(ErpProjectPlanStage::getProjectPlanId, projectPlan.getProjectPlanId())
.eq(ErpProjectPlanStage::getDelFlag, "0")
.orderByAsc(ErpProjectPlanStage::getSortOrder);
List<ErpProjectPlanStage> planStageList = planStageMapper.selectList(stageLqw);
// 将项目阶段转换为进度变更明细
if (ObjectUtils.isNotEmpty(planStageList)) {
List<ErpProjectChangeProgress> progressList = planStageList.stream().map(stage -> {
ErpProjectChangeProgress progress = new ErpProjectChangeProgress();
progress.setPlanStageId(stage.getPlanStageId()); // 绑定项目计划阶段ID
progress.setProjectPhases(stage.getProjectPhases()); // 项目阶段字典值(禁用显示)
progress.setMilestoneName(""); // 里程碑名称由用户手动输入
progress.setOriginalStart(stage.getPlanStartTime()); // 原计划开始时间
progress.setOriginalEnd(stage.getPlanEndTime()); // 原计划结束时间
progress.setChangedStart(stage.getPlanStartTime()); // 初始值设为原计划时间
progress.setChangedEnd(stage.getPlanEndTime()); // 初始值设为原计划时间
progress.setSortOrder(stage.getSortOrder()); // 排序顺序
return progress;
}).collect(Collectors.toList());
vo.setProgressList(progressList);
}
}
// 初始化空的预算变更列表(由用户手动添加)
vo.setBudgetList(new ArrayList<>());
// 计算变更次数:查询该项目已完成的变更次数
MPJLambdaWrapper<ErpProjectChange> changeCountLqw = JoinWrappers.lambda(ErpProjectChange.class)
.eq(ErpProjectChange::getProjectId, projectId)
.eq(ErpProjectChange::getDelFlag, "0")
.eq(ErpProjectChange::getProjectChangeStatus, OAStatusEnum.COMPLETED.getStatus());
int changeCount = Math.toIntExact(baseMapper.selectCount(changeCountLqw));
vo.setChangeNumber(changeCount + 1); // 当前变更次数 = 已有次数 + 1
// 设置默认值
vo.setActiveFlag("1");
vo.setProjectChangeStatus("1"); // 1-暂存
return vo;
}
/**
*
*
* @param bo
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public ErpProjectChangeVo projectChangeSubmitAndFlowStart(ErpProjectChangeBo bo) {
ErpProjectChange add = MapstructUtils.convert(bo, ErpProjectChange.class);
validEntityBeforeSave(add) ;
// 权限校验:只有项目经理才能提交
validateProjectManager(bo.getProjectManagerId());
// 保存或更新项目变更数据
boolean saveFlag;
if (bo.getProjectChangeId() == null) {
saveFlag = insertByBo(bo);
} else {
saveFlag = updateByBo(bo);
}
if (!saveFlag) {
throw new ServiceException("保存项目变更失败");
}
// 后端发起需要忽略权限
bo.getVariables().put("ignore", true);
RemoteStartProcess startProcess = new RemoteStartProcess();
startProcess.setBusinessId(bo.getProjectChangeId().toString());
startProcess.setFlowCode(bo.getFlowCode());
startProcess.setVariables(bo.getVariables());
startProcess.setBizExt(bo.getBizExt());
bo.getBizExt().setBusinessId(startProcess.getBusinessId());
boolean flagOne = remoteWorkflowService.startCompleteTask(startProcess);
if (!flagOne) {
throw new ServiceException("流程发起异常");
}
return MapstructUtils.convert(add, ErpProjectChangeVo.class);
}
/**
*
*
* @param processEvent
*/
@EventListener(condition = "#processEvent.flowCode == 'OAEP'")
public void processHandler(ProcessEvent processEvent) {
TenantHelper.dynamic(processEvent.getTenantId(), () -> {
ErpProjectChange projectChange = baseMapper.selectById(Convert.toLong(processEvent.getBusinessId()));
projectChange.setFlowStatus(processEvent.getStatus());
Map<String, Object> params = processEvent.getParams();
if (MapUtil.isNotEmpty( params)){
// 办理人
String handler = Convert.toStr(params.get("handler"));
}
if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.FINISH.getStatus())){
projectChange.setProjectChangeStatus(OAStatusEnum.COMPLETED.getStatus());
}
baseMapper.updateById(projectChange);
});
}
/**
*
*
* @param projectManagerId ID
*/
private void validateProjectManager(Long projectManagerId) {
// 超级管理员跳过校验
if (LoginHelper.isSuperAdmin()) {
return;
}
Long currentUserId = LoginHelper.getUserId();
if (!currentUserId.equals(projectManagerId)) {
throw new ServiceException("只有项目经理才能提交项目变更申请");
}
}
}

@ -0,0 +1,192 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.oa.erp.mapper.ErpProjectChangeBudgetMapper">
<resultMap type="org.dromara.oa.erp.domain.vo.ErpProjectChangeBudgetVo" id="ErpProjectChangeBudgetResult">
</resultMap>
<select id="selectCustomErpProjectChangeBudgetVoList" resultMap="ErpProjectChangeBudgetResult">
select change_budget_id, project_change_id, budget_detail_id, subject_name, budget_before, budget_after, amount_used, adjustment_reason, sort_order, remark, del_flag, create_dept, create_by, create_time, update_by, update_time from erp_project_change_budget t
${ew.getCustomSqlSegment}
</select>
<!-- 根据ID查询详情 -->
<select id="selectCustomErpProjectChangeBudgetVoById" resultMap="ErpProjectChangeBudgetResult">
select change_budget_id, project_change_id, budget_detail_id, subject_name, budget_before, budget_after, amount_used, adjustment_reason, sort_order, remark, del_flag, create_dept, create_by, create_time, update_by, update_time
from erp_project_change_budget t
where t.change_budget_id = #{changeBudgetId}
</select>
<!-- 批量查询 - 根据ID列表 -->
<select id="selectCustomErpProjectChangeBudgetVoByIds" resultMap="ErpProjectChangeBudgetResult">
select change_budget_id, project_change_id, budget_detail_id, subject_name, budget_before, budget_after, amount_used, adjustment_reason, sort_order, remark, del_flag, create_dept, create_by, create_time, update_by, update_time
from erp_project_change_budget t
where t.change_budget_id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<!-- 统计查询 -->
<select id="countCustomErpProjectChangeBudget" resultType="java.lang.Long">
select count(1) from erp_project_change_budget t
${ew.getCustomSqlSegment}
</select>
<!-- 分页查询(带自定义条件) -->
<select id="selectCustomErpProjectChangeBudgetVoPage" resultMap="ErpProjectChangeBudgetResult">
select change_budget_id, project_change_id, budget_detail_id, subject_name, budget_before, budget_after, amount_used, adjustment_reason, sort_order, remark, del_flag, create_dept, create_by, create_time, update_by, update_time
from erp_project_change_budget t
${ew.getCustomSqlSegment}
</select>
<!-- 批量插入 -->
<insert id="batchInsertErpProjectChangeBudget">
insert into erp_project_change_budget(
project_change_id,
budget_detail_id,
subject_name,
budget_before,
budget_after,
amount_used,
adjustment_reason,
sort_order,
remark,
del_flag,
create_dept,
create_by,
create_time,
update_by,
update_time
)
values
<foreach collection="list" item="item" separator=",">
(
#{item.projectChangeId},
#{item.budgetDetailId},
#{item.subjectName},
#{item.budgetBefore},
#{item.budgetAfter},
#{item.amountUsed},
#{item.adjustmentReason},
#{item.sortOrder},
#{item.remark},
#{item.delFlag},
#{item.createDept},
#{item.createBy},
#{item.createTime},
#{item.updateBy},
#{item.updateTime}
)
</foreach>
</insert>
<!-- 批量更新 -->
<update id="batchUpdateErpProjectChangeBudget">
<foreach collection="list" item="item" separator=";">
update erp_project_change_budget
<set>
<if test="item.projectChangeId != null">
project_change_id = #{item.projectChangeId},
</if>
<if test="item.budgetDetailId != null">
budget_detail_id = #{item.budgetDetailId},
</if>
<if test="item.subjectName != null and item.subjectName != ''">
subject_name = #{item.subjectName},
</if>
<if test="item.budgetBefore != null">
budget_before = #{item.budgetBefore},
</if>
<if test="item.budgetAfter != null">
budget_after = #{item.budgetAfter},
</if>
<if test="item.amountUsed != null">
amount_used = #{item.amountUsed},
</if>
<if test="item.adjustmentReason != null and item.adjustmentReason != ''">
adjustment_reason = #{item.adjustmentReason},
</if>
<if test="item.sortOrder != null">
sort_order = #{item.sortOrder},
</if>
<if test="item.remark != null and item.remark != ''">
remark = #{item.remark},
</if>
<if test="item.delFlag != null and item.delFlag != ''">
del_flag = #{item.delFlag},
</if>
<if test="item.createDept != null">
create_dept = #{item.createDept},
</if>
<if test="item.createBy != null">
create_by = #{item.createBy},
</if>
<if test="item.createTime != null">
create_time = #{item.createTime},
</if>
<if test="item.updateBy != null">
update_by = #{item.updateBy},
</if>
<if test="item.updateTime != null">
update_time = #{item.updateTime}
</if>
</set>
where change_budget_id = #{item.changeBudgetId}
</foreach>
</update>
<!-- 根据自定义条件删除 -->
<delete id="deleteCustomErpProjectChangeBudget">
delete from erp_project_change_budget
${ew.getCustomSqlSegment}
</delete>
<!-- 根据ID列表批量删除 -->
<delete id="deleteCustomErpProjectChangeBudgetByIds">
delete from erp_project_change_budget
where change_budget_id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<!-- 检查是否存在 -->
<select id="existsErpProjectChangeBudget" resultType="java.lang.Boolean">
select count(1) > 0 from erp_project_change_budget t
${ew.getCustomSqlSegment}
</select>
</mapper>

@ -0,0 +1,333 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.oa.erp.mapper.ErpProjectChangeMapper">
<resultMap type="org.dromara.oa.erp.domain.vo.ErpProjectChangeVo" id="ErpProjectChangeResult">
</resultMap>
<select id="selectCustomErpProjectChangeVoList" resultMap="ErpProjectChangeResult">
select t.project_change_id, t.tenant_id, t.project_id, t.project_code, t.project_name, t.project_category,
t.change_type, t.change_number, t.project_manager_id, t.dept_head_id, t.responsible_vp_id,
t.apply_change_date, t.contract_amount, t.contract_net_amount, t.current_status, t.change_reason,
t.follow_up_work, t.project_change_status, t.flow_status, t.remark, t.active_flag, t.del_flag,
t.create_dept, t.create_by, t.create_time, t.update_by, t.update_time,
u1.nick_name as project_manager_name,
u2.nick_name as dept_head_name,
u3.nick_name as responsible_vp_name
from erp_project_change t
left join sys_user u1 on t.project_manager_id = u1.user_id
left join sys_user u2 on t.dept_head_id = u2.user_id
left join sys_user u3 on t.responsible_vp_id = u3.user_id
${ew.getCustomSqlSegment}
</select>
<!-- 根据ID查询详情 -->
<select id="selectCustomErpProjectChangeVoById" resultMap="ErpProjectChangeResult">
select t.project_change_id, t.tenant_id, t.project_id, t.project_code, t.project_name, t.project_category,
t.change_type, t.change_number, t.project_manager_id, t.dept_head_id, t.responsible_vp_id,
t.apply_change_date, t.contract_amount, t.contract_net_amount, t.current_status, t.change_reason,
t.follow_up_work, t.project_change_status, t.flow_status, t.remark, t.active_flag, t.del_flag,
t.create_dept, t.create_by, t.create_time, t.update_by, t.update_time,
u1.nick_name as project_manager_name,
u2.nick_name as dept_head_name,
u3.nick_name as responsible_vp_name
from erp_project_change t
left join sys_user u1 on t.project_manager_id = u1.user_id
left join sys_user u2 on t.dept_head_id = u2.user_id
left join sys_user u3 on t.responsible_vp_id = u3.user_id
where t.project_change_id = #{projectChangeId}
</select>
<!-- 批量查询 - 根据ID列表 -->
<select id="selectCustomErpProjectChangeVoByIds" resultMap="ErpProjectChangeResult">
select project_change_id, tenant_id, project_id, project_code, project_name, project_category, change_type, change_number, project_manager_id, project_manager_name, dept_head_id, dept_head_name, responsible_vp_id, responsible_vp_name, apply_change_date, contract_amount, contract_net_amount, current_status, change_reason, follow_up_work, project_change_status, flow_status, remark, active_flag, del_flag, create_dept, create_by, create_time, update_by, update_time
from erp_project_change t
where t.project_change_id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<!-- 统计查询 -->
<select id="countCustomErpProjectChange" resultType="java.lang.Long">
select count(1) from erp_project_change t
${ew.getCustomSqlSegment}
</select>
<!-- 分页查询(带自定义条件) -->
<select id="selectCustomErpProjectChangeVoPage" resultMap="ErpProjectChangeResult">
select project_change_id, tenant_id, project_id, project_code, project_name, project_category, change_type, change_number, project_manager_id, project_manager_name, dept_head_id, dept_head_name, responsible_vp_id, responsible_vp_name, apply_change_date, contract_amount, contract_net_amount, current_status, change_reason, follow_up_work, project_change_status, flow_status, remark, active_flag, del_flag, create_dept, create_by, create_time, update_by, update_time
from erp_project_change t
${ew.getCustomSqlSegment}
</select>
<!-- 批量插入 -->
<insert id="batchInsertErpProjectChange">
insert into erp_project_change(
tenant_id,
project_id,
project_code,
project_name,
project_category,
change_type,
change_number,
project_manager_id,
project_manager_name,
dept_head_id,
dept_head_name,
responsible_vp_id,
responsible_vp_name,
apply_change_date,
contract_amount,
contract_net_amount,
current_status,
change_reason,
follow_up_work,
project_change_status,
flow_status,
remark,
active_flag,
del_flag,
create_dept,
create_by,
create_time,
update_by,
update_time
)
values
<foreach collection="list" item="item" separator=",">
(
#{item.tenantId},
#{item.projectId},
#{item.projectCode},
#{item.projectName},
#{item.projectCategory},
#{item.changeType},
#{item.changeNumber},
#{item.projectManagerId},
#{item.projectManagerName},
#{item.deptHeadId},
#{item.deptHeadName},
#{item.responsibleVpId},
#{item.responsibleVpName},
#{item.applyChangeDate},
#{item.contractAmount},
#{item.contractNetAmount},
#{item.currentStatus},
#{item.changeReason},
#{item.followUpWork},
#{item.projectChangeStatus},
#{item.flowStatus},
#{item.remark},
#{item.activeFlag},
#{item.delFlag},
#{item.createDept},
#{item.createBy},
#{item.createTime},
#{item.updateBy},
#{item.updateTime}
)
</foreach>
</insert>
<!-- 批量更新 -->
<update id="batchUpdateErpProjectChange">
<foreach collection="list" item="item" separator=";">
update erp_project_change
<set>
<if test="item.tenantId != null and item.tenantId != ''">
tenant_id = #{item.tenantId},
</if>
<if test="item.projectId != null">
project_id = #{item.projectId},
</if>
<if test="item.projectCode != null and item.projectCode != ''">
project_code = #{item.projectCode},
</if>
<if test="item.projectName != null and item.projectName != ''">
project_name = #{item.projectName},
</if>
<if test="item.projectCategory != null and item.projectCategory != ''">
project_category = #{item.projectCategory},
</if>
<if test="item.changeType != null and item.changeType != ''">
change_type = #{item.changeType},
</if>
<if test="item.changeNumber != null">
change_number = #{item.changeNumber},
</if>
<if test="item.projectManagerId != null">
project_manager_id = #{item.projectManagerId},
</if>
<if test="item.projectManagerName != null and item.projectManagerName != ''">
project_manager_name = #{item.projectManagerName},
</if>
<if test="item.deptHeadId != null">
dept_head_id = #{item.deptHeadId},
</if>
<if test="item.deptHeadName != null and item.deptHeadName != ''">
dept_head_name = #{item.deptHeadName},
</if>
<if test="item.responsibleVpId != null">
responsible_vp_id = #{item.responsibleVpId},
</if>
<if test="item.responsibleVpName != null and item.responsibleVpName != ''">
responsible_vp_name = #{item.responsibleVpName},
</if>
<if test="item.applyChangeDate != null">
apply_change_date = #{item.applyChangeDate},
</if>
<if test="item.contractAmount != null">
contract_amount = #{item.contractAmount},
</if>
<if test="item.contractNetAmount != null">
contract_net_amount = #{item.contractNetAmount},
</if>
<if test="item.currentStatus != null and item.currentStatus != ''">
current_status = #{item.currentStatus},
</if>
<if test="item.changeReason != null and item.changeReason != ''">
change_reason = #{item.changeReason},
</if>
<if test="item.followUpWork != null and item.followUpWork != ''">
follow_up_work = #{item.followUpWork},
</if>
<if test="item.projectChangeStatus != null and item.projectChangeStatus != ''">
project_change_status = #{item.projectChangeStatus},
</if>
<if test="item.flowStatus != null and item.flowStatus != ''">
flow_status = #{item.flowStatus},
</if>
<if test="item.remark != null and item.remark != ''">
remark = #{item.remark},
</if>
<if test="item.activeFlag != null and item.activeFlag != ''">
active_flag = #{item.activeFlag},
</if>
<if test="item.delFlag != null and item.delFlag != ''">
del_flag = #{item.delFlag},
</if>
<if test="item.createDept != null">
create_dept = #{item.createDept},
</if>
<if test="item.createBy != null">
create_by = #{item.createBy},
</if>
<if test="item.createTime != null">
create_time = #{item.createTime},
</if>
<if test="item.updateBy != null">
update_by = #{item.updateBy},
</if>
<if test="item.updateTime != null">
update_time = #{item.updateTime}
</if>
</set>
where project_change_id = #{item.projectChangeId}
</foreach>
</update>
<!-- 根据自定义条件删除 -->
<delete id="deleteCustomErpProjectChange">
delete from erp_project_change
${ew.getCustomSqlSegment}
</delete>
<!-- 根据ID列表批量删除 -->
<delete id="deleteCustomErpProjectChangeByIds">
delete from erp_project_change
where project_change_id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<!-- 检查是否存在 -->
<select id="existsErpProjectChange" resultType="java.lang.Boolean">
select count(1) > 0 from erp_project_change t
${ew.getCustomSqlSegment}
</select>
<!-- 根据项目ID准备项目变更信息带出项目信息和用户名称 -->
<select id="prepareByProjectId" resultMap="ErpProjectChangeResult">
select
pi.project_id,
pi.project_code,
pi.project_name,
pi.project_category,
pi.manager_id as project_manager_id,
pi.charge_id as dept_head_id,
pi.deputy_id as responsible_vp_id,
pi.amount as contract_amount,
pi.amount as contract_net_amount,
u1.nick_name as project_manager_name,
u2.nick_name as dept_head_name,
u3.nick_name as responsible_vp_name
from erp_project_info pi
left join sys_user u1 on pi.manager_id = u1.user_id
left join sys_user u2 on pi.charge_id = u2.user_id
left join sys_user u3 on pi.deputy_id = u3.user_id
where pi.project_id = #{projectId}
</select>
</mapper>

@ -0,0 +1,199 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.oa.erp.mapper.ErpProjectChangeProgressMapper">
<resultMap type="org.dromara.oa.erp.domain.vo.ErpProjectChangeProgressVo" id="ErpProjectChangeProgressResult">
</resultMap>
<select id="selectCustomErpProjectChangeProgressVoList" resultMap="ErpProjectChangeProgressResult">
select change_progress_id, project_change_id, plan_stage_id, milestone_name, original_start, original_end, changed_start, changed_end, completion_degree, sort_order, remark, del_flag, create_dept, create_by, create_time, update_by, update_time from erp_project_change_progress t
${ew.getCustomSqlSegment}
</select>
<!-- 根据ID查询详情 -->
<select id="selectCustomErpProjectChangeProgressVoById" resultMap="ErpProjectChangeProgressResult">
select change_progress_id, project_change_id, plan_stage_id, milestone_name, original_start, original_end, changed_start, changed_end, completion_degree, sort_order, remark, del_flag, create_dept, create_by, create_time, update_by, update_time
from erp_project_change_progress t
where t.change_progress_id = #{changeProgressId}
</select>
<!-- 批量查询 - 根据ID列表 -->
<select id="selectCustomErpProjectChangeProgressVoByIds" resultMap="ErpProjectChangeProgressResult">
select change_progress_id, project_change_id, plan_stage_id, milestone_name, original_start, original_end, changed_start, changed_end, completion_degree, sort_order, remark, del_flag, create_dept, create_by, create_time, update_by, update_time
from erp_project_change_progress t
where t.change_progress_id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<!-- 统计查询 -->
<select id="countCustomErpProjectChangeProgress" resultType="java.lang.Long">
select count(1) from erp_project_change_progress t
${ew.getCustomSqlSegment}
</select>
<!-- 分页查询(带自定义条件) -->
<select id="selectCustomErpProjectChangeProgressVoPage" resultMap="ErpProjectChangeProgressResult">
select change_progress_id, project_change_id, plan_stage_id, milestone_name, original_start, original_end, changed_start, changed_end, completion_degree, sort_order, remark, del_flag, create_dept, create_by, create_time, update_by, update_time
from erp_project_change_progress t
${ew.getCustomSqlSegment}
</select>
<!-- 批量插入 -->
<insert id="batchInsertErpProjectChangeProgress">
insert into erp_project_change_progress(
project_change_id,
plan_stage_id,
milestone_name,
original_start,
original_end,
changed_start,
changed_end,
completion_degree,
sort_order,
remark,
del_flag,
create_dept,
create_by,
create_time,
update_by,
update_time
)
values
<foreach collection="list" item="item" separator=",">
(
#{item.projectChangeId},
#{item.planStageId},
#{item.milestoneName},
#{item.originalStart},
#{item.originalEnd},
#{item.changedStart},
#{item.changedEnd},
#{item.completionDegree},
#{item.sortOrder},
#{item.remark},
#{item.delFlag},
#{item.createDept},
#{item.createBy},
#{item.createTime},
#{item.updateBy},
#{item.updateTime}
)
</foreach>
</insert>
<!-- 批量更新 -->
<update id="batchUpdateErpProjectChangeProgress">
<foreach collection="list" item="item" separator=";">
update erp_project_change_progress
<set>
<if test="item.projectChangeId != null">
project_change_id = #{item.projectChangeId},
</if>
<if test="item.planStageId != null">
plan_stage_id = #{item.planStageId},
</if>
<if test="item.milestoneName != null and item.milestoneName != ''">
milestone_name = #{item.milestoneName},
</if>
<if test="item.originalStart != null">
original_start = #{item.originalStart},
</if>
<if test="item.originalEnd != null">
original_end = #{item.originalEnd},
</if>
<if test="item.changedStart != null">
changed_start = #{item.changedStart},
</if>
<if test="item.changedEnd != null">
changed_end = #{item.changedEnd},
</if>
<if test="item.completionDegree != null">
completion_degree = #{item.completionDegree},
</if>
<if test="item.sortOrder != null">
sort_order = #{item.sortOrder},
</if>
<if test="item.remark != null and item.remark != ''">
remark = #{item.remark},
</if>
<if test="item.delFlag != null and item.delFlag != ''">
del_flag = #{item.delFlag},
</if>
<if test="item.createDept != null">
create_dept = #{item.createDept},
</if>
<if test="item.createBy != null">
create_by = #{item.createBy},
</if>
<if test="item.createTime != null">
create_time = #{item.createTime},
</if>
<if test="item.updateBy != null">
update_by = #{item.updateBy},
</if>
<if test="item.updateTime != null">
update_time = #{item.updateTime}
</if>
</set>
where change_progress_id = #{item.changeProgressId}
</foreach>
</update>
<!-- 根据自定义条件删除 -->
<delete id="deleteCustomErpProjectChangeProgress">
delete from erp_project_change_progress
${ew.getCustomSqlSegment}
</delete>
<!-- 根据ID列表批量删除 -->
<delete id="deleteCustomErpProjectChangeProgressByIds">
delete from erp_project_change_progress
where change_progress_id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<!-- 检查是否存在 -->
<select id="existsErpProjectChangeProgress" resultType="java.lang.Boolean">
select count(1) > 0 from erp_project_change_progress t
${ew.getCustomSqlSegment}
</select>
</mapper>

@ -0,0 +1,22 @@
致:
{customerContactName}
{title}
报价日期 {quoteDate}
含税信息 {taxIncludedInfo}
付款方式 {paymentMethod}
交货期 {deliveryPeriod}
交货方式 {deliveryMethod}
报价有效期 {quoteValidity}
币种:{currencyType} 价格单位:元
序号 产品名称 型号/说明 数量 单位 单价 小计 备注
{data.seq} {data.productName} {data.modelDesc} {data.quantity} {data.unit} {data.price} {data.subtotal} {data.remark}
合计 {total}
小写: {totalLower} 大写: {totalUpper}
注:
"供货方信息:
公司名称:青岛海威物联科技有限公司
公司地址青岛市市北区郑州路43号
公司网址www.highwayiot.com " " 联 系 人:
联系电话:
电子邮件:"
Loading…
Cancel
Save