feat(asset): enhance return order with inspection, BPM approval, and event-driven cross-module linkage
- Add sourceType/sourceId/deliveryOrderId to return order table and DO - Add inspectionRecordId to return order vehicle table and DO - Add createFromDelivery/createFromReplacement methods to auto-create return orders - Add startVehicleInspection/completeVehicleInspection for per-vehicle inspection flow - Add submitApproval/withdrawApproval/updateApprovalStatus for BPM workflow - Create ReturnApprovedEvent and ReturnOrderBpmListener - Create DeliveryCompletedEvent for future vehicle status tracking - Create VehicleStatusEventListener (TODO stubs for vehicle status updates) - Create ReturnOrderEventListener to auto-create return order on permanent replacement approval - Add BPM process definitions for replacement (with GM escalation) and return order approval Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
9
sql/2026-03-13-return-order-enhance.sql
Normal file
9
sql/2026-03-13-return-order-enhance.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
-- 还车单增强:添加来源类型、来源ID、关联交车单ID
|
||||
ALTER TABLE asset_return_order
|
||||
ADD COLUMN source_type tinyint DEFAULT NULL COMMENT '来源:1=手动 2=替换车触发',
|
||||
ADD COLUMN source_id bigint DEFAULT NULL COMMENT '来源业务ID',
|
||||
ADD COLUMN delivery_order_id bigint DEFAULT NULL COMMENT '关联交车单ID';
|
||||
|
||||
-- 还车车辆增强:添加验车记录关联
|
||||
ALTER TABLE asset_return_order_vehicle
|
||||
ADD COLUMN inspection_record_id bigint DEFAULT NULL COMMENT '关联验车记录';
|
||||
@@ -0,0 +1,132 @@
|
||||
package cn.iocoder.yudao.module.asset.controller.admin.returnorder;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.*;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderDO;
|
||||
import cn.iocoder.yudao.module.asset.service.returnorder.ReturnOrderService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 还车管理")
|
||||
@RestController
|
||||
@RequestMapping("/asset/return-order")
|
||||
@Validated
|
||||
public class ReturnOrderController {
|
||||
|
||||
@Resource
|
||||
private ReturnOrderService returnOrderService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建还车单")
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:create')")
|
||||
public CommonResult<Long> createReturnOrder(@Valid @RequestBody ReturnOrderSaveReqVO createReqVO) {
|
||||
return success(returnOrderService.createReturnOrder(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新还车单")
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||
public CommonResult<Boolean> updateReturnOrder(@Valid @RequestBody ReturnOrderSaveReqVO updateReqVO) {
|
||||
returnOrderService.updateReturnOrder(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除还车单")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:delete')")
|
||||
public CommonResult<Boolean> deleteReturnOrder(@RequestParam("id") Long id) {
|
||||
returnOrderService.deleteReturnOrder(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得还车单详情")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:query')")
|
||||
public CommonResult<ReturnOrderRespVO> getReturnOrder(@RequestParam("id") Long id) {
|
||||
return success(returnOrderService.getReturnOrderDetail(id));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得还车单分页")
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:query')")
|
||||
public CommonResult<PageResult<ReturnOrderRespVO>> getReturnOrderPage(@Valid ReturnOrderPageReqVO pageReqVO) {
|
||||
PageResult<ReturnOrderDO> pageResult = returnOrderService.getReturnOrderPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, ReturnOrderRespVO.class));
|
||||
}
|
||||
|
||||
@PutMapping("/complete-inspection")
|
||||
@Operation(summary = "完成验车")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||
public CommonResult<Boolean> completeInspection(@RequestParam("id") Long id) {
|
||||
returnOrderService.completeInspection(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/settle")
|
||||
@Operation(summary = "结算还车单")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||
public CommonResult<Boolean> settleReturnOrder(@RequestParam("id") Long id) {
|
||||
returnOrderService.settleReturnOrder(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/create-from-delivery")
|
||||
@Operation(summary = "从交车单创建还车单")
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:create')")
|
||||
public CommonResult<Long> createFromDelivery(@RequestParam("deliveryOrderId") Long deliveryOrderId,
|
||||
@RequestParam("vehicleIds") List<Long> vehicleIds) {
|
||||
return success(returnOrderService.createFromDelivery(deliveryOrderId, vehicleIds));
|
||||
}
|
||||
|
||||
@PostMapping("/start-inspection")
|
||||
@Operation(summary = "开始单车验车")
|
||||
@Parameter(name = "returnOrderVehicleId", description = "还车车辆ID", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||
public CommonResult<Long> startVehicleInspection(@RequestParam("returnOrderVehicleId") Long returnOrderVehicleId) {
|
||||
return success(returnOrderService.startVehicleInspection(returnOrderVehicleId));
|
||||
}
|
||||
|
||||
@PostMapping("/complete-vehicle-inspection")
|
||||
@Operation(summary = "完成单车验车")
|
||||
@Parameter(name = "returnOrderVehicleId", description = "还车车辆ID", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||
public CommonResult<Boolean> completeVehicleInspection(@RequestParam("returnOrderVehicleId") Long returnOrderVehicleId) {
|
||||
returnOrderService.completeVehicleInspection(returnOrderVehicleId);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/submit")
|
||||
@Operation(summary = "提交审批")
|
||||
@Parameter(name = "id", description = "还车单ID", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||
public CommonResult<Boolean> submitApproval(@RequestParam("id") Long id) {
|
||||
returnOrderService.submitApproval(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/withdraw")
|
||||
@Operation(summary = "撤回审批")
|
||||
@Parameter(name = "id", description = "还车单ID", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||
public CommonResult<Boolean> withdrawApproval(@RequestParam("id") Long id) {
|
||||
returnOrderService.withdrawApproval(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package cn.iocoder.yudao.module.asset.dal.dataobject.returnorder;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 还车单 DO
|
||||
*/
|
||||
@TableName("asset_return_order")
|
||||
@KeySequence("asset_return_order_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReturnOrderDO extends BaseDO {
|
||||
|
||||
@TableId
|
||||
private Long id;
|
||||
private String orderCode;
|
||||
private Long contractId;
|
||||
private String contractCode;
|
||||
private String projectName;
|
||||
private Long customerId;
|
||||
private String customerName;
|
||||
private LocalDateTime returnDate;
|
||||
private String returnPerson;
|
||||
private String returnLocation;
|
||||
private String returnReason;
|
||||
private String returnReasonDesc;
|
||||
private BigDecimal totalRefundAmount;
|
||||
private BigDecimal depositRefund;
|
||||
private BigDecimal hydrogenRefund;
|
||||
private BigDecimal otherCharges;
|
||||
private String returnPhotos;
|
||||
/**
|
||||
* 状态(0=待验车 1=验车完成 2=已结算)
|
||||
*/
|
||||
private Integer status;
|
||||
private Integer approvalStatus;
|
||||
private String bpmInstanceId;
|
||||
/**
|
||||
* 来源:1=手动 2=替换车触发
|
||||
*/
|
||||
private Integer sourceType;
|
||||
/**
|
||||
* 来源业务ID
|
||||
*/
|
||||
private Long sourceId;
|
||||
/**
|
||||
* 关联交车单ID
|
||||
*/
|
||||
private Long deliveryOrderId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package cn.iocoder.yudao.module.asset.dal.dataobject.returnorder;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 还车车辆 DO
|
||||
*/
|
||||
@TableName("asset_return_order_vehicle")
|
||||
@KeySequence("asset_return_order_vehicle_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReturnOrderVehicleDO extends BaseDO {
|
||||
|
||||
@TableId
|
||||
private Long id;
|
||||
private Long returnOrderId;
|
||||
private Long vehicleId;
|
||||
private String plateNo;
|
||||
private String vin;
|
||||
private String brand;
|
||||
private String model;
|
||||
private Integer returnMileage;
|
||||
private BigDecimal returnHydrogenLevel;
|
||||
private BigDecimal deliveryHydrogenLevel;
|
||||
private BigDecimal hydrogenDiff;
|
||||
private BigDecimal hydrogenUnitPrice;
|
||||
private BigDecimal hydrogenRefundAmount;
|
||||
private String checkList;
|
||||
private String defectPhotos;
|
||||
private BigDecimal vehicleDamageFee;
|
||||
private BigDecimal toolDamageFee;
|
||||
private BigDecimal unpaidMaintenanceFee;
|
||||
private BigDecimal unpaidRepairFee;
|
||||
private BigDecimal violationFee;
|
||||
private BigDecimal otherFee;
|
||||
/**
|
||||
* 关联验车记录ID
|
||||
*/
|
||||
private Long inspectionRecordId;
|
||||
|
||||
}
|
||||
@@ -57,6 +57,11 @@ public interface ErrorCodeConstants {
|
||||
// ========== 还车单管理 1-008-010-000 ==========
|
||||
ErrorCode RETURN_ORDER_NOT_EXISTS = new ErrorCode(1_008_010_000, "还车单不存在");
|
||||
ErrorCode RETURN_ORDER_ALREADY_SETTLED = new ErrorCode(1_008_010_001, "还车单已结算");
|
||||
ErrorCode RETURN_ORDER_VEHICLE_NOT_EXISTS = new ErrorCode(1_008_010_002, "还车车辆不存在");
|
||||
ErrorCode RETURN_ORDER_STATUS_NOT_ALLOW_SUBMIT = new ErrorCode(1_008_010_003, "当前状态不允许提交审批");
|
||||
ErrorCode RETURN_ORDER_STATUS_NOT_ALLOW_WITHDRAW = new ErrorCode(1_008_010_004, "当前状态不允许撤回");
|
||||
ErrorCode RETURN_ORDER_INSPECTION_ALREADY_STARTED = new ErrorCode(1_008_010_005, "该车辆验车已开始");
|
||||
ErrorCode RETURN_ORDER_INSPECTION_NOT_STARTED = new ErrorCode(1_008_010_006, "该车辆验车未开始");
|
||||
|
||||
// ========== 验车模板管理 1-008-011-000 ==========
|
||||
ErrorCode INSPECTION_TEMPLATE_NOT_EXISTS = new ErrorCode(1_008_011_000, "验车模板不存在");
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.asset.service.delivery.event;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 交车完成事件
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class DeliveryCompletedEvent {
|
||||
|
||||
/**
|
||||
* 交车单ID
|
||||
*/
|
||||
private final Long deliveryOrderId;
|
||||
|
||||
/**
|
||||
* 车辆ID
|
||||
*/
|
||||
private final Long vehicleId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package cn.iocoder.yudao.module.asset.service.event;
|
||||
|
||||
import cn.iocoder.yudao.module.asset.enums.replacement.ReplacementTypeEnum;
|
||||
import cn.iocoder.yudao.module.asset.service.replacement.event.ReplacementApprovedEvent;
|
||||
import cn.iocoder.yudao.module.asset.service.returnorder.ReturnOrderService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 还车单事件监听器
|
||||
* 监听替换车审批通过事件,自动创建还车单
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ReturnOrderEventListener {
|
||||
|
||||
@Resource
|
||||
private ReturnOrderService returnOrderService;
|
||||
|
||||
/**
|
||||
* 永久替换审批通过时,自动创建还车单
|
||||
* 使用 @EventListener 而非 @TransactionalEventListener,确保在同一事务中执行
|
||||
*/
|
||||
@EventListener
|
||||
public void onReplacementApproved(ReplacementApprovedEvent event) {
|
||||
if (event.getReplacementType().equals(ReplacementTypeEnum.PERMANENT.getType())) {
|
||||
log.info("[onReplacementApproved] permanent replacement, creating return order: replacementId={}",
|
||||
event.getReplacementId());
|
||||
returnOrderService.createFromReplacement(
|
||||
event.getReplacementId(),
|
||||
event.getContractId(),
|
||||
event.getOriginalVehicleId()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package cn.iocoder.yudao.module.asset.service.event;
|
||||
|
||||
import cn.iocoder.yudao.module.asset.service.delivery.event.DeliveryCompletedEvent;
|
||||
import cn.iocoder.yudao.module.asset.service.replacement.event.ReplacementReturnConfirmedEvent;
|
||||
import cn.iocoder.yudao.module.asset.service.returnorder.event.ReturnApprovedEvent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
|
||||
/**
|
||||
* 车辆状态事件监听器
|
||||
* 负责在业务事件发生时更新车辆状态
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class VehicleStatusEventListener {
|
||||
|
||||
@TransactionalEventListener
|
||||
public void onDeliveryCompleted(DeliveryCompletedEvent event) {
|
||||
log.info("[onDeliveryCompleted] vehicleId={}", event.getVehicleId());
|
||||
// TODO: update vehicle status to DELIVERED when vehicle status management is implemented
|
||||
}
|
||||
|
||||
@TransactionalEventListener
|
||||
public void onReturnApproved(ReturnApprovedEvent event) {
|
||||
log.info("[onReturnApproved] vehicleIds={}", event.getVehicleIds());
|
||||
// TODO: update vehicle status to AVAILABLE when vehicle status management is implemented
|
||||
}
|
||||
|
||||
@TransactionalEventListener
|
||||
public void onReplacementReturnConfirmed(ReplacementReturnConfirmedEvent event) {
|
||||
log.info("[onReplacementReturnConfirmed] vehicleId={}", event.getOriginalVehicleId());
|
||||
// TODO: update vehicle status to AVAILABLE
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package cn.iocoder.yudao.module.asset.service.returnorder;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.ReturnOrderPageReqVO;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.ReturnOrderRespVO;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.ReturnOrderSaveReqVO;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderDO;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
public interface ReturnOrderService {
|
||||
|
||||
Long createReturnOrder(@Valid ReturnOrderSaveReqVO createReqVO);
|
||||
|
||||
void updateReturnOrder(@Valid ReturnOrderSaveReqVO updateReqVO);
|
||||
|
||||
void deleteReturnOrder(Long id);
|
||||
|
||||
ReturnOrderDO getReturnOrder(Long id);
|
||||
|
||||
ReturnOrderRespVO getReturnOrderDetail(Long id);
|
||||
|
||||
PageResult<ReturnOrderDO> getReturnOrderPage(ReturnOrderPageReqVO pageReqVO);
|
||||
|
||||
void completeInspection(Long id);
|
||||
|
||||
void settleReturnOrder(Long id);
|
||||
|
||||
/**
|
||||
* 从交车单创建还车单
|
||||
*/
|
||||
Long createFromDelivery(Long deliveryOrderId, List<Long> vehicleIds);
|
||||
|
||||
/**
|
||||
* 从替换车创建还车单(永久替换审批通过时)
|
||||
*/
|
||||
Long createFromReplacement(Long replacementId, Long contractId, Long vehicleId);
|
||||
|
||||
/**
|
||||
* 开始单车验车(创建或克隆验车记录)
|
||||
*/
|
||||
Long startVehicleInspection(Long returnOrderVehicleId);
|
||||
|
||||
/**
|
||||
* 完成单车验车
|
||||
*/
|
||||
void completeVehicleInspection(Long returnOrderVehicleId);
|
||||
|
||||
/**
|
||||
* 提交审批
|
||||
*/
|
||||
void submitApproval(Long id);
|
||||
|
||||
/**
|
||||
* 撤回审批
|
||||
*/
|
||||
void withdrawApproval(Long id);
|
||||
|
||||
/**
|
||||
* 更新审批状态(BPM 回调)
|
||||
*/
|
||||
void updateApprovalStatus(Long id, Integer bpmStatus);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
package cn.iocoder.yudao.module.asset.service.returnorder;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.*;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractDO;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryOrderDO;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryOrderVehicleDO;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordDO;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateDO;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderDO;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderVehicleDO;
|
||||
import cn.iocoder.yudao.module.asset.dal.mysql.contract.ContractMapper;
|
||||
import cn.iocoder.yudao.module.asset.dal.mysql.delivery.DeliveryOrderMapper;
|
||||
import cn.iocoder.yudao.module.asset.dal.mysql.inspection.InspectionRecordMapper;
|
||||
import cn.iocoder.yudao.module.asset.dal.mysql.delivery.DeliveryOrderVehicleMapper;
|
||||
import cn.iocoder.yudao.module.asset.dal.mysql.returnorder.ReturnOrderMapper;
|
||||
import cn.iocoder.yudao.module.asset.dal.mysql.returnorder.ReturnOrderVehicleMapper;
|
||||
import cn.iocoder.yudao.module.asset.enums.inspection.InspectionSourceTypeEnum;
|
||||
import cn.iocoder.yudao.module.asset.service.inspection.InspectionRecordService;
|
||||
import cn.iocoder.yudao.module.asset.service.inspection.InspectionTemplateService;
|
||||
import cn.iocoder.yudao.module.asset.service.returnorder.event.ReturnApprovedEvent;
|
||||
import cn.iocoder.yudao.module.asset.service.returnorder.listener.ReturnOrderBpmListener;
|
||||
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
|
||||
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
|
||||
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class ReturnOrderServiceImpl implements ReturnOrderService {
|
||||
|
||||
@Resource
|
||||
private ReturnOrderMapper returnOrderMapper;
|
||||
|
||||
@Resource
|
||||
private ReturnOrderVehicleMapper returnOrderVehicleMapper;
|
||||
|
||||
@Resource
|
||||
private DeliveryOrderMapper deliveryOrderMapper;
|
||||
|
||||
@Resource
|
||||
private DeliveryOrderVehicleMapper deliveryOrderVehicleMapper;
|
||||
|
||||
@Resource
|
||||
private ContractMapper contractMapper;
|
||||
|
||||
@Resource
|
||||
private InspectionRecordMapper inspectionRecordMapper;
|
||||
|
||||
@Resource
|
||||
private InspectionRecordService inspectionRecordService;
|
||||
|
||||
@Resource
|
||||
private InspectionTemplateService inspectionTemplateService;
|
||||
|
||||
@Resource
|
||||
private BpmProcessInstanceApi bpmProcessInstanceApi;
|
||||
|
||||
@Resource
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createReturnOrder(ReturnOrderSaveReqVO createReqVO) {
|
||||
// Generate order code: HC + timestamp
|
||||
String orderCode = "HC" + System.currentTimeMillis();
|
||||
|
||||
ReturnOrderDO order = BeanUtils.toBean(createReqVO, ReturnOrderDO.class);
|
||||
order.setOrderCode(orderCode);
|
||||
order.setSourceType(1); // 手动创建
|
||||
order.setStatus(0); // pending inspection
|
||||
order.setApprovalStatus(0); // draft
|
||||
returnOrderMapper.insert(order);
|
||||
|
||||
// Insert vehicles
|
||||
if (createReqVO.getVehicles() != null) {
|
||||
for (ReturnOrderVehicleVO vehicleVO : createReqVO.getVehicles()) {
|
||||
ReturnOrderVehicleDO vehicle = BeanUtils.toBean(vehicleVO, ReturnOrderVehicleDO.class);
|
||||
vehicle.setReturnOrderId(order.getId());
|
||||
returnOrderVehicleMapper.insert(vehicle);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate total refund
|
||||
calculateTotalRefund(order.getId());
|
||||
|
||||
return order.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateReturnOrder(ReturnOrderSaveReqVO updateReqVO) {
|
||||
ReturnOrderDO order = validateReturnOrderExists(updateReqVO.getId());
|
||||
if (order.getStatus().equals(2)) {
|
||||
throw exception(RETURN_ORDER_ALREADY_SETTLED);
|
||||
}
|
||||
|
||||
ReturnOrderDO updateObj = BeanUtils.toBean(updateReqVO, ReturnOrderDO.class);
|
||||
returnOrderMapper.updateById(updateObj);
|
||||
|
||||
// Update vehicles
|
||||
if (updateReqVO.getVehicles() != null) {
|
||||
returnOrderVehicleMapper.deleteByReturnOrderId(updateReqVO.getId());
|
||||
for (ReturnOrderVehicleVO vehicleVO : updateReqVO.getVehicles()) {
|
||||
ReturnOrderVehicleDO vehicle = BeanUtils.toBean(vehicleVO, ReturnOrderVehicleDO.class);
|
||||
vehicle.setReturnOrderId(updateReqVO.getId());
|
||||
returnOrderVehicleMapper.insert(vehicle);
|
||||
}
|
||||
}
|
||||
|
||||
calculateTotalRefund(updateReqVO.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteReturnOrder(Long id) {
|
||||
validateReturnOrderExists(id);
|
||||
returnOrderMapper.deleteById(id);
|
||||
returnOrderVehicleMapper.deleteByReturnOrderId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnOrderDO getReturnOrder(Long id) {
|
||||
return returnOrderMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnOrderRespVO getReturnOrderDetail(Long id) {
|
||||
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||
ReturnOrderRespVO respVO = BeanUtils.toBean(order, ReturnOrderRespVO.class);
|
||||
List<ReturnOrderVehicleDO> vehicles = returnOrderVehicleMapper.selectListByReturnOrderId(id);
|
||||
respVO.setVehicles(BeanUtils.toBean(vehicles, ReturnOrderVehicleVO.class));
|
||||
return respVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<ReturnOrderDO> getReturnOrderPage(ReturnOrderPageReqVO pageReqVO) {
|
||||
return returnOrderMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeInspection(Long id) {
|
||||
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||
if (order.getStatus().equals(2)) {
|
||||
throw exception(RETURN_ORDER_ALREADY_SETTLED);
|
||||
}
|
||||
returnOrderMapper.updateById(ReturnOrderDO.builder().id(id).status(1).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settleReturnOrder(Long id) {
|
||||
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||
if (order.getStatus().equals(2)) {
|
||||
throw exception(RETURN_ORDER_ALREADY_SETTLED);
|
||||
}
|
||||
returnOrderMapper.updateById(ReturnOrderDO.builder().id(id).status(2).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createFromDelivery(Long deliveryOrderId, List<Long> vehicleIds) {
|
||||
// 查询交车单信息
|
||||
DeliveryOrderDO deliveryOrder = deliveryOrderMapper.selectById(deliveryOrderId);
|
||||
if (deliveryOrder == null) {
|
||||
throw exception(DELIVERY_ORDER_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 创建还车单
|
||||
ReturnOrderDO order = new ReturnOrderDO();
|
||||
order.setOrderCode("HC" + System.currentTimeMillis());
|
||||
order.setSourceType(1); // 手动(从交车单创建)
|
||||
order.setDeliveryOrderId(deliveryOrderId);
|
||||
order.setContractId(deliveryOrder.getContractId());
|
||||
order.setContractCode(deliveryOrder.getContractCode());
|
||||
order.setProjectName(deliveryOrder.getProjectName());
|
||||
order.setCustomerId(deliveryOrder.getCustomerId());
|
||||
order.setCustomerName(deliveryOrder.getCustomerName());
|
||||
order.setStatus(0); // 待验车
|
||||
order.setApprovalStatus(0); // 草稿
|
||||
returnOrderMapper.insert(order);
|
||||
|
||||
// 查询交车单车辆,筛选指定的 vehicleIds
|
||||
List<DeliveryOrderVehicleDO> deliveryVehicles = deliveryOrderVehicleMapper.selectListByOrderId(deliveryOrderId);
|
||||
for (DeliveryOrderVehicleDO dv : deliveryVehicles) {
|
||||
if (vehicleIds.contains(dv.getVehicleId())) {
|
||||
ReturnOrderVehicleDO vehicle = new ReturnOrderVehicleDO();
|
||||
vehicle.setReturnOrderId(order.getId());
|
||||
vehicle.setVehicleId(dv.getVehicleId());
|
||||
vehicle.setPlateNo(dv.getPlateNo());
|
||||
vehicle.setVin(dv.getVin());
|
||||
vehicle.setBrand(dv.getBrand());
|
||||
vehicle.setModel(dv.getModel());
|
||||
returnOrderVehicleMapper.insert(vehicle);
|
||||
}
|
||||
}
|
||||
|
||||
return order.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createFromReplacement(Long replacementId, Long contractId, Long vehicleId) {
|
||||
// 查询合同信息
|
||||
ContractDO contract = contractMapper.selectById(contractId);
|
||||
if (contract == null) {
|
||||
throw exception(CONTRACT_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 创建还车单
|
||||
ReturnOrderDO order = new ReturnOrderDO();
|
||||
order.setOrderCode("HC" + System.currentTimeMillis());
|
||||
order.setSourceType(2); // 替换车触发
|
||||
order.setSourceId(replacementId);
|
||||
order.setContractId(contractId);
|
||||
order.setContractCode(contract.getContractCode());
|
||||
order.setProjectName(contract.getProjectName());
|
||||
order.setCustomerId(contract.getCustomerId());
|
||||
order.setCustomerName(contract.getCustomerName());
|
||||
order.setStatus(0); // 待验车
|
||||
order.setApprovalStatus(0); // 草稿
|
||||
returnOrderMapper.insert(order);
|
||||
|
||||
// 创建还车车辆(原车辆)
|
||||
// TODO: 查询车辆信息获取 plateNo/vin/brand/model,暂时只设置 vehicleId
|
||||
ReturnOrderVehicleDO vehicle = new ReturnOrderVehicleDO();
|
||||
vehicle.setReturnOrderId(order.getId());
|
||||
vehicle.setVehicleId(vehicleId);
|
||||
returnOrderVehicleMapper.insert(vehicle);
|
||||
|
||||
return order.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long startVehicleInspection(Long returnOrderVehicleId) {
|
||||
// 查找还车车辆
|
||||
ReturnOrderVehicleDO vehicle = returnOrderVehicleMapper.selectById(returnOrderVehicleId);
|
||||
if (vehicle == null) {
|
||||
throw exception(RETURN_ORDER_VEHICLE_NOT_EXISTS);
|
||||
}
|
||||
if (vehicle.getInspectionRecordId() != null) {
|
||||
throw exception(RETURN_ORDER_INSPECTION_ALREADY_STARTED);
|
||||
}
|
||||
|
||||
Long inspectionRecordId;
|
||||
|
||||
// 尝试查找最新的交车验车记录进行克隆
|
||||
InspectionRecordDO latestRecord = inspectionRecordService.getLatestRecord(
|
||||
vehicle.getVehicleId(), InspectionSourceTypeEnum.DELIVERY.getType());
|
||||
|
||||
if (latestRecord != null) {
|
||||
// 克隆交车验车记录
|
||||
inspectionRecordId = inspectionRecordService.cloneRecord(
|
||||
latestRecord.getId(),
|
||||
InspectionSourceTypeEnum.RETURN.getType(),
|
||||
returnOrderVehicleId);
|
||||
} else {
|
||||
// 没有交车记录,尝试匹配模板创建新记录
|
||||
InspectionTemplateDO template = inspectionTemplateService.matchTemplate(
|
||||
InspectionSourceTypeEnum.RETURN.getType(), null);
|
||||
if (template == null) {
|
||||
throw exception(INSPECTION_TEMPLATE_MATCH_FAILED);
|
||||
}
|
||||
inspectionRecordId = inspectionRecordService.createRecord(
|
||||
template.getId(),
|
||||
InspectionSourceTypeEnum.RETURN.getType(),
|
||||
returnOrderVehicleId,
|
||||
vehicle.getVehicleId());
|
||||
}
|
||||
|
||||
// 更新还车车辆的验车记录ID
|
||||
ReturnOrderVehicleDO updateObj = new ReturnOrderVehicleDO();
|
||||
updateObj.setId(returnOrderVehicleId);
|
||||
updateObj.setInspectionRecordId(inspectionRecordId);
|
||||
returnOrderVehicleMapper.updateById(updateObj);
|
||||
|
||||
return inspectionRecordId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void completeVehicleInspection(Long returnOrderVehicleId) {
|
||||
// 查找还车车辆
|
||||
ReturnOrderVehicleDO vehicle = returnOrderVehicleMapper.selectById(returnOrderVehicleId);
|
||||
if (vehicle == null) {
|
||||
throw exception(RETURN_ORDER_VEHICLE_NOT_EXISTS);
|
||||
}
|
||||
if (vehicle.getInspectionRecordId() == null) {
|
||||
throw exception(RETURN_ORDER_INSPECTION_NOT_STARTED);
|
||||
}
|
||||
|
||||
// 完成验车记录
|
||||
Long userId = SecurityFrameworkUtils.getLoginUserId();
|
||||
String inspectorName = userId != null ? String.valueOf(userId) : "system";
|
||||
inspectionRecordService.completeRecord(vehicle.getInspectionRecordId(), inspectorName);
|
||||
|
||||
// 检查该还车单的所有车辆是否都完成了验车
|
||||
List<ReturnOrderVehicleDO> allVehicles = returnOrderVehicleMapper.selectListByReturnOrderId(vehicle.getReturnOrderId());
|
||||
boolean allCompleted = allVehicles.stream().allMatch(v -> {
|
||||
if (v.getInspectionRecordId() == null) {
|
||||
return false;
|
||||
}
|
||||
// 当前正在完成的车辆视为已完成
|
||||
if (v.getId().equals(returnOrderVehicleId)) {
|
||||
return true;
|
||||
}
|
||||
// 检查验车记录状态(2=已完成)
|
||||
InspectionRecordDO record = inspectionRecordMapper.selectById(v.getInspectionRecordId());
|
||||
return record != null && Integer.valueOf(2).equals(record.getStatus());
|
||||
});
|
||||
|
||||
if (allCompleted) {
|
||||
// 所有车辆验车完成,更新还车单状态
|
||||
returnOrderMapper.updateById(ReturnOrderDO.builder()
|
||||
.id(vehicle.getReturnOrderId())
|
||||
.status(1) // 验车完成
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void submitApproval(Long id) {
|
||||
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||
|
||||
// 校验状态:验车完成才能提交审批
|
||||
if (!Integer.valueOf(1).equals(order.getStatus())) {
|
||||
throw exception(RETURN_ORDER_STATUS_NOT_ALLOW_SUBMIT);
|
||||
}
|
||||
// 校验审批状态:草稿、已驳回、已撤回才能提交
|
||||
if (order.getApprovalStatus() != null && order.getApprovalStatus() == 1) {
|
||||
throw exception(RETURN_ORDER_STATUS_NOT_ALLOW_SUBMIT);
|
||||
}
|
||||
|
||||
// 创建流程变量
|
||||
Map<String, Object> variables = new HashMap<>();
|
||||
variables.put("orderCode", order.getOrderCode());
|
||||
variables.put("contractCode", order.getContractCode());
|
||||
variables.put("customerName", order.getCustomerName());
|
||||
|
||||
// 创建流程实例
|
||||
BpmProcessInstanceCreateReqDTO reqDTO = new BpmProcessInstanceCreateReqDTO();
|
||||
reqDTO.setProcessDefinitionKey(ReturnOrderBpmListener.PROCESS_KEY);
|
||||
reqDTO.setBusinessKey(String.valueOf(id));
|
||||
reqDTO.setVariables(variables);
|
||||
|
||||
Long userId = SecurityFrameworkUtils.getLoginUserId();
|
||||
String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, reqDTO).getData();
|
||||
|
||||
// 更新审批状态
|
||||
ReturnOrderDO updateObj = new ReturnOrderDO();
|
||||
updateObj.setId(id);
|
||||
updateObj.setApprovalStatus(1); // 审批中
|
||||
updateObj.setBpmInstanceId(processInstanceId);
|
||||
returnOrderMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void withdrawApproval(Long id) {
|
||||
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||
|
||||
// 校验审批状态:只有审批中才能撤回
|
||||
if (!Integer.valueOf(1).equals(order.getApprovalStatus())) {
|
||||
throw exception(RETURN_ORDER_STATUS_NOT_ALLOW_WITHDRAW);
|
||||
}
|
||||
|
||||
// 更新审批状态
|
||||
ReturnOrderDO updateObj = new ReturnOrderDO();
|
||||
updateObj.setId(id);
|
||||
updateObj.setApprovalStatus(4); // 已撤回
|
||||
returnOrderMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateApprovalStatus(Long id, Integer bpmStatus) {
|
||||
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||
|
||||
ReturnOrderDO updateObj = new ReturnOrderDO();
|
||||
updateObj.setId(id);
|
||||
|
||||
if (BpmProcessInstanceStatusEnum.APPROVE.getStatus().equals(bpmStatus)) {
|
||||
updateObj.setApprovalStatus(2); // 审批通过
|
||||
returnOrderMapper.updateById(updateObj);
|
||||
|
||||
// 发布审批通过事件
|
||||
List<ReturnOrderVehicleDO> vehicles = returnOrderVehicleMapper.selectListByReturnOrderId(id);
|
||||
List<Long> vehicleIds = vehicles.stream()
|
||||
.map(ReturnOrderVehicleDO::getVehicleId)
|
||||
.collect(Collectors.toList());
|
||||
eventPublisher.publishEvent(new ReturnApprovedEvent(id, vehicleIds));
|
||||
} else if (BpmProcessInstanceStatusEnum.REJECT.getStatus().equals(bpmStatus)) {
|
||||
updateObj.setApprovalStatus(3); // 审批拒绝
|
||||
returnOrderMapper.updateById(updateObj);
|
||||
} else if (BpmProcessInstanceStatusEnum.CANCEL.getStatus().equals(bpmStatus)) {
|
||||
updateObj.setApprovalStatus(4); // 已撤回
|
||||
returnOrderMapper.updateById(updateObj);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 私有方法 ====================
|
||||
|
||||
private ReturnOrderDO validateReturnOrderExists(Long id) {
|
||||
ReturnOrderDO order = returnOrderMapper.selectById(id);
|
||||
if (order == null) {
|
||||
throw exception(RETURN_ORDER_NOT_EXISTS);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
private void calculateTotalRefund(Long orderId) {
|
||||
ReturnOrderDO order = returnOrderMapper.selectById(orderId);
|
||||
if (order == null) return;
|
||||
|
||||
List<ReturnOrderVehicleDO> vehicles = returnOrderVehicleMapper.selectListByReturnOrderId(orderId);
|
||||
BigDecimal totalHydrogenRefund = vehicles.stream()
|
||||
.map(v -> v.getHydrogenRefundAmount() != null ? v.getHydrogenRefundAmount() : BigDecimal.ZERO)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
BigDecimal depositRefund = order.getDepositRefund() != null ? order.getDepositRefund() : BigDecimal.ZERO;
|
||||
BigDecimal otherCharges = order.getOtherCharges() != null ? order.getOtherCharges() : BigDecimal.ZERO;
|
||||
BigDecimal totalRefund = depositRefund.add(totalHydrogenRefund).subtract(otherCharges);
|
||||
|
||||
returnOrderMapper.updateById(ReturnOrderDO.builder()
|
||||
.id(orderId)
|
||||
.hydrogenRefund(totalHydrogenRefund)
|
||||
.totalRefundAmount(totalRefund)
|
||||
.build());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.iocoder.yudao.module.asset.service.returnorder.event;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 还车单审批通过事件
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class ReturnApprovedEvent {
|
||||
|
||||
/**
|
||||
* 还车单ID
|
||||
*/
|
||||
private final Long returnOrderId;
|
||||
|
||||
/**
|
||||
* 还车单中的所有车辆ID
|
||||
*/
|
||||
private final List<Long> vehicleIds;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package cn.iocoder.yudao.module.asset.service.returnorder.listener;
|
||||
|
||||
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
|
||||
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
|
||||
import cn.iocoder.yudao.module.asset.service.returnorder.ReturnOrderService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 还车单审批状态监听器
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
public class ReturnOrderBpmListener extends BpmProcessInstanceStatusEventListener {
|
||||
|
||||
/**
|
||||
* 流程定义 Key
|
||||
*/
|
||||
public static final String PROCESS_KEY = "asset_return_order";
|
||||
|
||||
@Resource
|
||||
private ReturnOrderService returnOrderService;
|
||||
|
||||
@Override
|
||||
protected String getProcessDefinitionKey() {
|
||||
return PROCESS_KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvent(BpmProcessInstanceStatusEvent event) {
|
||||
returnOrderService.updateApprovalStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:flowable="http://flowable.org/bpmn"
|
||||
typeLanguage="http://www.w3.org/2001/XMLSchema"
|
||||
expressionLanguage="http://www.w3.org/1999/XPath"
|
||||
targetNamespace="http://www.flowable.org/processdef">
|
||||
|
||||
<process id="asset_return_order" name="还车单审批" isExecutable="true">
|
||||
|
||||
<startEvent id="startEvent" name="开始"/>
|
||||
|
||||
<sequenceFlow sourceRef="startEvent" targetRef="deptManagerApproval"/>
|
||||
|
||||
<!-- 部门主管审批 -->
|
||||
<userTask id="deptManagerApproval" name="部门主管审批" flowable:candidateGroups="dept_manager">
|
||||
<extensionElements>
|
||||
<flowable:formProperty id="approved" name="是否同意" type="boolean" required="true"/>
|
||||
<flowable:formProperty id="comment" name="审批意见" type="string"/>
|
||||
</extensionElements>
|
||||
</userTask>
|
||||
|
||||
<sequenceFlow sourceRef="deptManagerApproval" targetRef="gateway1"/>
|
||||
|
||||
<!-- 网关:判断部门主管是否同意 -->
|
||||
<exclusiveGateway id="gateway1"/>
|
||||
|
||||
<sequenceFlow sourceRef="gateway1" targetRef="endEventApprove">
|
||||
<conditionExpression xsi:type="tFormalExpression">${approved == true}</conditionExpression>
|
||||
</sequenceFlow>
|
||||
|
||||
<sequenceFlow sourceRef="gateway1" targetRef="endEventReject">
|
||||
<conditionExpression xsi:type="tFormalExpression">${approved == false}</conditionExpression>
|
||||
</sequenceFlow>
|
||||
|
||||
<!-- 审批通过结束 -->
|
||||
<endEvent id="endEventApprove" name="审批通过"/>
|
||||
|
||||
<!-- 审批拒绝结束 -->
|
||||
<endEvent id="endEventReject" name="审批拒绝"/>
|
||||
|
||||
</process>
|
||||
|
||||
</definitions>
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:flowable="http://flowable.org/bpmn"
|
||||
typeLanguage="http://www.w3.org/2001/XMLSchema"
|
||||
expressionLanguage="http://www.w3.org/1999/XPath"
|
||||
targetNamespace="http://www.flowable.org/processdef">
|
||||
|
||||
<process id="asset_vehicle_replacement" name="替换车审批" isExecutable="true">
|
||||
|
||||
<startEvent id="startEvent" name="开始"/>
|
||||
|
||||
<sequenceFlow sourceRef="startEvent" targetRef="deptManagerApproval"/>
|
||||
|
||||
<!-- 部门主管审批 -->
|
||||
<userTask id="deptManagerApproval" name="部门主管审批" flowable:candidateGroups="dept_manager">
|
||||
<extensionElements>
|
||||
<flowable:formProperty id="approved" name="是否同意" type="boolean" required="true"/>
|
||||
<flowable:formProperty id="comment" name="审批意见" type="string"/>
|
||||
</extensionElements>
|
||||
</userTask>
|
||||
|
||||
<sequenceFlow sourceRef="deptManagerApproval" targetRef="gateway1"/>
|
||||
|
||||
<!-- 网关:判断部门主管是否同意 -->
|
||||
<exclusiveGateway id="gateway1"/>
|
||||
|
||||
<!-- 同意且为永久替换 → 总经理审批 -->
|
||||
<sequenceFlow sourceRef="gateway1" targetRef="gmApproval">
|
||||
<conditionExpression xsi:type="tFormalExpression">${approved == true && replacementType == 2}</conditionExpression>
|
||||
</sequenceFlow>
|
||||
|
||||
<!-- 同意且为临时替换 → 直接通过 -->
|
||||
<sequenceFlow sourceRef="gateway1" targetRef="endEventApprove">
|
||||
<conditionExpression xsi:type="tFormalExpression">${approved == true && replacementType == 1}</conditionExpression>
|
||||
</sequenceFlow>
|
||||
|
||||
<!-- 不同意 → 拒绝 -->
|
||||
<sequenceFlow sourceRef="gateway1" targetRef="endEventReject">
|
||||
<conditionExpression xsi:type="tFormalExpression">${approved == false}</conditionExpression>
|
||||
</sequenceFlow>
|
||||
|
||||
<!-- 总经理审批 -->
|
||||
<userTask id="gmApproval" name="总经理审批" flowable:candidateGroups="general_manager">
|
||||
<extensionElements>
|
||||
<flowable:formProperty id="approved" name="是否同意" type="boolean" required="true"/>
|
||||
<flowable:formProperty id="comment" name="审批意见" type="string"/>
|
||||
</extensionElements>
|
||||
</userTask>
|
||||
|
||||
<sequenceFlow sourceRef="gmApproval" targetRef="gateway2"/>
|
||||
|
||||
<!-- 网关:判断总经理是否同意 -->
|
||||
<exclusiveGateway id="gateway2"/>
|
||||
|
||||
<sequenceFlow sourceRef="gateway2" targetRef="endEventApprove">
|
||||
<conditionExpression xsi:type="tFormalExpression">${approved == true}</conditionExpression>
|
||||
</sequenceFlow>
|
||||
|
||||
<sequenceFlow sourceRef="gateway2" targetRef="endEventReject">
|
||||
<conditionExpression xsi:type="tFormalExpression">${approved == false}</conditionExpression>
|
||||
</sequenceFlow>
|
||||
|
||||
<!-- 审批通过结束 -->
|
||||
<endEvent id="endEventApprove" name="审批通过"/>
|
||||
|
||||
<!-- 审批拒绝结束 -->
|
||||
<endEvent id="endEventReject" name="审批拒绝"/>
|
||||
|
||||
</process>
|
||||
|
||||
</definitions>
|
||||
Reference in New Issue
Block a user