package com.chinaztt.mes.plan.service.impl;
|
|
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.http.HttpRequest;
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
|
import com.chinaztt.ifs.api.feign.IfsFeignClient;
|
import com.chinaztt.mes.basic.entity.Part;
|
import com.chinaztt.mes.basic.mapper.PartMapper;
|
import com.chinaztt.mes.common.handler.StateMachineHandler;
|
import com.chinaztt.mes.common.numgen.NumberGenerator;
|
import com.chinaztt.mes.common.oa.OAProcess;
|
import com.chinaztt.mes.common.oa.OAProperty;
|
import com.chinaztt.mes.common.oa.OAResult;
|
import com.chinaztt.mes.common.util.StateResult;
|
import com.chinaztt.mes.plan.dto.*;
|
import com.chinaztt.mes.plan.entity.MasterProductionSchedule;
|
import com.chinaztt.mes.plan.entity.MasterProductionScheduleTheoryQuantity;
|
import com.chinaztt.mes.plan.entity.MpsStructureComponent;
|
import com.chinaztt.mes.plan.entity.OperationTaskProduce;
|
import com.chinaztt.mes.plan.mapper.*;
|
import com.chinaztt.mes.plan.service.CustomerOrderService;
|
import com.chinaztt.mes.plan.service.MasterProductionScheduleService;
|
import com.chinaztt.mes.plan.state.auditstate.constant.AuditStateStringValues;
|
import com.chinaztt.mes.plan.state.masterproductionschedule.MasterProductionScheduleStateMachineConfig;
|
import com.chinaztt.mes.plan.state.masterproductionschedule.constant.MasterProductionScheduleEvents;
|
import com.chinaztt.mes.plan.state.masterproductionschedule.constant.MasterProductionScheduleStates;
|
import com.chinaztt.mes.technology.entity.Document;
|
import com.chinaztt.mes.technology.entity.Routing;
|
import com.chinaztt.mes.technology.entity.Structure;
|
import com.chinaztt.mes.technology.mapper.DocumentMapper;
|
import com.chinaztt.mes.technology.mapper.RoutingMapper;
|
import com.chinaztt.mes.technology.mapper.StructureMapper;
|
import com.chinaztt.mes.technology.service.DocumentService;
|
import com.chinaztt.mes.technology.state.document.constant.DocumentStates;
|
import com.chinaztt.ztt.admin.api.vo.TreeUtil;
|
import com.chinaztt.ztt.common.core.util.R;
|
import com.chinaztt.ztt.common.security.util.SecurityUtils;
|
import lombok.AllArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.lang3.StringUtils;
|
import org.springframework.messaging.Message;
|
import org.springframework.messaging.support.MessageBuilder;
|
import org.springframework.statemachine.config.StateMachineFactory;
|
import org.springframework.statemachine.persist.StateMachinePersister;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.CollectionUtils;
|
|
import java.math.BigDecimal;
|
import java.util.Comparator;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.stream.Collectors;
|
|
/**
|
* 计划
|
*
|
* @author cxf
|
* @date 2020-09-21 14:42:39
|
*/
|
@Slf4j
|
@Service
|
@AllArgsConstructor
|
@Transactional(rollbackFor = Exception.class)
|
public class MasterProductionScheduleServiceImpl extends ServiceImpl<MasterProductionScheduleMapper, MasterProductionSchedule> implements MasterProductionScheduleService {
|
|
private CustomerOrderMapper customerOrderMapper;
|
private CustomerOrderService customerOrderService;
|
private DocumentMapper documentMapper;
|
private DocumentService documentService;
|
private IfsFeignClient ifsFeignClient;
|
private MasterProductionScheduleMapper masterProductionScheduleMapper;
|
private MasterProductionScheduleTheoryQuantityMapper masterProductionScheduleTheoryQuantityMapper;
|
private MpsSourceMapper planMpsSourceMapper;
|
private MpsStructureComponentMapper mpsStructureComponentMapper;
|
private NumberGenerator<MasterProductionSchedule> scheduleNumberGenerator;
|
private OAProperty oaProperty;
|
private OutsourcingOrderMapper outsourcingOrderMapper;
|
private OperationTaskProduceMapper operationTaskProduceMapper;
|
private PartMapper partMapper;
|
private RoutingMapper routingMapper;
|
private StructureMapper structureMapper;
|
private StateMachineFactory<MasterProductionScheduleStates, MasterProductionScheduleEvents> masterproductionscheduleStateMachineFactory;
|
private StateMachinePersister<MasterProductionScheduleStates, MasterProductionScheduleEvents, MasterProductionSchedule> persister;
|
|
|
@Override
|
public IPage<List<MasterProductionScheduleDTO>> getMasterProductionSchedulePage(Page page, QueryWrapper<MasterProductionScheduleDTO> masterProductionScheduleDTO) {
|
return baseMapper.getMasterProductionSchedulePage(page, masterProductionScheduleDTO);
|
}
|
|
@Override
|
public MasterProductionScheduleDTO getByIdExt(Long id) {
|
if (null == id) {
|
return null;
|
}
|
return baseMapper.getByIdExt(id);
|
}
|
|
@Override
|
public List<MpsSourceDTO> loadMasterPlanSourceById(Long id) {
|
return planMpsSourceMapper.loadMasterPlanSourceById(id);
|
}
|
|
@Override
|
public boolean updateQtyPlaned(CustomerOrderDTO customerOrderDTO) {
|
MasterProductionSchedule masterProductionSchedule = baseMapper.selectById(customerOrderDTO.getMpsId());
|
// 1.检查对应需求数量是否超出:客户订单的销售数量require - 客户订单的已下发数量original >= 主计划的修改数量updatePlan - 主计划的下发数量plan(有需要可以简化,当前方便阅读)
|
//主计划的修改数量
|
BigDecimal updatePlan = customerOrderDTO.getQtyPlaned();
|
// 2.3 保存计划
|
masterProductionSchedule.setQtyRequired(updatePlan);
|
baseMapper.updateById(masterProductionSchedule);
|
// 删除原先的理论用量重
|
masterProductionScheduleTheoryQuantityMapper.delete(Wrappers.<MasterProductionScheduleTheoryQuantity>lambdaQuery()
|
.eq(MasterProductionScheduleTheoryQuantity::getMid, masterProductionSchedule.getId()));
|
// 重新计算理论用量
|
customerOrderService.calPlanTheory(masterProductionSchedule);
|
return true;
|
}
|
|
|
@Override
|
public List<MpsStructureComponentDTO> saveMpsStructureComponent(List<MpsStructureComponentDTO> list, Long mpsId) {
|
MpsStructureComponentDTO mpsStructureComponentDTO = list.get(0);
|
// 1.先把对应的主计划产品结构全部删除
|
mpsStructureComponentMapper.delete(Wrappers.<MpsStructureComponent>query().lambda().eq(MpsStructureComponent::getMpsId, mpsId));
|
// 2.保存结构
|
if (mpsStructureComponentDTO.getParentId() == null) {
|
mpsStructureComponentDTO.setParentId(0L);
|
}
|
saveOrUpdateComponent(mpsStructureComponentDTO, mpsId);
|
return list;
|
}
|
|
public void saveOrUpdateComponent(MpsStructureComponentDTO mpsStructureComponentDTO, Long mpsId) {
|
// 如果存在id就更新回来,其他就新增
|
if (mpsStructureComponentDTO.getId() != null) {
|
mpsStructureComponentMapper.updateActiveById(mpsStructureComponentDTO.getId());
|
} else {
|
mpsStructureComponentDTO.setMpsId(mpsId);
|
mpsStructureComponentDTO.setManufacturingOrderQuantity(BigDecimal.ZERO);
|
mpsStructureComponentMapper.insert(mpsStructureComponentDTO);
|
}
|
List<MpsStructureComponentDTO> children = mpsStructureComponentDTO.getChildren();
|
if (CollectionUtil.isNotEmpty(children)) {
|
for (MpsStructureComponentDTO component : children) {
|
if (component.getParentId() == null) {
|
component.setParentId(mpsStructureComponentDTO.getId());
|
}
|
saveOrUpdateComponent(component, mpsId);
|
}
|
}
|
}
|
|
@Override
|
public boolean deleteMpsStructureComponentById(Long id) {
|
// 递归删除结构节点
|
recursiveDeleteMpsStructureComponent(id);
|
return true;
|
}
|
|
public void recursiveDeleteMpsStructureComponent(Long id) {
|
mpsStructureComponentMapper.delete(Wrappers.<MpsStructureComponent>query().lambda().eq(MpsStructureComponent::getId, id).ne(MpsStructureComponent::getParentId, 0));
|
List<MpsStructureComponent> children = mpsStructureComponentMapper.selectList(Wrappers.<MpsStructureComponent>query().lambda().eq(MpsStructureComponent::getParentId, id));
|
if (CollectionUtil.isNotEmpty(children)) {
|
for (MpsStructureComponent child : children) {
|
recursiveDeleteMpsStructureComponent(child.getId());
|
}
|
}
|
}
|
|
@Override
|
public List<MpsStructureComponentTreeNode> getMpsStructureComponentByMpsId(Long id) {
|
List<MpsStructureComponentTreeNode> collect = mpsStructureComponentMapper.selectDtoListByMpsId(id)
|
.stream().sorted(Comparator.comparing(MpsStructureComponent::getId)).map(mpsStructureComponentDTO -> {
|
MpsStructureComponentTreeNode node = new MpsStructureComponentTreeNode();
|
node.setId(mpsStructureComponentDTO.getId().intValue());
|
node.setPartId(mpsStructureComponentDTO.getPartId());
|
node.setPartNo(mpsStructureComponentDTO.getPartNo());
|
node.setDrawingNumber(mpsStructureComponentDTO.getDrawingNumber());
|
node.setUnit(mpsStructureComponentDTO.getUnit());
|
node.setParentId(mpsStructureComponentDTO.getParentId().intValue());
|
node.setLabel(mpsStructureComponentDTO.getLabel());
|
node.setManufacturingOrderQuantity(mpsStructureComponentDTO.getManufacturingOrderQuantity());
|
node.setMpsId(mpsStructureComponentDTO.getMpsId());
|
node.setQpa(mpsStructureComponentDTO.getQpa());
|
return node;
|
}).collect(Collectors.toList());
|
return TreeUtil.build(collect, 0);
|
}
|
|
@Override
|
public MpsStructureComponentDTO insertMpsStructureComponent(MpsStructureComponentDTO mpsStructureComponentDTO, Long mpsId) {
|
try {
|
saveOrUpdateComponent(mpsStructureComponentDTO, mpsId);
|
} catch (Exception e) {
|
throw new RuntimeException("新增节点失败");
|
}
|
return mpsStructureComponentDTO;
|
}
|
|
@Override
|
public boolean updateMpsStructureComponent(MpsStructureComponentDTO mpsStructureComponentDTO) {
|
return SqlHelper.retBool(mpsStructureComponentMapper.updateById(mpsStructureComponentDTO));
|
}
|
|
@Override
|
public boolean changeState(List<Long> ids, String event) {
|
for (Long id : ids) {
|
MasterProductionSchedule masterProductionSchedule = baseMapper.selectById(id);
|
Message<MasterProductionScheduleEvents> message = MessageBuilder.withPayload(MasterProductionScheduleEvents.valueOf(event)).setHeader("masterProductionSchedule", masterProductionSchedule).build();
|
StateMachineHandler handler = new StateMachineHandler(masterproductionscheduleStateMachineFactory, persister, MasterProductionScheduleStateMachineConfig.MACHINE_ID, masterProductionSchedule);
|
StateResult res = handler.sendEvent(message, masterProductionSchedule.getId());
|
if (!res.isSuccess()) {
|
throw new RuntimeException(res.getMsg());
|
}
|
}
|
return true;
|
}
|
|
@Override
|
public List<OutsourcingOrderDTO> loadOrder(Long id) {
|
return outsourcingOrderMapper.loadOrderByMpsId(id);
|
}
|
|
@Override
|
public List<CustomerOrderDTO> loadMasterPlanSourceByCustomer(Long id) {
|
return customerOrderMapper.loadMasterPlanSourceByCustomer(id);
|
}
|
|
@Override
|
public R handleDocument(List<Long> ids, Long docId) {
|
Integer count = baseMapper.selectCount(Wrappers.<MasterProductionSchedule>lambdaQuery()
|
.isNotNull(MasterProductionSchedule::getTechnologyDocumentId)
|
.in(MasterProductionSchedule::getId, ids));
|
if (count > 0) {
|
return R.failed("存在关联的生产计划");
|
} else {
|
List<MasterProductionSchedule> masterProductionScheduleList = baseMapper.selectBatchIds(ids);
|
Document document = documentMapper.selectById(docId);
|
if (document == null) {
|
return R.failed("工艺文件缺失");
|
} else {
|
masterProductionScheduleList.forEach(MasterProductionSchedule -> {
|
MasterProductionSchedule.setTechnologyDocumentId(document.getId());
|
MasterProductionSchedule.setDocNumber(document.getNumber());
|
baseMapper.updateById(MasterProductionSchedule);
|
customerOrderService.calPlanTheory(MasterProductionSchedule);
|
});
|
return R.ok();
|
}
|
}
|
}
|
|
/**
|
* 取消关联
|
*
|
* @param ids
|
* @return
|
*/
|
@Override
|
public R rejectHandleDocument(List<Long> ids) {
|
for (Long id : ids) {
|
MasterProductionSchedule masterProductionSchedule = baseMapper.selectById(id);
|
// if (masterProductionSchedule.getIsAudit() != null) {
|
// if (masterProductionSchedule.getIsAudit().equals(AuditStateStringValues.ACCEPTED) || masterProductionSchedule.getIsAudit().equals(AuditStateStringValues.PENDING)) {
|
// return R.failed("生产计划号为" + masterProductionSchedule.getMpsNo() + ",已在流程中不可取消关联");
|
// }
|
// }
|
baseMapper.rejectHandleDocument(id);
|
masterProductionScheduleTheoryQuantityMapper.delete(Wrappers.<MasterProductionScheduleTheoryQuantity>lambdaQuery()
|
.eq(MasterProductionScheduleTheoryQuantity::getMid, id));
|
}
|
return R.ok();
|
}
|
|
/**
|
* oa对接
|
*
|
* @param id
|
* @return
|
*/
|
@Override
|
public R oa(Long id) {
|
try {
|
MasterProductionSchedule masterProductionSchedule = baseMapper.selectById(id);
|
if (masterProductionSchedule.getTechnologyDocumentId() == null) {
|
return R.failed("请先关联工艺文件");
|
}
|
Map<String, String> fields = new HashMap<>();
|
Document document = documentMapper.selectById(masterProductionSchedule.getTechnologyDocumentId());
|
Part part = partMapper.selectById(document.getPartId());
|
//零件编号
|
fields.put("part_no", part.getPartNo());
|
//零件名称
|
fields.put("part_desc", part.getPartName());
|
//产品名称
|
fields.put("product_name", part.getPartName());
|
//规格型号
|
fields.put("product_style", part.getSpecs());
|
//订单来源
|
fields.put("source", "masterProductionSchedule");
|
//工艺文件展示连接
|
fields.put("technology_document_id", "<a href='" + oaProperty.getDocumentUrl() + masterProductionSchedule.getTechnologyDocumentId() + "' target='_blank'>工艺审批流程,点击阅览</a>");
|
OAResult oaResult = OAProcess.start(fields, "工艺审批流程", oaProperty.getCustomerOrderOaId(), SecurityUtils.getUser().getUsername());
|
if (oaResult.success()) {
|
//OA流程发起成功,状态变成待审批 ,订单和工艺文件同步进行
|
masterProductionSchedule.setOaWorkflowId(oaResult.getAddWorkflowResult());
|
masterProductionSchedule.setIsAudit(AuditStateStringValues.PENDING);
|
baseMapper.updateById(masterProductionSchedule);
|
document.setOaWorkflowId(oaResult.getAddWorkflowResult());
|
document.setState(DocumentStates.PENDING.getValue());
|
documentMapper.updateById(document);
|
return R.ok().setMsg("发起成功");
|
} else {
|
return R.failed(oaResult.getErrorMsg());
|
}
|
} catch (Exception e) {
|
return R.failed("发起失败");
|
}
|
}
|
|
@Override
|
public R changeAudit(Long id, String status) {
|
MasterProductionSchedule masterProductionSchedule = baseMapper.selectById(id);
|
Document document = documentMapper.selectById(masterProductionSchedule.getTechnologyDocumentId());
|
if (document == null) {
|
return R.failed("缺少工艺文件");
|
}
|
masterProductionSchedule.setIsAudit(status);
|
baseMapper.updateById(masterProductionSchedule);
|
if (status.equals(AuditStateStringValues.ACCEPTED)) {
|
document.setState(status);
|
documentService.saveOrUpdate(document);
|
}
|
return R.ok().setMsg("操作成功");
|
}
|
|
@Override
|
public R queryInventUseablePlanStd(String partNo) {
|
if (StringUtils.isBlank(partNo)) {
|
return R.failed("无零件号");
|
}
|
R result = ifsFeignClient.queryInventUseablePlanStd(new JSONObject().fluentPut("PART_NO", partNo), true);
|
if (result.getCode() == 0) {
|
JSONObject data = (JSONObject) JSON.toJSON(result.getData());
|
return R.ok(data.getJSONArray("LIST_INFO"), "OK");
|
} else {
|
return R.failed("IFS错误——" + result.getMsg());
|
}
|
}
|
|
/**
|
* 工艺文件对接IFS
|
*
|
* @param id
|
* @return
|
*/
|
@Override
|
public R checkIfsSync(Long id) {
|
MasterProductionSchedule masterProductionSchedule = masterProductionScheduleMapper.selectById(id);
|
if (masterProductionSchedule.getTechnologyDocumentId() != null) {
|
Document document = documentMapper.selectById(masterProductionSchedule.getId());
|
if (document == null) {
|
return R.failed("工艺文件丢失");
|
}
|
List<Routing> routingList = routingMapper.selectUnIfsSyncByDocId(document.getId());
|
if (!CollectionUtils.isEmpty(routingList)) {
|
return R.failed("工艺路线未同步");
|
}
|
List<Structure> structureList = structureMapper.getUnIfsedStructureDtoByDocId(document.getId());
|
if (!CollectionUtils.isEmpty(structureList)) {
|
return R.failed("产品结构未同步");
|
}
|
}
|
return R.ok();
|
}
|
|
/**
|
* 查询半成品理论用量
|
*
|
* @param id
|
* @return
|
*/
|
@Override
|
public R getTheoryQuantity(Long id, List<OperationTaskProduce> operationTaskProduceList) {
|
List<MasterProductionScheduleTheoryQuantityDTO> masterProductionScheduleTheoryQuantityDTOList = masterProductionScheduleTheoryQuantityMapper.getTheoryQuantity(id);
|
// changeQty(id, masterProductionScheduleTheoryQuantityDTOList, operationTaskProduceList);
|
return R.ok(masterProductionScheduleTheoryQuantityDTOList);
|
}
|
|
/**
|
* 成品订单需求数量改为段长长度和
|
*
|
* @param id
|
* @param masterProductionScheduleTheoryQuantityDTOList
|
* @param operationTaskProduceList
|
*/
|
private void changeQty(Long id, List<MasterProductionScheduleTheoryQuantityDTO> masterProductionScheduleTheoryQuantityDTOList, List<OperationTaskProduce> operationTaskProduceList) {
|
if (CollectionUtil.isNotEmpty(operationTaskProduceList)) {
|
//查询成品的用量
|
List<MasterProductionScheduleTheoryQuantity> list = masterProductionScheduleTheoryQuantityMapper.selectList(
|
Wrappers.<MasterProductionScheduleTheoryQuantity>lambdaQuery()
|
.eq(MasterProductionScheduleTheoryQuantity::getMid, id)
|
.eq(MasterProductionScheduleTheoryQuantity::getIsMaster, true)
|
);
|
if (list.size() != 1) {
|
throw new RuntimeException("成品工序的理论用量丢失,或存在多个成品理论用量");
|
}
|
//段长长度总和
|
BigDecimal totalQuantity = operationTaskProduceList.stream().map(OperationTaskProduce::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);
|
masterProductionScheduleTheoryQuantityDTOList.forEach(e -> {
|
//成品理论数量
|
BigDecimal rtq = list.get(0).getQuantity();
|
//成品段长长度总和
|
BigDecimal tq = totalQuantity;
|
//当前产出的理论用量
|
BigDecimal thq = e.getQuantity();
|
//实际数量
|
BigDecimal acq = thq.multiply(tq).divide(rtq).setScale(3, BigDecimal.ROUND_UP);
|
e.setOrderQuantity(acq);
|
});
|
}
|
}
|
|
/**
|
* 手动新增生产计划
|
*
|
* @param masterProductionSchedule
|
* @return
|
*/
|
@Override
|
public R doAdd(MasterProductionSchedule masterProductionSchedule) {
|
if (StringUtils.isBlank(masterProductionSchedule.getManufactureAttr())) {
|
masterProductionSchedule.setManufactureAttr("N");
|
}
|
masterProductionSchedule.setMpsNo(scheduleNumberGenerator.generateNumberWithPrefix(MasterProductionSchedule.DIGIT, MasterProductionSchedule.PREFIX, MasterProductionSchedule::getMpsNo));
|
masterProductionSchedule.setIsAudit(AuditStateStringValues.DRAFT);
|
return R.ok(save(masterProductionSchedule));
|
}
|
|
/**
|
* 根据id查询
|
*
|
* @param id
|
* @return
|
*/
|
@Override
|
public MasterProductionScheduleDTO getById(Long id) {
|
MasterProductionScheduleDTO masterProductionScheduleDTO = baseMapper.getDtoById(id);
|
List<OperationTaskProduce> operationTaskProduceList = operationTaskProduceMapper.selectList(Wrappers.<OperationTaskProduce>lambdaQuery()
|
.eq(OperationTaskProduce::getMpsId, id));
|
masterProductionScheduleDTO.setOutPutBatchList(operationTaskProduceList);
|
return masterProductionScheduleDTO;
|
}
|
|
/**
|
* 添加采购计划
|
* @param masterProductionSchedules
|
* @return
|
*/
|
@Override
|
public boolean addPlanPurchasing(List<MasterProductionSchedule>masterProductionSchedules) {
|
masterProductionSchedules.forEach(p->{
|
Long technologyDocumentId = p.getTechnologyDocumentId();
|
Document document = documentMapper.selectById(technologyDocumentId);
|
Long firstPart = document.getPartId();
|
String url="http://192.168.20.47:8008/PurchService.ashx?contract=ZTKJ&contractKey=4ttDeLKNsZuhstjtROMcRE1USNFXKdFYE7lQ2p1m5Bo=&procedureName=QUERY_INVENTORY_INFO_STD&userId=7632&inAttr={\"LOCATION_NO\": \"1019\",\"PART_NO\":"+p+"}";
|
String body = HttpRequest.get(url).execute().body();
|
JSONObject partInfo = JSONObject.parseObject(body);
|
log.info("库存零件======>"+partInfo);
|
});
|
return false;
|
}
|
|
|
|
|
|
}
|