package com.qcadoo.mes.costCalculation.print;
import com.google.common.collect.Lists;
import com.qcadoo.mes.costCalculation.constants.CostCalculationFields;
import com.qcadoo.mes.costCalculation.print.utils.CostCalculationMaterial;
import com.qcadoo.mes.costNormsForMaterials.ProductsCostCalculationService;
import com.qcadoo.mes.costNormsForOperation.constants.CalculationOperationComponentFields;
import com.qcadoo.mes.technologies.ProductQuantitiesService;
import com.qcadoo.mes.technologies.constants.OperationProductOutComponentFields;
import com.qcadoo.mes.technologies.constants.TechnologyOperationComponentFields;
import com.qcadoo.mes.technologies.dto.OperationProductComponentHolder;
import com.qcadoo.model.api.BigDecimalUtils;
import com.qcadoo.model.api.Entity;
import com.qcadoo.model.api.EntityTree;
import com.qcadoo.model.api.NumberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class CostCalculationComponentsService {
private static final String L_COMPONENT = "component";
@Autowired
private ProductQuantitiesService productQuantitiesService;
@Autowired
private ProductsCostCalculationService productsCostCalculationService;
@Autowired
private NumberService numberService;
public void addMaterialOperationCost(final Entity costCalculation,
final Map<Long, ComponentsCalculationHolder> basicComponentsMap,
final Map<OperationProductComponentHolder, BigDecimal> materialQuantitiesByOPC) {
MathContext mathContext = numberService.getMathContext();
List<CostCalculationMaterial> list = Lists.newArrayList();
Entity order = costCalculation.getBelongsToField(CostCalculationFields.ORDER);
for (Map.Entry<OperationProductComponentHolder, BigDecimal> neededProductQuantity : materialQuantitiesByOPC.entrySet()) {
Entity product = neededProductQuantity.getKey().getProduct();
Entity productEntity = productsCostCalculationService.getAppropriateCostNormForProduct(product, order,
costCalculation.getStringField(CostCalculationFields.SOURCE_OF_MATERIAL_COSTS));
BigDecimal productQuantity = neededProductQuantity.getValue();
BigDecimal costForGivenQuantity = productsCostCalculationService.calculateProductCostForGivenQuantity(productEntity,
productQuantity, costCalculation.getStringField(CostCalculationFields.CALCULATE_MATERIAL_COSTS_MODE));
if (basicComponentsMap.containsKey((neededProductQuantity.getKey().getTechnologyOperationComponentId()))) {
ComponentsCalculationHolder cc = basicComponentsMap.get(neededProductQuantity.getKey()
.getTechnologyOperationComponentId());
BigDecimal materialCost = BigDecimalUtils.convertNullToZero(cc.getMaterialCost()).add(
BigDecimalUtils.convertNullToZero(costForGivenQuantity), mathContext);
cc.setMaterialCost(numberService.setScale(materialCost, 2));
}
}
}
public void addOperationCost(final Entity costCalculation, final Map<Long, ComponentsCalculationHolder> components) {
MathContext mathContext = numberService.getMathContext();
List<Entity> calculationOperationComponents = costCalculation
.getTreeField(CostCalculationFields.CALCULATION_OPERATION_COMPONENTS);
for (Entity calculationOperationComponent : calculationOperationComponents) {
BigDecimal totalMachineOperationCost = calculationOperationComponent
.getDecimalField(CalculationOperationComponentFields.TOTAL_MACHINE_OPERATION_COST);
BigDecimal totalLaborOperationCost = calculationOperationComponent
.getDecimalField(CalculationOperationComponentFields.TOTAL_LABOR_OPERATION_COST);
if (components.containsKey(calculationOperationComponent.getBelongsToField("technologyOperationComponent").getId())) {
ComponentsCalculationHolder holder = components.get(calculationOperationComponent.getBelongsToField(
"technologyOperationComponent").getId());
BigDecimal cost = BigDecimalUtils.convertNullToZero(totalMachineOperationCost).add(
BigDecimalUtils.convertNullToZero(totalLaborOperationCost), mathContext);
holder.setLaborCost(numberService.setScale(cost, 2));
}
}
}
public List<ComponentsCalculationHolder> fillAllOperations(final EntityTree operationComponents) {
List<ComponentsCalculationHolder> components = Lists.newArrayList();
for (Entity toc : operationComponents) {
ComponentsCalculationHolder component = new ComponentsCalculationHolder(toc,
toc.getBelongsToField(TechnologyOperationComponentFields.PRODUCT_FROM_STRUCTURE_TREE));
components.add(component);
}
return components;
}
public List<ComponentsCalculationHolder> fillBasicComponents(final EntityTree operationComponents) {
List<ComponentsCalculationHolder> basicComponents = Lists.newArrayList();
Map<Long, Entity> componentsById = operationComponents.stream().collect(Collectors.toMap(x -> x.getId(), x -> x));
List<Entity> tocs = operationComponents.stream()
.filter(pc -> L_COMPONENT.equals(pc.getStringField(TechnologyOperationComponentFields.TYPE_FROM_STRUCTURE_TREE)))
.collect(Collectors.toList());
for (Entity toc : tocs) {
if (toc.getHasManyField(TechnologyOperationComponentFields.OPERATION_PRODUCT_OUT_COMPONENTS).stream()
.filter(op -> op.getBooleanField(OperationProductOutComponentFields.SET)).findAny().isPresent()) {
List<Entity> setOperations = toc.getHasManyField(TechnologyOperationComponentFields.CHILDREN);
for (Entity setOperation : setOperations) {
Entity op = componentsById.get(setOperation.getId());
if (!L_COMPONENT.equals(op.getStringField(TechnologyOperationComponentFields.TYPE_FROM_STRUCTURE_TREE))) {
ComponentsCalculationHolder component = new ComponentsCalculationHolder(op,
op.getBelongsToField(TechnologyOperationComponentFields.PRODUCT_FROM_STRUCTURE_TREE));
basicComponents.add(component);
}
}
} else {
ComponentsCalculationHolder component = new ComponentsCalculationHolder(toc,
toc.getBelongsToField(TechnologyOperationComponentFields.PRODUCT_FROM_STRUCTURE_TREE));
basicComponents.add(component);
}
}
return basicComponents;
}
public void fillBasicComponentsCosts(final EntityTree operationComponents,
final Map<Long, ComponentsCalculationHolder> basicComponentsMap,
final Map<Long, ComponentsCalculationHolder> allOperationsMap, final BigDecimal quantity) {
Map<Long, Entity> entitiesById = new LinkedHashMap<Long, Entity>();
MathContext mathContext = numberService.getMathContext();
for (Entity entity : operationComponents) {
entitiesById.put(entity.getId(), entity);
}
for (Map.Entry<Long, ComponentsCalculationHolder> entry : basicComponentsMap.entrySet()) {
ComponentsCalculationHolder component = entry.getValue();
component.setMaterialCost(allOperationsMap.get(entry.getKey()).getMaterialCost());
component.setLaborCost(allOperationsMap.get(entry.getKey()).getLaborCost());
addChildCost(component, null, allOperationsMap, entitiesById, mathContext);
BigDecimal sumOfCost = BigDecimalUtils.convertNullToZero(component.getLaborCost()).add(
BigDecimalUtils.convertNullToZero(component.getMaterialCost()), mathContext);
BigDecimal costPerUnit = sumOfCost.divide(quantity, mathContext);
component.setSumOfCost(numberService.setScale(sumOfCost, 2));
component.setCostPerUnit(numberService.setScale(costPerUnit, 2));
}
}
private void addChildCost(ComponentsCalculationHolder component, ComponentsCalculationHolder child,
Map<Long, ComponentsCalculationHolder> allOperationsMap, Map<Long, Entity> entitiesById, MathContext mathContext) {
ComponentsCalculationHolder _component = component;
if (child != null) {
BigDecimal materialCost = BigDecimalUtils.convertNullToZero(component.getMaterialCost()).add(
BigDecimalUtils.convertNullToZero(child.getMaterialCost()), mathContext);
BigDecimal laborCost = BigDecimalUtils.convertNullToZero(component.getLaborCost()).add(
BigDecimalUtils.convertNullToZero(child.getLaborCost()), mathContext);
component.setLaborCost(numberService.setScale(laborCost, 2));
component.setMaterialCost(numberService.setScale(materialCost, 2));
_component = child;
}
for (Entity toc : entitiesById.get(_component.getToc().getId()).getHasManyField(
TechnologyOperationComponentFields.CHILDREN)) {
ComponentsCalculationHolder nextChild = allOperationsMap.get(toc.getId());
addChildCost(component, nextChild, allOperationsMap, entitiesById, mathContext);
}
}
}