@@ -290,6 +309,17 @@ export default {
}
},
dicts:['delivery_order_type'],
+ computed: {
+ // 关联项目回显文本:关联订单编码 / 关联项目名称
+ relatedOrderText() {
+ const code = this.localOrderData.relatedOrderCode;
+ const name = this.localOrderData.relatedProjectName;
+ if (!code && !name) {
+ return '';
+ }
+ return [code, name].filter(item => !!item).join(' / ');
+ }
+ },
data() {
return {
localOrderData: {},
@@ -331,6 +361,25 @@ export default {
},
methods: {
getDicts,
+ // 切换订单类型:非仅维保时清空关联项目
+ handleOrderTypeChange(value) {
+ if (value !== '2') {
+ this.clearRelatedOrder();
+ }
+ },
+ // 打开关联项目选择弹窗,只读态不响应
+ openRelatedOrderDialog() {
+ if (this.isReadonly) {
+ return;
+ }
+ this.$emit('select-related-order');
+ },
+ // 清空关联项目:关联订单id/编码/项目名称一并清除,产品配置保持不动
+ clearRelatedOrder() {
+ this.$set(this.localOrderData, 'relatedOrderId', null);
+ this.$set(this.localOrderData, 'relatedOrderCode', null);
+ this.$set(this.localOrderData, 'relatedProjectName', null);
+ },
handleBgChange(value, isInitialLoad = false) {
if (!isInitialLoad) {
this.localOrderData.industryType = null;
diff --git a/oms_web/oms_vue/src/views/project/order/components/OrderInfoDisplay.vue b/oms_web/oms_vue/src/views/project/order/components/OrderInfoDisplay.vue
index 961d7193..5968b541 100644
--- a/oms_web/oms_vue/src/views/project/order/components/OrderInfoDisplay.vue
+++ b/oms_web/oms_vue/src/views/project/order/components/OrderInfoDisplay.vue
@@ -106,6 +106,10 @@
| 付款比例 |
{{ displayValue(localOrderData.paymentRatio, true) }} |
+
+ | 关联项目 |
+ {{ displayValue(relatedText) }} |
+
| 付款条件 |
{{ displayValue(localOrderData.paymentDescription) }} |
@@ -180,6 +184,16 @@ export default {
paymentMethodOptions: [],
};
},
+ computed: {
+ // 仅维保订单展示的关联项目:订单编号 / 项目名称
+ relatedText() {
+ if (!this.localOrderData.relatedOrderCode) { return ''; }
+ if (this.localOrderData.relatedProjectName) {
+ return this.localOrderData.relatedOrderCode + ' / ' + this.localOrderData.relatedProjectName;
+ }
+ return this.localOrderData.relatedOrderCode;
+ },
+ },
watch: {
orderData: {
handler(newValue) {
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueDeliveryController.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueDeliveryController.java
index 0da88326..e0d99696 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueDeliveryController.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueDeliveryController.java
@@ -75,6 +75,15 @@ public class VueDeliveryController extends BaseController {
return AjaxResult.success(inventoryDelivery);
}
+ /**
+ * 查询仅维保订单发货可续用的SN(关联项目下同产品编码的已发货SN)
+ */
+ @RequiresPermissions("inventory:delivery:add")
+ @GetMapping("/maintenanceSn")
+ public AjaxResult maintenanceSn(@RequestParam String orderCode, @RequestParam String productCode) {
+ return AjaxResult.success(inventoryDeliveryService.getMaintenanceSnList(orderCode, productCode));
+ }
+
/**
* 新增发货记录
*/
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueProjectOrderInfoController.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueProjectOrderInfoController.java
index 39283441..8aa5ead3 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueProjectOrderInfoController.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueProjectOrderInfoController.java
@@ -169,6 +169,19 @@ public class VueProjectOrderInfoController extends BaseController {
return AjaxResult.success(fileName);
}
+ /**
+ * 仅维保订单「关联项目」候选订单:只返回已审批完成的正常订单,可排除自身
+ */
+ @RequiresPermissions("project:order:list")
+ @GetMapping("/relatedCandidateList")
+ public TableDataInfo relatedCandidateList(@RequestParam(required = false) String projectCode,
+ @RequestParam(required = false) String projectName,
+ @RequestParam(required = false) Long excludeOrderId) {
+ startPage();
+ List list = projectOrderInfoService.selectRelatedCandidateList(projectCode, projectName, excludeOrderId);
+ return getDataTable(list);
+ }
+
/**
* 配备货产品信息
*/
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectOrderInfo.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectOrderInfo.java
index e2b18254..a9e52bc1 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectOrderInfo.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectOrderInfo.java
@@ -73,6 +73,21 @@ public class ProjectOrderInfo extends BaseEntity {
private String customerUserName;
private String orderType;
+ /**
+ * 关联项目订单id:仅维保订单(orderType=2)必填,指向被关联的正常订单
+ */
+ private Long relatedOrderId;
+
+ /**
+ * 关联项目订单编码(只读,联表带出)
+ */
+ private String relatedOrderCode;
+
+ /**
+ * 关联项目名称(只读,联表带出)
+ */
+ private String relatedProjectName;
+
/**
* 出货金额
*/
@@ -317,6 +332,25 @@ public class ProjectOrderInfo extends BaseEntity {
*/
private Integer operationVersion;
+ /**
+ * 订单类型 1:正常订单 2:仅维保
+ */
+ @Getter
+ public enum OrderTypeEnum {
+ NORMAL("1", "正常订单"),
+ MAINTENANCE("2", "仅维保"),
+
+ ;
+
+ private final String value;
+ private final String code;
+
+ OrderTypeEnum(String code, String value) {
+ this.code = code;
+ this.value = value;
+ }
+
+ }
@Getter
public enum OrderStatus {
WAIT_COMMIT("0", "待提交"),
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/InventoryDeliveryMapper.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/InventoryDeliveryMapper.java
index a3563f5b..12309f25 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/InventoryDeliveryMapper.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/InventoryDeliveryMapper.java
@@ -7,6 +7,7 @@ import com.ruoyi.sip.domain.InventoryDelivery;
import com.ruoyi.sip.dto.ApiDataQueryDto;
import com.ruoyi.sip.vo.DeliveryApproveVo;
import com.ruoyi.sip.vo.DeliveryInfoVo;
+import com.ruoyi.sip.vo.MaintenanceSnVo;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@@ -71,6 +72,15 @@ public interface InventoryDeliveryMapper
List listSn(ApiDataQueryDto dto);
+ /**
+ * 查询指定订单指定产品编码下已发货的SN(仅维保订单续用)
+ *
+ * @param orderCode 关联订单编码
+ * @param productCode 产品编码
+ * @return 已发货SN列表
+ */
+ List listMaintenanceSn(@Param("orderCode") String orderCode, @Param("productCode") String productCode);
+
List selectDeliveryApproveList(@Param("id") Long id);
/**
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/ProjectOrderInfoMapper.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/ProjectOrderInfoMapper.java
index 020e1bdb..2f652b97 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/ProjectOrderInfoMapper.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/ProjectOrderInfoMapper.java
@@ -2,6 +2,7 @@ package com.ruoyi.sip.mapper;
import java.math.BigDecimal;
import java.util.List;
+import java.util.Map;
import com.ruoyi.sip.domain.InventoryDelivery;
import com.ruoyi.sip.domain.ProjectOrderInfo;
@@ -38,6 +39,14 @@ public interface ProjectOrderInfoMapper
* @return 订单管理集合
*/
public List selectProjectOrderInfoList(ProjectOrderInfo projectOrderInfo);
+
+ /**
+ * 仅维保订单「关联项目」候选订单:已审批完成的正常订单
+ *
+ * @param params projectCode 项目编码 / projectName 项目名称 / excludeOrderId 需排除的订单id
+ * @return 候选订单集合
+ */
+ public List selectRelatedCandidateList(Map params);
public ProjectOrderInfo selectProjectOrderInfoByCode(String orderCode);
/**
@@ -64,6 +73,14 @@ public interface ProjectOrderInfoMapper
*/
public int clearRebackApproveStatus(Long id);
+ /**
+ * 清空订单的关联项目(仅维保订单改回正常订单时使用)
+ *
+ * @param id 订单管理主键
+ * @return 结果
+ */
+ public int clearRelatedOrderId(Long id);
+
/**
* 删除订单管理
*
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IInventoryDeliveryService.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IInventoryDeliveryService.java
index 5ba630ce..426bb8d6 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IInventoryDeliveryService.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IInventoryDeliveryService.java
@@ -6,6 +6,7 @@ import com.ruoyi.sip.domain.InventoryDelivery;
import com.ruoyi.sip.dto.ApiDataQueryDto;
import com.ruoyi.sip.dto.inventory.InventoryDeliveryDetailExcelDto;
import com.ruoyi.sip.vo.DeliveryInfoVo;
+import com.ruoyi.sip.vo.MaintenanceDeliveryVo;
/**
* 产品库存Service接口
@@ -110,4 +111,13 @@ public interface IInventoryDeliveryService
void generateServiceBillsWhenAllDelivered(String orderCode);
+ /**
+ * 查询仅维保订单发货可续用的SN(关联项目下同产品编码的已发货SN)
+ *
+ * @param orderCode 仅维保订单编码
+ * @param productCode 产品编码
+ * @return 关联项目信息与可续用的SN列表
+ */
+ MaintenanceDeliveryVo getMaintenanceSnList(String orderCode, String productCode);
+
}
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java
index 833abddc..1435c494 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java
@@ -54,6 +54,16 @@ public interface IProjectOrderInfoService
* @return 结果
*/
public int updateProjectOrderInfo(ProjectOrderInfo projectOrderInfo);
+
+ /**
+ * 仅维保订单「关联项目」候选订单列表(已审批完成的正常订单)
+ *
+ * @param projectCode 项目编码,模糊匹配,可为空
+ * @param projectName 项目名称,模糊匹配,可为空
+ * @param excludeOrderId 需要排除的订单id(编辑时排除自身),可为空
+ * @return 候选订单集合
+ */
+ List selectRelatedCandidateList(String projectCode, String projectName, Long excludeOrderId);
public int updateProjectOrderInfoByCode(ProjectOrderInfo projectOrderInfo);
/**
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/InventoryDeliveryServiceImpl.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/InventoryDeliveryServiceImpl.java
index 81468970..ac064321 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/InventoryDeliveryServiceImpl.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/InventoryDeliveryServiceImpl.java
@@ -27,6 +27,8 @@ import com.ruoyi.sip.mapper.OmsPurchaseOrderMapMapper;
import com.ruoyi.sip.service.*;
import com.ruoyi.sip.vo.DeliveryApproveVo;
import com.ruoyi.sip.vo.DeliveryInfoVo;
+import com.ruoyi.sip.vo.MaintenanceDeliveryVo;
+import com.ruoyi.sip.vo.MaintenanceSnVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.flowable.engine.RuntimeService;
@@ -145,6 +147,8 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService,
throw new ServiceException("发货清单为空,保存失败");
}
+ //仅维保订单:发货SN直接沿用关联项目已发货的SN,不校验采购绑定、不回写SN库存信息
+ boolean maintenanceOnly = false;
if (StringUtils.isNotEmpty(inventoryDelivery.getOrderCode())) {
ProjectOrderInfo orderInfo = projectOrderInfoService.selectProjectOrderInfoByOrderCode(inventoryDelivery.getOrderCode());
if (orderInfo == null) {
@@ -152,8 +156,11 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService,
}
//版本号取订单的version_code
inventoryDelivery.setVersionCode(orderInfo.getVersionCode());
+ maintenanceOnly = ProjectOrderInfo.OrderTypeEnum.MAINTENANCE.getCode().equals(orderInfo.getOrderType());
- if (StringUtils.isNotEmpty(inventoryDelivery.getPurchaseNo())) {
+ if (maintenanceOnly) {
+ validateMaintenanceDeliverySn(inventoryDelivery.getOrderCode(), inventoryDelivery.getProductCode(), productSnList);
+ } else if (StringUtils.isNotEmpty(inventoryDelivery.getPurchaseNo())) {
int newSnCount = CollUtil.isEmpty(productSnList) ? productSnDataList.size() : productSnList.size();
OmsPurchaseOrder purchaseOrder = omsPurchaseOrderService.selectOmsPurchaseOrderByNo(inventoryDelivery.getPurchaseNo());
if (purchaseOrder == null) {
@@ -276,7 +283,10 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService,
return info;
}).collect(Collectors.toList());
- inventoryInfoService.saveBatch(inventoryInfoList);
+ //仅维保发货只写发货单与发货明细,SN的库存状态、出库单号、订单归属保持关联项目原值
+ if (!maintenanceOnly) {
+ inventoryInfoService.saveBatch(inventoryInfoList);
+ }
} else {
Long warehouseId = productSnDataList.get(0).getWarehouseId();
if (warehouseId!=null && !warehouseId.equals(inventoryDelivery.getWarehouseId())){
@@ -615,9 +625,19 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService,
List productInfos = productInfoService.selectProductInfoList(productInfo);
productInfo.setType(ProductInfo.ProductTypeEnum.SERVICE.getType());
productInfos.addAll(productInfoService.selectProductInfoList(productInfo));
- // 设置服务等级和服务结束时间
- for (DeliveryInfoVo deliveryInfoVo : resultList) {
- updateDeliveryInfoVo(deliveryInfoVo, maintenanceTypeMap, productInfos);
+ // 设置服务等级和服务结束时间:同一SN+同一产品编码按订单排序(审批时间→创建时间→订单id升序),
+ // 后一单(仅维保)的维保起始日取前一单最后一段维保截止日,实现维保日期续算
+ Map> snGroupMap = resultList.stream().collect(Collectors.groupingBy(
+ item -> item.getSerialNumber() + "#" + item.getProductCode(), LinkedHashMap::new, Collectors.toList()));
+ for (List sameSnList : snGroupMap.values()) {
+ sameSnList.sort(maintenanceSnComparator());
+ Date carryStartTime = null;
+ for (DeliveryInfoVo deliveryInfoVo : sameSnList) {
+ Date lastServiceEndTime = updateDeliveryInfoVo(deliveryInfoVo, maintenanceTypeMap, productInfos, carryStartTime);
+ if (lastServiceEndTime != null) {
+ carryStartTime = lastServiceEndTime;
+ }
+ }
}
return resultList;
}
@@ -1473,10 +1493,16 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService,
/**
* 更新 DeliveryInfoVo 的服务等级和服务结束时间
*/
- private void updateDeliveryInfoVo(DeliveryInfoVo deliveryInfoVo, Map> maintenanceTypeMap, List productInfos) {
+ /**
+ * 计算发货明细的维保等级与维保起止时间
+ *
+ * @param carryStartTime 续算起始日(同一SN上一单最后一段维保截止日),为空时按发货日期起算
+ * @return 本单最后一段维保截止日,无维保段时返回 null,供下一单续算
+ */
+ private Date updateDeliveryInfoVo(DeliveryInfoVo deliveryInfoVo, Map> maintenanceTypeMap, List productInfos, Date carryStartTime) {
List productInfoList = maintenanceTypeMap.get(deliveryInfoVo.getProjectId());
List serviceInfoList = new ArrayList<>();
- Date startTime = deliveryInfoVo.getServiceStartTime();
+ Date startTime = carryStartTime != null ? carryStartTime : deliveryInfoVo.getServiceStartTime();
if (CollUtil.isNotEmpty(productInfoList) && ProductInfo.ProductTypeEnum.SOFTWARE.getType().equals(deliveryInfoVo.getProductType())) {
for (ProjectProductInfo productInfo : productInfoList) {
if (ProductInfo.ProductTypeLevel2ServiceEnum.SOFTWARE_QA.getType().equals(productInfo.getLevel2Type()) && StringUtils.isNotEmpty(productInfo.getValue())) {
@@ -1511,6 +1537,10 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService,
}
}
deliveryInfoVo.setServiceInfo(serviceInfoList);
+ if (CollUtil.isEmpty(serviceInfoList)) {
+ return null;
+ }
+ return serviceInfoList.get(serviceInfoList.size() - 1).getServiceEndTime();
}
private Date updateStartTimeAndAddList(DeliveryInfoVo deliveryInfoVo, ProjectProductInfo productInfo, Date startTime, List serviceInfoList) {
@@ -1525,4 +1555,57 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService,
serviceInfoList.add(serviceInfo);
return startTime;
}
+
+ /**
+ * 同一SN+产品编码的续算排序:审批时间(为空回退创建时间)升序,完全相同按订单id升序
+ */
+ private Comparator maintenanceSnComparator() {
+ Comparator dateComparator = Comparator.nullsLast(Comparator.naturalOrder());
+ return Comparator.comparing((DeliveryInfoVo vo) -> vo.getApproveTime() != null ? vo.getApproveTime() : vo.getCreateTime(), dateComparator)
+ .thenComparing(DeliveryInfoVo::getOrderId, Comparator.nullsLast(Comparator.naturalOrder()));
+ }
+
+ /**
+ * 查询仅维保订单发货可续用的SN(关联项目下同产品编码的已发货SN)
+ */
+ @Override
+ public MaintenanceDeliveryVo getMaintenanceSnList(String orderCode, String productCode) {
+ if (StringUtils.isEmpty(orderCode) || StringUtils.isEmpty(productCode)) {
+ throw new ServiceException("订单编码和产品编码不能为空");
+ }
+ ProjectOrderInfo orderInfo = projectOrderInfoService.selectProjectOrderInfoByOrderCode(orderCode);
+ if (orderInfo == null) {
+ throw new ServiceException("订单信息不存在");
+ }
+ if (!ProjectOrderInfo.OrderTypeEnum.MAINTENANCE.getCode().equals(orderInfo.getOrderType())) {
+ throw new ServiceException("当前订单不是仅维保订单,无需续用关联项目SN");
+ }
+ if (orderInfo.getRelatedOrderId() == null) {
+ throw new ServiceException("当前仅维保订单未配置关联项目,无法发货");
+ }
+ ProjectOrderInfo relatedOrder = projectOrderInfoService.selectProjectOrderInfoById(orderInfo.getRelatedOrderId());
+ if (relatedOrder == null) {
+ throw new ServiceException("关联项目订单不存在");
+ }
+ List snList = inventoryDeliveryMapper.listMaintenanceSn(relatedOrder.getOrderCode(), productCode);
+ MaintenanceDeliveryVo vo = new MaintenanceDeliveryVo();
+ vo.setRelatedOrderId(relatedOrder.getId());
+ vo.setRelatedOrderCode(relatedOrder.getOrderCode());
+ vo.setRelatedProjectName(relatedOrder.getProjectName());
+ vo.setSnList(snList == null ? new ArrayList<>() : snList);
+ vo.setAvailableNum(CollUtil.isEmpty(snList) ? 0 : snList.size());
+ return vo;
+ }
+
+ /**
+ * 校验仅维保订单发货的SN必须来自关联项目同产品编码的已发货SN
+ */
+ private void validateMaintenanceDeliverySn(String orderCode, String productCode, List productSnList) {
+ MaintenanceDeliveryVo maintenanceVo = getMaintenanceSnList(orderCode, productCode);
+ List availableSnList = maintenanceVo.getSnList().stream()
+ .map(MaintenanceSnVo::getProductSn).collect(Collectors.toList());
+ if (CollUtil.isEmpty(productSnList) || !availableSnList.containsAll(productSnList)) {
+ throw new ServiceException("仅维保订单只能发关联项目已发货的SN,请重新选择发货清单");
+ }
+ }
}
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java
index b2fed239..82c15b85 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java
@@ -329,6 +329,7 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To
if (projectOrderInfo.getProjectId() == null) {
throw new ServiceException("请选择项目");
}
+ validateRelatedOrder(projectOrderInfo, projectOrderInfo.getOrderType());
List projectOrderInfos = this.selectProjectOrderInfoByProjectId(Collections.singletonList(projectOrderInfo.getProjectId()));
if (CollUtil.isNotEmpty(projectOrderInfos)) {
throw new ServiceException("该项目存在订单流转,无法添加");
@@ -448,6 +449,15 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To
}
projectInfoMapper.updateProjectInfo(projectInfo);
+ // 前端未回传订单类型时以库中已有类型为准,避免仅维保校验被绕过
+ String effectiveOrderType = StringUtils.isNotEmpty(projectOrderInfo.getOrderType())
+ ? projectOrderInfo.getOrderType() : existProjectOrderInfo.getOrderType();
+ validateRelatedOrder(projectOrderInfo, effectiveOrderType);
+ if (!ProjectOrderInfo.OrderTypeEnum.MAINTENANCE.getCode().equals(effectiveOrderType)
+ && existProjectOrderInfo.getRelatedOrderId() != null) {
+ //订单类型由仅维保改回正常:动态update不会写入null,需显式清空历史关联
+ projectOrderInfoMapper.clearRelatedOrderId(projectOrderInfo.getId());
+ }
//不更新订单编号
projectOrderInfo.setOrderCode(null);
projectOrderInfo.setUpdateBy(ShiroUtils.getUserId().toString());
@@ -529,6 +539,46 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To
return projectOrderInfoMapper.updateProjectOrderInfoByCode(projectOrderInfo);
}
+ @Override
+ public List selectRelatedCandidateList(String projectCode, String projectName, Long excludeOrderId) {
+ Map params = new HashMap<>();
+ params.put("projectCode", projectCode);
+ params.put("projectName", projectName);
+ params.put("excludeOrderId", excludeOrderId);
+ return projectOrderInfoMapper.selectRelatedCandidateList(params);
+ }
+
+ /**
+ * 校验「关联项目」:仅维保订单必须关联一个已审批完成的正常订单,且不能是订单自身;
+ * 非仅维保订单不保留关联项目。
+ *
+ * @param projectOrderInfo 待保存订单
+ * @param orderType 生效的订单类型(编辑时前端可能不回传)
+ */
+ private void validateRelatedOrder(ProjectOrderInfo projectOrderInfo, String orderType) {
+ if (!ProjectOrderInfo.OrderTypeEnum.MAINTENANCE.getCode().equals(orderType)) {
+ projectOrderInfo.setRelatedOrderId(null);
+ return;
+ }
+ Long relatedOrderId = projectOrderInfo.getRelatedOrderId();
+ if (relatedOrderId == null) {
+ throw new ServiceException("仅维保订单必须选择关联项目");
+ }
+ if (relatedOrderId.equals(projectOrderInfo.getId())) {
+ throw new ServiceException("关联项目不能选择当前订单本身");
+ }
+ ProjectOrderInfo related = projectOrderInfoMapper.selectProjectOrderInfoById(relatedOrderId);
+ if (related == null) {
+ throw new ServiceException("关联项目订单不存在");
+ }
+ if (!ProjectOrderInfo.OrderTypeEnum.NORMAL.getCode().equals(related.getOrderType())) {
+ throw new ServiceException("仅维保订单只能关联正常订单");
+ }
+ if (!ProjectOrderInfo.OrderStatus.APPROVE_COMPLETE.getCode().equals(related.getOrderStatus())) {
+ throw new ServiceException("关联项目订单不处于审批完成状态,无法关联");
+ }
+ }
+
private String getFlowBusinessKey(String code, String processType) {
if (StringUtils.isEmpty(code)) {
throw new ServiceException("流程BusinessKey为空");
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/vo/DeliveryInfoVo.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/vo/DeliveryInfoVo.java
index 22e41ffb..5d0dab03 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/vo/DeliveryInfoVo.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/vo/DeliveryInfoVo.java
@@ -38,6 +38,17 @@ public class DeliveryInfoVo {
private Date serviceStartTime;
private List serviceInfo;
+ /**
+ * 订单审批完成时间:仅维保续算时用于订单排序,审批时间为空回退 createTime
+ */
+ @JsonIgnore
+ private Date approveTime;
+ /**
+ * 订单创建时间
+ */
+ @JsonIgnore
+ private Date createTime;
+
private Date lastUpdateTime;
@JsonIgnore
private Long projectId;
diff --git a/ruoyi-sip/src/main/resources/mapper/inventory/InventoryDeliveryMapper.xml b/ruoyi-sip/src/main/resources/mapper/inventory/InventoryDeliveryMapper.xml
index f280f007..d0f3d0c6 100644
--- a/ruoyi-sip/src/main/resources/mapper/inventory/InventoryDeliveryMapper.xml
+++ b/ruoyi-sip/src/main/resources/mapper/inventory/InventoryDeliveryMapper.xml
@@ -85,51 +85,101 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where t3.order_code= #{orderCode} and t1.delivery_status = #{status}
+
+
insert into oms_inventory_delivery
diff --git a/ruoyi-sip/src/main/resources/mapper/sip/ProjectOrderInfoMapper.xml b/ruoyi-sip/src/main/resources/mapper/sip/ProjectOrderInfoMapper.xml
index 3cc0beb9..f0c106ca 100644
--- a/ruoyi-sip/src/main/resources/mapper/sip/ProjectOrderInfoMapper.xml
+++ b/ruoyi-sip/src/main/resources/mapper/sip/ProjectOrderInfoMapper.xml
@@ -50,6 +50,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+
+
+
@@ -57,7 +60,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
shipment_amount, actual_purchase_amount, order_end_time, delivery_time, company_delivery, notifier,finance_status,
notifier_email, notifier_phone, duty, duty_email, duty_phone, order_channel, partner_code, supplier,notifier_address,
remark, order_status, create_by, create_time, update_by, update_time,version_code,process_type,process_template,discount_fold,order_stocking_status,
- delivery_status,sign_status,outer_status,approve_time,payment_method,payment_ratio,payment_description,order_type,operation_version,reback_approve_status
+ delivery_status,sign_status,outer_status,approve_time,payment_method,payment_ratio,payment_description,order_type,operation_version,reback_approve_status,related_order_id
from project_order_info t1
@@ -67,7 +70,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
t1.notifier_email, t1.notifier_phone, t1.duty, t1.duty_email, t1.duty_phone, t1.order_channel, t1.partner_code, t1.supplier,
t1.remark, t1.order_status, t1.create_by, t1.create_time, t1.update_by, t1.update_time,t1.partner_user_name,t1.partner_email
,t1.partner_phone,t1.version_code,t1.process_type,t1.process_template,t1.discount_fold,t1.notifier_address,t1.finance_status,
- t1.delivery_status,t1.sign_status,t1.outer_status,t1.approve_time,t1.payment_method,t1.payment_ratio,t1.payment_description,t1.operation_version,t1.order_stocking_status,t1.reback_approve_status
+ t1.delivery_status,t1.sign_status,t1.outer_status,t1.approve_time,t1.payment_method,t1.payment_ratio,t1.payment_description,t1.operation_version,t1.order_stocking_status,t1.reback_approve_status,t1.related_order_id
,t2.project_code,t2.project_name,t2.project_desc,t2.software_info,t2.hardware_info,t2.terminal_peripheral,t2.server_configuration
,t2.management_version,t2.desktop_vm_os_version,t2.vm_spec_quantity,t2.key_problem,t2.joint_trial_result
,t2.province,t2.customer_name,t2.customer_code,t2.industry_type,t2.bg_property,t2.agent_code,t2.estimated_order_time
@@ -76,7 +79,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
,t4.agent_name
,t5.user_name as duty_name
,t6.charge_status,t6.biz_charge_date,t6.finance_charge_date
+ ,rel_order.order_code related_order_code,rel_project.project_name related_project_name
from project_order_info t1
+ left join project_order_info rel_order on t1.related_order_id = rel_order.id
+ left join project_info rel_project on rel_order.project_id = rel_project.id
left join project_info t2 on t1.project_id = t2.id
left join partner_info t3 on t1.partner_code=t3.partner_code
@@ -85,6 +91,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
left join oms_finance_charge t6 on t1.order_code=t6.order_code
+
+
+
#{projectId},
@@ -695,6 +716,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{paymentRatio},
#{paymentDescription},
#{operationVersion},
+ #{relatedOrderId},
@@ -839,6 +861,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
finance_status = #{financeStatus},
reback_approve_status = #{rebackApproveStatus},
operation_version = #{operationVersion},
+ related_order_id = #{relatedOrderId},
where id = #{id}
@@ -847,6 +870,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
set reback_approve_status = null
where id = #{id}
+
+
+ update project_order_info
+ set related_order_id = null
+ where id = #{id}
+
update project_order_info