/**
* ***************************************************************************
* Copyright (c) 2010 Qcadoo Limited
* Project: Qcadoo MES
* Version: 1.2.0
*
* This file is part of Qcadoo.
*
* Qcadoo is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* ***************************************************************************
*/
package com.qcadoo.mes.genealogies;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import com.qcadoo.mes.basic.constants.BasicConstants;
import com.qcadoo.mes.genealogies.constants.GenealogiesConstants;
import com.qcadoo.mes.orders.constants.OrdersConstants;
import com.qcadoo.mes.states.messages.MessageService;
import com.qcadoo.mes.states.messages.MessagesHolder;
import com.qcadoo.mes.states.messages.MessagesHolderImpl;
import com.qcadoo.mes.states.messages.constants.StateMessageType;
import com.qcadoo.mes.states.service.client.StateChangeViewClientUtil;
import com.qcadoo.mes.states.service.client.StateChangeViewClientValidationUtil;
import com.qcadoo.mes.technologies.TechnologyService;
import com.qcadoo.model.api.DataDefinition;
import com.qcadoo.model.api.DataDefinitionService;
import com.qcadoo.model.api.Entity;
import com.qcadoo.model.api.search.SearchRestrictions;
import com.qcadoo.model.api.search.SearchResult;
import com.qcadoo.model.api.validators.ErrorMessage;
import com.qcadoo.plugin.api.PluginManager;
import com.qcadoo.security.api.SecurityService;
import com.qcadoo.view.api.ComponentState;
import com.qcadoo.view.api.ComponentState.MessageType;
import com.qcadoo.view.api.ViewDefinitionState;
import com.qcadoo.view.api.components.FormComponent;
@Service
public class AutoGenealogyService {
private static final String BATCH_MODEL = "batch";
private static final String ORDER_MODEL = "order";
private static final String PRODUCT_MODEL = "product";
private static final String PRODUCT_IN_BATCH_MODEL = "productInBatch";
private static final String GENEALOGY_PRODUCT_IN_COMPONENT_MODEL = "genealogyProductInComponent";
private static final String NUMBER_FIELD = "number";
private static final String NAME_FIELD = "name";
private static final String BATCH_REQUIRED_FIELD = "batchRequired";
private static final String OPERATION_PRODUCT_IN_COMPONENTS_FIELD = "operationProductInComponents";
private static final String OPERATION_COMPONENTS_FIELD = "operationComponents";
private static final String PRODUCT_IN_COMPONENTS_FIELD = "productInComponents";
private static final String POST_FEATURES_FIELD = "postFeatures";
private static final String POST_FIELD = "post";
private static final String POST_FEATURE_REQUIRED_FIELD = "postFeatureRequired";
private static final String OTHER_FEATURES_FIELD = "otherFeatures";
private static final String OTHER_FIELD = "other";
private static final String OTHER_FEATURE_REQUIRED_FIELD = "otherFeatureRequired";
private static final String GENEALOGY_FIELD = "genealogy";
private static final String SHIFT_FEATURES_FIELD = "shiftFeatures";
private static final String SHIFT_FIELD = "shift";
private static final String SHIFT_FEATURE_REQUIRED_FIELD = "shiftFeatureRequired";
private static final String GENEALOGIES_FOR_COMPONENTS_PLUGIN = "genealogiesForComponents";
private static final String DATE_FIELD = "date";
private static final String WORKER_FIELD = "worker";
private static final String TECHNOLOGY_FIELD = "technology";
private static final String LAST_USED_OTHER_FIELD = "lastUsedOther";
private static final String LAST_USED_POST_FIELD = "lastUsedPost";
private static final String VALUE_FIELD = "value";
private static final String LAST_USED_SHIFT_FIELD = "lastUsedShift";
private static final String LAST_USED_BATCH_FIELD = "lastUsedBatch";
private static final String PRODUCT_IN_COMPONENT_FIELD = "productInComponent";
@Autowired
private DataDefinitionService dataDefinitionService;
@Autowired
private SecurityService securityService;
@Autowired
private TechnologyService technologyService;
@Autowired
private PluginManager pluginManager;
@Autowired
private MessageService messageService;
@Autowired
private StateChangeViewClientValidationUtil viewValidationUtil;
@Autowired
private StateChangeViewClientUtil viewUtil;
public void fillLastUsedBatchForProduct(final DataDefinition dataDefinition, final Entity entity) {
fillUserAndDate(entity);
Entity product = entity.getBelongsToField(PRODUCT_IN_COMPONENT_FIELD).getBelongsToField(PRODUCT_IN_COMPONENT_FIELD)
.getBelongsToField(PRODUCT_MODEL);
DataDefinition productInDef = dataDefinitionService.get(BasicConstants.PLUGIN_IDENTIFIER, BasicConstants.MODEL_PRODUCT);
Entity productEntity = productInDef.get(product.getId());
productEntity.setField(LAST_USED_BATCH_FIELD, entity.getField(BATCH_MODEL));
productInDef.save(productEntity);
}
public void fillLastUsedBatchForGenealogy(final DataDefinition dataDefinition, final Entity entity) {
fillUserAndDate(entity);
Entity product = entity.getBelongsToField(ORDER_MODEL).getBelongsToField(PRODUCT_MODEL);
if (product == null) {
return;
} else {
DataDefinition productInDef = dataDefinitionService.get(BasicConstants.PLUGIN_IDENTIFIER,
BasicConstants.MODEL_PRODUCT);
Entity productEntity = productInDef.get(product.getId());
productEntity.setField(LAST_USED_BATCH_FIELD, entity.getField(BATCH_MODEL));
productInDef.save(productEntity);
}
}
@Transactional
public void autocompleteGenealogy(final ViewDefinitionState viewDefinitionState, final ComponentState state,
final String[] args) {
if (state.getFieldValue() instanceof Long) {
Entity order = dataDefinitionService.get(OrdersConstants.PLUGIN_IDENTIFIER, OrdersConstants.MODEL_ORDER).get(
(Long) state.getFieldValue());
if (order == null) {
state.addMessage("qcadooView.message.entityNotFound", MessageType.FAILURE);
} else {
final MessagesHolder messagesHolder = new MessagesHolderImpl(messageService);
createGenealogy(order, messagesHolder, Boolean.parseBoolean(args[0]));
viewValidationUtil.addValidationErrorMessages(state, order, messagesHolder);
viewUtil.addStateMessagesToView(state, messagesHolder);
}
} else {
if (state instanceof FormComponent) {
state.addMessage("qcadooView.form.entityWithoutIdentifier", MessageType.FAILURE);
} else {
state.addMessage("qcadooView.grid.noRowSelectedError", MessageType.FAILURE);
}
}
}
public void fillLastUsedShiftFeature(final DataDefinition dataDefinition, final Entity entity) {
fillUserAndDate(entity);
DataDefinition featureDef = dataDefinitionService.get(GenealogiesConstants.PLUGIN_IDENTIFIER,
GenealogiesConstants.MODEL_CURRENT_ATTRIBUTE);
SearchResult searchResult = featureDef.find().setMaxResults(1).list();
if (!searchResult.getEntities().isEmpty()) {
Entity currentAttribute = searchResult.getEntities().get(0);
currentAttribute.setField(LAST_USED_SHIFT_FIELD, entity.getField(VALUE_FIELD));
featureDef.save(currentAttribute);
}
}
public void fillLastUsedPostFeature(final DataDefinition dataDefinition, final Entity entity) {
fillUserAndDate(entity);
DataDefinition featureDef = dataDefinitionService.get(GenealogiesConstants.PLUGIN_IDENTIFIER,
GenealogiesConstants.MODEL_CURRENT_ATTRIBUTE);
SearchResult searchResult = featureDef.find().setMaxResults(1).list();
if (!searchResult.getEntities().isEmpty()) {
Entity currentAttribute = searchResult.getEntities().get(0);
currentAttribute.setField(LAST_USED_POST_FIELD, entity.getField(VALUE_FIELD));
featureDef.save(currentAttribute);
}
}
public void fillLastUsedOtherFeature(final DataDefinition dataDefinition, final Entity entity) {
fillUserAndDate(entity);
DataDefinition featureDef = dataDefinitionService.get(GenealogiesConstants.PLUGIN_IDENTIFIER,
GenealogiesConstants.MODEL_CURRENT_ATTRIBUTE);
SearchResult searchResult = featureDef.find().setMaxResults(1).list();
if (!searchResult.getEntities().isEmpty()) {
Entity currentAttribute = searchResult.getEntities().get(0);
currentAttribute.setField(LAST_USED_OTHER_FIELD, entity.getField(VALUE_FIELD));
featureDef.save(currentAttribute);
}
}
private void fillUserAndDate(final Entity entity) {
if (entity.getField(DATE_FIELD) == null) {
entity.setField(DATE_FIELD, new Date());
}
if (entity.getField(WORKER_FIELD) == null) {
entity.setField(WORKER_FIELD, securityService.getCurrentUserName());
}
}
public void createGenealogy(final Entity order, final MessagesHolder messagesHolder, final boolean lastUsedMode) {
Entity mainProduct = order.getBelongsToField(PRODUCT_MODEL);
Entity technology = order.getBelongsToField(TECHNOLOGY_FIELD);
if (mainProduct == null || technology == null) {
messagesHolder.addMessage("genealogies.message.autoGenealogy.failure.product", StateMessageType.INFO);
return;
}
Object mainBatch = null;
if (lastUsedMode) {
mainBatch = mainProduct.getField(LAST_USED_BATCH_FIELD);
} else {
mainBatch = mainProduct.getField(BATCH_MODEL);
}
if (mainBatch == null) {
messagesHolder.addMessage("genealogies.message.autoGenealogy.missingMainBatch", StateMessageType.INFO);
return;
}
if (checkIfExistGenealogyWithBatch(order, mainBatch.toString())) {
messagesHolder.addMessage("genealogies.message.autoGenealogy.genealogyExist", StateMessageType.INFO);
return;
}
DataDefinition genealogyDef = dataDefinitionService.get(GenealogiesConstants.PLUGIN_IDENTIFIER,
GenealogiesConstants.MODEL_GENEALOGY);
Entity genealogy = genealogyDef.create();
genealogy.setField(ORDER_MODEL, order);
genealogy.setField(BATCH_MODEL, mainBatch);
completeAttributesForGenealogy(technology, genealogy, lastUsedMode);
if (pluginManager.isPluginEnabled(GENEALOGIES_FOR_COMPONENTS_PLUGIN)) {
completeBatchForComponents(technology, genealogy, lastUsedMode);
}
if (genealogy.isValid()) {
genealogy = genealogyDef.save(genealogy);
}
if (genealogy.isValid()) {
messagesHolder.addMessage("genealogies.message.autoGenealogy.success", StateMessageType.SUCCESS);
} else {
if (genealogy.getGlobalErrors().isEmpty()) {
messagesHolder.addMessage("genealogies.message.autoGenealogy.failure", StateMessageType.INFO);
} else {
for (ErrorMessage error : genealogy.getGlobalErrors()) {
messagesHolder.addMessage(error.getMessage(), StateMessageType.FAILURE, error.getVars());
}
}
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
private boolean checkIfExistGenealogyWithBatch(final Entity order, final String batch) {
SearchResult searchResult = dataDefinitionService
.get(GenealogiesConstants.PLUGIN_IDENTIFIER, GenealogiesConstants.MODEL_GENEALOGY).find()
.add(SearchRestrictions.eq(BATCH_MODEL, batch)).add(SearchRestrictions.belongsTo(ORDER_MODEL, order))
.setMaxResults(1).list();
if (!searchResult.getEntities().isEmpty()) {
return true;
}
return false;
}
private void completeAttributesForGenealogy(final Entity technology, final Entity genealogy, final boolean lastUsedMode) {
SearchResult searchResult = dataDefinitionService
.get(GenealogiesConstants.PLUGIN_IDENTIFIER, GenealogiesConstants.MODEL_CURRENT_ATTRIBUTE).find()
.setMaxResults(1).list();
Entity currentAttribute = null;
if (!searchResult.getEntities().isEmpty()) {
currentAttribute = searchResult.getEntities().get(0);
}
if ((Boolean) technology.getField(SHIFT_FEATURE_REQUIRED_FIELD)) {
Entity shift = dataDefinitionService.get(GenealogiesConstants.PLUGIN_IDENTIFIER,
GenealogiesConstants.MODEL_SHIFT_FEATURE).create();
shift.setField(GENEALOGY_FIELD, genealogy);
if (currentAttribute == null) {
shift.setField(VALUE_FIELD, null);
} else if (lastUsedMode) {
shift.setField(VALUE_FIELD, currentAttribute.getField(LAST_USED_SHIFT_FIELD));
} else {
shift.setField(VALUE_FIELD, currentAttribute.getField(SHIFT_FIELD));
}
if (shift.getField(VALUE_FIELD) == null) {
genealogy.addGlobalError("genealogies.message.autoGenealogy.missingShift");
} else {
genealogy.setField(SHIFT_FEATURES_FIELD, Collections.singletonList(shift));
}
}
if ((Boolean) technology.getField(OTHER_FEATURE_REQUIRED_FIELD)) {
Entity other = dataDefinitionService.get(GenealogiesConstants.PLUGIN_IDENTIFIER,
GenealogiesConstants.MODEL_OTHER_FEATURE).create();
other.setField(GENEALOGY_FIELD, genealogy);
if (currentAttribute == null) {
other.setField(VALUE_FIELD, null);
} else if (lastUsedMode) {
other.setField(VALUE_FIELD, currentAttribute.getField(LAST_USED_OTHER_FIELD));
} else {
other.setField(VALUE_FIELD, currentAttribute.getField(OTHER_FIELD));
}
if (other.getField(VALUE_FIELD) == null) {
genealogy.addGlobalError("genealogies.message.autoGenealogy.missingOther");
} else {
genealogy.setField(OTHER_FEATURES_FIELD, Collections.singletonList(other));
}
}
if ((Boolean) technology.getField(POST_FEATURE_REQUIRED_FIELD)) {
Entity post = dataDefinitionService.get(GenealogiesConstants.PLUGIN_IDENTIFIER,
GenealogiesConstants.MODEL_POST_FEATURE).create();
post.setField(GENEALOGY_FIELD, genealogy);
if (currentAttribute == null) {
post.setField(VALUE_FIELD, null);
} else if (lastUsedMode) {
post.setField(VALUE_FIELD, currentAttribute.getField(LAST_USED_POST_FIELD));
} else {
post.setField(VALUE_FIELD, currentAttribute.getField(POST_FIELD));
}
if (post.getField(VALUE_FIELD) == null) {
genealogy.addGlobalError("genealogies.message.autoGenealogy.missingPost");
} else {
genealogy.setField(POST_FEATURES_FIELD, Collections.singletonList(post));
}
}
}
@SuppressWarnings("unchecked")
private void completeBatchForComponents(final Entity technology, final Entity genealogy, final boolean lastUsedMode) {
genealogy.setField(PRODUCT_IN_COMPONENTS_FIELD, new ArrayList<Entity>());
List<String> componentsWithoutBatch = new ArrayList<String>();
List<Entity> operationComponents = new ArrayList<Entity>();
technologyService.addOperationsFromSubtechnologiesToList(technology.getTreeField(OPERATION_COMPONENTS_FIELD),
operationComponents);
for (Entity operationComponent : operationComponents) {
for (Entity operationProductComponent : operationComponent.getHasManyField(OPERATION_PRODUCT_IN_COMPONENTS_FIELD)) {
if (operationProductComponent.getField(BATCH_REQUIRED_FIELD) != null
&& (Boolean) operationProductComponent.getField(BATCH_REQUIRED_FIELD)) {
Entity productIn = dataDefinitionService.get(GENEALOGIES_FOR_COMPONENTS_PLUGIN,
GENEALOGY_PRODUCT_IN_COMPONENT_MODEL).create();
productIn.setField(GENEALOGY_FIELD, genealogy);
productIn.setField(PRODUCT_IN_COMPONENT_FIELD, operationProductComponent);
Entity product = (Entity) operationProductComponent.getField(PRODUCT_MODEL);
Object batch = null;
if (lastUsedMode) {
batch = product.getField(LAST_USED_BATCH_FIELD);
} else {
batch = product.getField(BATCH_MODEL);
}
if (batch == null) {
String value = product.getField(NUMBER_FIELD) + "-" + product.getField(NAME_FIELD) + "; ";
if (!componentsWithoutBatch.contains(value)) {
componentsWithoutBatch.add(value);
}
} else {
Entity productBatch = dataDefinitionService
.get(GENEALOGIES_FOR_COMPONENTS_PLUGIN, PRODUCT_IN_BATCH_MODEL).create();
productBatch.setField(BATCH_MODEL, batch);
productBatch.setField(PRODUCT_IN_COMPONENT_FIELD, productIn);
productIn.setField(BATCH_MODEL, Collections.singletonList(productBatch));
}
((List<Entity>) genealogy.getField(PRODUCT_IN_COMPONENTS_FIELD)).add(productIn);
}
}
}
if (!componentsWithoutBatch.isEmpty()) {
genealogy.addGlobalError("genealogies.message.autoGenealogy.missingBatch",
componentsWithoutBatch.toArray(new String[componentsWithoutBatch.size()]));
}
}
}