Java tutorial
/* * MPSProcessorServiceBean.java * * Copyright (c) 1998 - 2004 BusinessTechnology, Ltd. * All rights reserved * * This program is the proprietary and confidential information * of BusinessTechnology, Ltd. and may be used and disclosed only * as authorized in a license agreement authorizing and * controlling such use and disclosure * * Millennium ERP system. * */ package com.mg.merp.planning.support; import com.mg.framework.api.BusinessException; import com.mg.framework.api.math.Constants; import com.mg.framework.api.orm.Order; import com.mg.framework.api.orm.OrmTemplate; import com.mg.framework.api.orm.PersistentManager; import com.mg.framework.api.orm.Restrictions; import com.mg.framework.api.orm.ResultTransformer; import com.mg.framework.service.ApplicationDictionaryLocator; import com.mg.framework.utils.DateTimeUtils; import com.mg.framework.utils.MathUtils; import com.mg.framework.utils.ServerUtils; import com.mg.framework.utils.StringUtils; import com.mg.merp.manufacture.TransactionServiceLocal; import com.mg.merp.manufacture.model.Job; import com.mg.merp.manufacture.model.JobMaterial; import com.mg.merp.manufacture.support.ManufactureUtils; import com.mg.merp.mfreference.BOMServiceLocal; import com.mg.merp.mfreference.BucketRange; import com.mg.merp.mfreference.TimeRange; import com.mg.merp.mfreference.model.Bom; import com.mg.merp.mfreference.model.BomMaterial; import com.mg.merp.mfreference.model.BomRoute; import com.mg.merp.mfreference.model.PlanningLevel; import com.mg.merp.mfreference.model.ScheduleDirection; import com.mg.merp.mfreference.support.MfUtils; import com.mg.merp.planning.CatalogWarehouseServiceLocal; import com.mg.merp.planning.MPSLineServiceLocal; import com.mg.merp.planning.MPSProcessorServiceLocal; import com.mg.merp.planning.MPSServiceLocal; import com.mg.merp.planning.SafetyLevel; import com.mg.merp.planning.model.ForecastMethod; import com.mg.merp.planning.model.ForecastVersion; import com.mg.merp.planning.model.GenericItem; import com.mg.merp.planning.model.InventoryForecast; import com.mg.merp.planning.model.InventoryForecastLine; import com.mg.merp.planning.model.Mps; import com.mg.merp.planning.model.MpsLine; import com.mg.merp.planning.model.PlanningForecast; import com.mg.merp.reference.CurrentStockSituation; import com.mg.merp.reference.CurrentStockSituationLocator; import com.mg.merp.reference.MeasureConversionServiceLocal; import com.mg.merp.reference.StockSituationValues; import com.mg.merp.reference.model.Catalog; import com.mg.merp.reference.model.Measure; import com.mg.merp.warehouse.OrderHeadCusServiceLocal; import com.mg.merp.warehouse.OrderHeadSupServiceLocal; import com.mg.merp.warehouse.model.OrderStatus; import org.apache.commons.lang.builder.HashCodeBuilder; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.ejb.Remove; import javax.ejb.Stateful; /** * ? ?- "?? MPS" * * @author Oleg V. Safonov * @version $Id: MPSProcessorServiceBean.java,v 1.6 2009/03/05 10:51:04 safonov Exp $ */ @Stateful(name = "merp/planning/MPSProcessorService") public class MPSProcessorServiceBean extends com.mg.framework.generic.AbstractPOJOBusinessObjectStatelessServiceBean implements MPSProcessorServiceLocal { private MPSServiceLocal mpsService; private MPSLineServiceLocal mpsLineService; private BOMServiceLocal bomService; private MeasureConversionServiceLocal measureConversionService; private TransactionServiceLocal mfTransactionService; private Mps mps; private OrmTemplate ormTemplate; private List<MpsLine> generatedMPSLines; private int mpsSequence; private PersistentManager pm = ServerUtils.getPersistentManager(); private void clearMPS(Mps mps) { ormTemplate.bulkUpdateByNamedQuery("Planing.MPSProcessor.clearMPS", "mps", mps); } private MeasureConversionServiceLocal getMeasureConversionService() { if (measureConversionService == null) measureConversionService = ((MeasureConversionServiceLocal) ApplicationDictionaryLocator.locate() .getBusinessService(MeasureConversionServiceLocal.LOCAL_SERVICE_NAME)); return measureConversionService; } private TransactionServiceLocal getMfTransactionService() { if (mfTransactionService == null) mfTransactionService = ((TransactionServiceLocal) ApplicationDictionaryLocator.locate() .getBusinessService(TransactionServiceLocal.SERVICE_NAME)); return mfTransactionService; } private PlanningRange calculateMPSPlanningRange(Mps mps) { PlanningRange result = new PlanningRange(); PlanningLevel planningLevel = mps.getPlanningLevel(); //? ? MPS, result.startPlanningDate = mps.getPlanningDate(); result.startBucket = MfUtils.determineBucketOffset(planningLevel.getId(), result.startPlanningDate); //? , ? if (result.startBucket == -1) throw new BusinessException(StringUtils.format( "? ? ? ? dd/mm/yyyy", result.startPlanningDate)); result.endBucket = (short) (result.startBucket + planningLevel.getTimeFence() - 1); BucketRange bucketRange = MfUtils.determineBucketRange(planningLevel.getId(), result.endBucket); result.endPlanningDate = bucketRange.getBucketEnd(); //? , ? if (result.endPlanningDate.getTime() == 0) throw new BusinessException(StringUtils.format( "? ? ? ? %d", result.endBucket)); return result; } private GenericItem findPlanningItem(Catalog catalog) { return ormTemplate.findUniqueByCriteria(OrmTemplate.createCriteria(GenericItem.class) .add(Restrictions.eq("Catalog", catalog)).add(Restrictions.eq("PlanningItemFlag", true))); } private MpsLine initMPSLineItem(Mps mps, GenericItem genericItem, short bucketOffset, int outputMPSSequence) { // ? MPS mpsSequence++; MpsLine result = mpsLineService.initialize(); result.setMps(mps); result.setPlanningItem(genericItem); result.setBucketOffset(bucketOffset); BucketRange bucketRange = MfUtils.determineBucketRange(mps.getPlanningLevel().getId(), bucketOffset); result.setBucketOffsetDate(bucketRange.getBucketStart()); result.setDemandFenceDate(mps.getDemandFenceDate()); result.setMpsSequence(mpsSequence); result.setOutputMpsSequence(outputMPSSequence == 0 ? null : outputMPSSequence); return result; } private MpsLine prepareMPSLine(Mps mps, GenericItem genericItem, short bucketOffset) { return prepareMPSLine(mps, genericItem, bucketOffset, 0); } private MpsLine prepareMPSLine(Mps mps, GenericItem genericItem, short bucketOffset, int outputMPSSequence) { // Collections.sort(generatedMPSLines, new Comparator<MpsLine>() { // // public int compare(MpsLine o1, MpsLine o2) { // return 0; // } // // }); MpsLine findedMPSLine = null; // ?? //TODO ? ? for (MpsLine mpsLine : generatedMPSLines) { if (/*mpsLine.getMps().getId() == mps.getId() && */mpsLine.getPlanningItem().getId() == genericItem.getId() && mpsLine.getBucketOffset() == bucketOffset && (outputMPSSequence == 0 || mpsLine.getOutputMpsSequence() != null && mpsLine.getOutputMpsSequence() == outputMPSSequence)) { findedMPSLine = mpsLine; break; } } // if (findedMPSLine == null) { // Criteria criteria = OrmTemplate.createCriteria(MpsLine.class) // .add(Restrictions.eq("Mps", mps)) // .add(Restrictions.eq("GenericItem", genericItem)) // .add(Restrictions.eq("BucketOffset", bucketOffset)); // if (outputMPSSequence != 0) // criteria.add(Restrictions.eq("OutputMpsSequence", outputMPSSequence)); // findedMPSLine = ormTemplate.findUniqueByCriteria(criteria); // //? ? // if (findedMPSLine == null) { findedMPSLine = initMPSLineItem(mps, genericItem, bucketOffset, outputMPSSequence); // } generatedMPSLines.add(findedMPSLine); } return findedMPSLine; } private List<ProductDemandItem> loadDemandFromOrder(Date planningStartDate, Date planningEndDate, int docSection) { List<ProductDemandItem> fromSpecs = ormTemplate.findByNamedQueryAndNamedParam( "Planing.MPSProcessor.loadDemandFromOrder", new String[] { "docSectionId", "status", "startDate", "endDate" }, new Object[] { docSection, OrderStatus.ORDERED, planningStartDate, planningEndDate }, new ResultTransformer<ProductDemandItem>() { public ProductDemandItem transformTuple(Object[] tuple, String[] aliases) { GenericItem gi = pm.find(GenericItem.class, tuple[0]); Catalog catalog = pm.find(Catalog.class, tuple[1]); Date requiredDate = (Date) tuple[2]; BigDecimal quan = (BigDecimal) tuple[3]; if (gi.getMeasure().getId() != catalog.getMeasure1().getId()) quan = getMeasureConversionService().conversion(catalog.getMeasure1(), gi.getMeasure(), catalog, requiredDate, quan); return new ProductDemandItem(gi, catalog, gi.getMeasure(), requiredDate, quan, (short) 0, null); } }); // List<ProductDemandItem> fromSpecs = ormTemplate.findByCriteria(OrmTemplate.createCriteria(OrderSpec.class, "os") // .createAlias("os.DocHead", "dh") // .setProjection(Projections.projectionList( // Projections.property("os.RequiredDate"), // Projections.property("os.Catalog"), // Projections.property("os.Measure1"), // Projections.sum("os.QtyOutstanding"), // Projections.groupProperty("os.RequiredDate"), // Projections.groupProperty("os.Catalog"), // Projections.groupProperty("os.Measure1"))) // .add(Restrictions.eq("dh.DocSection.Id", docSection)) // .add(Restrictions.eq("dh.Status", OrderStatus.ORDERED)) // .add(Restrictions.eq("os.Status", OrderStatus.ORDERED)) // .add(Restrictions.eq("os.ClosedForPlanning", false)) // .add(Restrictions.between("os.RequiredDate", planningStartDate, planningEndDate)) // .add(Restrictions.gt("os.QtyOutstanding", BigDecimal.ZERO)) // .setResultTransformer(new ResultTransformer<Object>() { // // public Object transformTuple(Object[] tuple, String[] aliases) { // return new ProductDemandItem(null, (Catalog) tuple[1], (Measure) tuple[2], (Date) tuple[0], (BigDecimal) tuple[3], (short) 0, null); // } // // })); // List<ProductDemandItem> result = new ArrayList<ProductDemandItem>(); // for (ProductDemandItem productDemandItem : fromSpecs) { // GenericItem genericItem = findPlanningItem(productDemandItem.catalog); // if (genericItem != null) { // productDemandItem.genericItem = genericItem; // if (genericItem.getMeasure().getId() != productDemandItem.measure.getId()) { // productDemandItem.quan = getMeasureConversionService() // .conversion(productDemandItem.measure, genericItem.getMeasure(), productDemandItem.catalog, productDemandItem.requiredDate, productDemandItem.quan); // // // productDemandItem.measure = genericItem.getMeasure(); // } // result.add(productDemandItem); // } // } return fromSpecs; // ormTemplate.findByCriteria(OrmTemplate.createCriteria(GenericItem.class, "gi") // .createAlias("gi.Catalog", "c") // .createAlias("os.DocHead", "dh") // .add(Restrictions.eq("dh.DocSection.Id", docSection))); } private void processOrders(Date planningStartDate, Date planningEndDate, short docSection) { for (ProductDemandItem productDemandItem : loadDemandFromOrder(planningStartDate, planningEndDate, docSection)) { productDemandItem.bucketOffset = MfUtils.determineBucketOffset(mps.getPlanningLevel().getId(), productDemandItem.requiredDate); BucketRange bucketRange = MfUtils.determineBucketRange(mps.getPlanningLevel().getId(), productDemandItem.bucketOffset); MpsLine mpsLine = prepareMPSLine(mps, productDemandItem.genericItem, productDemandItem.bucketOffset); mpsLine.setBucketOffsetDate(bucketRange.getBucketStart()); mpsLine.setLevelCode(productDemandItem.genericItem.getLowLevelCode()); mpsLine.setMeasure(productDemandItem.measure); switch (docSection) { case OrderHeadCusServiceLocal.DOCSECTION: mpsLine.setSalesOrderQty(mpsLine.getSalesOrderQty().add(productDemandItem.quan)); break; case OrderHeadSupServiceLocal.DOCSECTION: mpsLine.setPurchaseOrderQty(mpsLine.getPurchaseOrderQty().add(productDemandItem.quan)); break; default: throw new IllegalArgumentException("Invalid document section"); } mpsLine.updateDemandQuantities(); } } // private List<ProductDemandItem> prepareProductDemands(List<ProductDemandItem> productDemands) { // List<ProductDemandItem> result = new ArrayList<ProductDemandItem>(); // for (ProductDemandItem productDemandItem : productDemands) { // GenericItem genericItem = findPlanningItem(productDemandItem.catalog); // if (genericItem != null) { // productDemandItem.genericItem = genericItem; // if (genericItem.getMeasure().getId() != productDemandItem.measure.getId()) { // productDemandItem.quan = getMeasureConversionService() // .conversion(productDemandItem.measure, genericItem.getMeasure(), productDemandItem.catalog, productDemandItem.requiredDate, productDemandItem.quan); // // // productDemandItem.measure = genericItem.getMeasure(); // } // result.add(productDemandItem); // } // } // return result; // } /** * , .. ?? ? * . */ private boolean checkDemandFenceDate(ForecastMethod forecastMethod, Date requiredDate, short demandFenceDays, short bucketOffset) { Date fenceDate = DateTimeUtils.incDay(mps.getDemandFenceDate(), demandFenceDays); switch (forecastMethod) { case BY_PERIOD: short pdfBucketOffset = MfUtils.determineBucketOffset(mps.getPlanningLevel().getId(), fenceDate); if (pdfBucketOffset != -1 && bucketOffset >= pdfBucketOffset) return true; break; case BY_DATE: if (requiredDate.compareTo(fenceDate) >= 0) return true; break; } return false; } private List<ProductDemandItem> loadDemandFromSalesForecast(PlanningRange planningRange) { // List<ProductDemandItem> fromForecast = ormTemplate.findByCriteria(OrmTemplate.createCriteria(PlanningForecast.class, "pf") // .setProjection(Projections.projectionList( // Projections.property("pf.RequiredDate"), // Projections.property("pf.Catalog"), // Projections.property("pf.Measure"), // Projections.property("pf.ForecastMethod"), // Projections.sum("pf.ForecastQuantity"))) // .add(Restrictions.eq("pf.PlanningLevel", mps.getPlanningLevel())) // .add(Restrictions.eq("pf.ForecastType", ForecastType.SALE)) // .add(Restrictions.or( // Restrictions.and( // Restrictions.eq("pf.ForecastMethod", ForecastMethod.BY_DATE), // Restrictions.between("pf.RequiredDate", planningRange.startPlanningDate, planningRange.endPlanningDate)), // Restrictions.and( // Restrictions.eq("pf.ForecastMethod", ForecastMethod.BY_PERIOD), // Restrictions.between("pf.BucketOffset", planningRange.startBucket, planningRange.endBucket)))) // .add(Restrictions.gt("pf.ForecastQuantity", BigDecimal.ZERO)) // .add(Restrictions.eq("pf.ForecastVersion", mps.getForecastVersion())) // .setResultTransformer(new ResultTransformer<ProductDemandItem>() { // // public ProductDemandItem transformTuple(Object[] tuple, String[] aliases) { // //return new ProductDemandItem(); // return null; // } // // })); // fromForecast = prepareProductDemands(fromForecast); // ? ?? (CATALOG_ID is not null) List<ProductDemandItem> fromForecast = ormTemplate.findByNamedQueryAndNamedParam( "Planing.MPSProcessor.loadDemandFromSalesForecastByCatalog", new String[] { "planningLevel", "startDate", "endDate", "startBucket", "endBucket", "forecastVersion" }, new Object[] { mps.getPlanningLevel(), planningRange.startPlanningDate, planningRange.endPlanningDate, planningRange.startBucket, planningRange.endBucket, mps.getForecastVersion() }, new ResultTransformer<ProductDemandItem>() { public ProductDemandItem transformTuple(Object[] tuple, String[] aliases) { GenericItem gi = pm.find(GenericItem.class, tuple[0]); PlanningForecast pf = pm.find(PlanningForecast.class, tuple[1]); Date requiredDate = pf.getRequiredDate(); BigDecimal quan = (BigDecimal) tuple[2]; if (!checkDemandFenceDate(pf.getForecastMethod(), requiredDate, gi.getDemandFenceDays(), pf.getBucketOffset())) return null; if (gi.getMeasure().getId() != pf.getMeasure().getId()) quan = getMeasureConversionService().conversion(pf.getMeasure(), gi.getMeasure(), gi.getCatalog(), requiredDate, quan); return new ProductDemandItem(gi, gi.getCatalog(), gi.getMeasure(), requiredDate, quan, pf.getBucketOffset(), pf.getForecastVersion()); } }); // ? ?? (PLANNING_ITEM_ID is not null) //TODO ??? (planning_item_flag = 1), // ? , } fromForecast.addAll(ormTemplate.findByNamedQueryAndNamedParam( "Planing.MPSProcessor.loadDemandFromSalesForecastByGenericItem", new String[] { "planningLevel", "startDate", "endDate", "startBucket", "endBucket", "forecastVersion" }, new Object[] { mps.getPlanningLevel(), planningRange.startPlanningDate, planningRange.endPlanningDate, planningRange.startBucket, planningRange.endBucket, mps.getForecastVersion() }, new ResultTransformer<ProductDemandItem>() { public ProductDemandItem transformTuple(Object[] tuple, String[] aliases) { PlanningForecast pf = pm.find(PlanningForecast.class, tuple[0]); GenericItem gi = pf.getPlanningItem(); Date requiredDate = pf.getRequiredDate(); BigDecimal quan = (BigDecimal) tuple[1]; if (!checkDemandFenceDate(pf.getForecastMethod(), requiredDate, gi.getDemandFenceDays(), pf.getBucketOffset())) return null; if (gi.getMeasure().getId() != pf.getMeasure().getId()) quan = getMeasureConversionService().conversion(pf.getMeasure(), gi.getMeasure(), gi.getCatalog(), requiredDate, quan); return new ProductDemandItem(gi, gi.getCatalog(), gi.getMeasure(), requiredDate, quan, pf.getBucketOffset(), pf.getForecastVersion()); } })); //? ? ?, ? List<ProductDemandItem> result = new ArrayList<ProductDemandItem>(); for (ProductDemandItem productDemandItem : fromForecast) if (productDemandItem != null) result.add(productDemandItem); return result; } private void processSalesForecasts(PlanningRange planningRange) { for (ProductDemandItem productDemandItem : loadDemandFromSalesForecast(planningRange)) { if (productDemandItem.bucketOffset == 0) productDemandItem.bucketOffset = MfUtils.determineBucketOffset(mps.getPlanningLevel().getId(), productDemandItem.requiredDate); BucketRange bucketRange = MfUtils.determineBucketRange(mps.getPlanningLevel().getId(), productDemandItem.bucketOffset); MpsLine mpsLine = prepareMPSLine(mps, productDemandItem.genericItem, productDemandItem.bucketOffset); mpsLine.setBucketOffsetDate(bucketRange.getBucketStart()); mpsLine.setLevelCode(productDemandItem.genericItem.getLowLevelCode()); mpsLine.setMeasure(productDemandItem.measure); mpsLine.setSalesForecastQty(mpsLine.getSalesForecastQty().add(productDemandItem.quan)); mpsLine.setForecastVersion(productDemandItem.forecastVersion); mpsLine.updateDemandQuantities(); } } private List<ProductDemandItem> loadCurrentQuantityOnHandFromWarehouse(Date planningStartDate) { List<GenericItem> giList = ormTemplate.findByCriteria( OrmTemplate.createCriteria(GenericItem.class).add(Restrictions.eq("PlanningItemFlag", true))); List<ProductDemandItem> result = new ArrayList<ProductDemandItem>(); CurrentStockSituation currentStockSituation = CurrentStockSituationLocator.locate(); for (GenericItem genericItem : giList) { BigDecimal quan = BigDecimal.ZERO; List<StockSituationValues> stockSituationValuesList = currentStockSituation .getSituation(genericItem.getCatalog()); if (stockSituationValuesList == null) continue; for (StockSituationValues stockSituationValues : stockSituationValuesList) quan = quan.add(stockSituationValues.getLocated1()); if (genericItem.getMeasure().getId() != genericItem.getCatalog().getMeasure1().getId()) quan = getMeasureConversionService().conversion(genericItem.getCatalog().getMeasure1(), genericItem.getMeasure(), genericItem.getCatalog(), planningStartDate, quan); result.add(new ProductDemandItem(genericItem, genericItem.getCatalog(), genericItem.getMeasure(), planningStartDate, quan, (short) 0, null)); } return result; } private void processCurrentQuantityOnHand(Date planningStartDate, short startBucket) { for (ProductDemandItem productDemandItem : loadCurrentQuantityOnHandFromWarehouse(planningStartDate)) { MpsLine mpsLine = prepareMPSLine(mps, productDemandItem.genericItem, startBucket); mpsLine.setLevelCode(productDemandItem.genericItem.getLowLevelCode()); mpsLine.setMeasure(productDemandItem.genericItem.getMeasure()); mpsLine.setQtyAvailable(mpsLine.getQtyAvailable().add(productDemandItem.quan)); } } private List<ProductDemandItem> loadProductionOutputs(Date planningStartDate, Date planningEndDate) { return ormTemplate.findByNamedQueryAndNamedParam("Planing.MPSProcessor.loadProductionOutputs", new String[] { "startDate", "endDate" }, new Object[] { planningStartDate, planningEndDate }, new ResultTransformer<ProductDemandItem>() { public ProductDemandItem transformTuple(Object[] tuple, String[] aliases) { Job job = pm.find(Job.class, tuple[0]); GenericItem gi = pm.find(GenericItem.class, tuple[1]); BigDecimal quan = (BigDecimal) tuple[2]; Date requiredDate = job.getEndDate(); if (gi.getMeasure().getId() != gi.getCatalog().getMeasure1().getId()) quan = getMeasureConversionService().conversion(gi.getCatalog().getMeasure1(), gi.getMeasure(), gi.getCatalog(), requiredDate, quan); return new ProductDemandItem(gi, gi.getCatalog(), gi.getMeasure(), requiredDate, quan, (short) 0, null); } }); } private void processLiveProductionOutputs(Date planningStartDate, Date planningEndDate) { for (ProductDemandItem productDemandItem : loadProductionOutputs(planningStartDate, planningEndDate)) { productDemandItem.bucketOffset = MfUtils.determineBucketOffset(mps.getPlanningLevel().getId(), productDemandItem.requiredDate); BucketRange bucketRange = MfUtils.determineBucketRange(mps.getPlanningLevel().getId(), productDemandItem.bucketOffset); MpsLine mpsLine = prepareMPSLine(mps, productDemandItem.genericItem, productDemandItem.bucketOffset); mpsLine.setBucketOffsetDate(bucketRange.getBucketStart()); mpsLine.setLevelCode(productDemandItem.genericItem.getLowLevelCode()); mpsLine.setMeasure(productDemandItem.measure); mpsLine.setProductionQty(mpsLine.getProductionQty().add(productDemandItem.quan)); } } private List<ProductDemandItem> loadProductionInputs(Date planningStartDate, Date planningEndDate) { return ormTemplate.findByNamedQueryAndNamedParam("Planing.MPSProcessor.loadProductionInputs", new String[] { "startDate", "endDate" }, new Object[] { planningStartDate, planningEndDate }, new ResultTransformer<ProductDemandItem>() { public ProductDemandItem transformTuple(Object[] tuple, String[] aliases) { JobMaterial jm = pm.find(JobMaterial.class, tuple[0]); GenericItem gi = pm.find(GenericItem.class, tuple[1]); BigDecimal quan = ManufactureUtils.calculateJobMaterialQuan(jm) .divide((BigDecimal) tuple[2]) .subtract(getMfTransactionService().getQuantityByResource(jm.getId())); Date requiredDate = jm.getOper().getJob().getStartDate(); if (gi.getMeasure().getId() != jm.getMeasure().getId()) quan = getMeasureConversionService().conversion(jm.getMeasure(), gi.getMeasure(), gi.getCatalog(), requiredDate, quan); return new ProductDemandItem(gi, gi.getCatalog(), gi.getMeasure(), requiredDate, quan, (short) 0, null); } }); } private void processLiveProductionInputs(Date planningStartDate, Date planningEndDate) { for (ProductDemandItem productDemandItem : loadProductionInputs(planningStartDate, planningEndDate)) { productDemandItem.bucketOffset = MfUtils.determineBucketOffset(mps.getPlanningLevel().getId(), productDemandItem.requiredDate); BucketRange bucketRange = MfUtils.determineBucketRange(mps.getPlanningLevel().getId(), productDemandItem.bucketOffset); MpsLine mpsLine = prepareMPSLine(mps, productDemandItem.genericItem, productDemandItem.bucketOffset); mpsLine.setBucketOffsetDate(bucketRange.getBucketStart()); mpsLine.setLevelCode(productDemandItem.genericItem.getLowLevelCode()); mpsLine.setMeasure(productDemandItem.measure); mpsLine.setLiveProductionDemand(mpsLine.getLiveProductionDemand().add(productDemandItem.quan)); } } private List<ProductDemandItem> loadQOHForecasts(final Date planningStartDate, Date planningEndDate, InventoryForecast inventoryForecast) { return ormTemplate.findByCriteria( OrmTemplate.createCriteria(InventoryForecastLine.class, "ifl").createAlias("ifl.GenericItem", "gi") .add(Restrictions.eq("ifl.InventoryForecast", inventoryForecast)) .add(Restrictions.le("ifl.EffOnDate", planningStartDate)) .add(Restrictions.ge("ifl.EffOffDate", planningEndDate)) .add(Restrictions.eq("gi.PlanningItemFlag", true)) .setResultTransformer(new ResultTransformer<ProductDemandItem>() { public ProductDemandItem transformTuple(Object[] tuple, String[] aliases) { InventoryForecastLine ifl = (InventoryForecastLine) tuple[0]; GenericItem gi = ifl.getGenericItem(); BigDecimal quan = ifl.getQtyOnHand(); if (ifl.getMeasure().getId() != gi.getMeasure().getId()) quan = getMeasureConversionService().conversion(ifl.getMeasure(), gi.getMeasure(), gi.getCatalog(), planningStartDate, quan); return new ProductDemandItem(gi, gi.getCatalog(), gi.getMeasure(), null, quan, (short) 0, null); } })); } private void processQOHForecasts(Date planningStartDate, Date planningEndDate, InventoryForecast inventoryForecast) { for (ProductDemandItem productDemandItem : loadQOHForecasts(planningStartDate, planningEndDate, inventoryForecast)) { productDemandItem.bucketOffset = MfUtils.determineBucketOffset(mps.getPlanningLevel().getId(), planningStartDate); BucketRange bucketRange = MfUtils.determineBucketRange(mps.getPlanningLevel().getId(), productDemandItem.bucketOffset); int generatedCount = generatedMPSLines.size(); MpsLine mpsLine = prepareMPSLine(mps, productDemandItem.genericItem, productDemandItem.bucketOffset); // if (generatedCount == generatedMPSLines.size()) mpsLine.setQtyAvailable(mpsLine.getQtyAvailable().add(productDemandItem.quan)); else { mpsLine.setInventoryForecast(inventoryForecast); mpsLine.setBucketOffsetDate(bucketRange.getBucketStart()); mpsLine.setLevelCode(productDemandItem.genericItem.getLowLevelCode()); mpsLine.setMeasure(productDemandItem.measure); mpsLine.setQtyAvailable(productDemandItem.quan); } } } private void processSafetyLevel(Date planningStartDate, short startBucket) { CatalogWarehouseServiceLocal catalogWarehouseService = (CatalogWarehouseServiceLocal) ApplicationDictionaryLocator .locate().getBusinessService(CatalogWarehouseServiceLocal.SERVICE_NAME); for (SafetyLevel safetyLevel : catalogWarehouseService.getSafetyLevel()) { // ? if (safetyLevel.getGenericItem() == null || !safetyLevel.getGenericItem().getPlanningItemFlag()) continue; int lineCount = generatedMPSLines.size(); MpsLine mpsLine = prepareMPSLine(mps, safetyLevel.getGenericItem(), startBucket); // ?? ? ? ? ?? ? if (lineCount != generatedMPSLines.size()) { mpsLine.setBucketOffsetDate(planningStartDate); mpsLine.setLevelCode(safetyLevel.getGenericItem().getLowLevelCode()); mpsLine.setMeasure(safetyLevel.getGenericItem().getMeasure()); } BigDecimal quan = safetyLevel.getQuantity(); if (safetyLevel.getCatalog().getMeasure1().getId() != safetyLevel.getGenericItem().getMeasure().getId()) quan = getMeasureConversionService().conversion(safetyLevel.getCatalog().getMeasure1(), safetyLevel.getGenericItem().getMeasure(), safetyLevel.getCatalog(), planningStartDate, quan); mpsLine.setSafetyLevelQty(quan); } } private void processDependantDemand(short lowLevelCode) { Map<ProductionDemandKey, ProductionDemandEntry> productionDemand = new HashMap<ProductionDemandKey, ProductionDemandEntry>(); // BucketOffset, PlanningItem, Measure. ?? ? ? for (MpsLine mpsLine : generatedMPSLines) { if (MathUtils.compareToZero(mpsLine.getProductionDemandQty()) > 0 && mpsLine.getLevelCode() == lowLevelCode) { ProductionDemandKey key = new ProductionDemandKey(mpsLine.getBucketOffset(), mpsLine.getPlanningItem().getId(), mpsLine.getMeasure().getId()); ProductionDemandEntry entry = productionDemand.get(key); if (entry == null) productionDemand.put(key, new ProductionDemandEntry(mpsLine.getProductionDemandQty(), mpsLine)); else entry.productionDemandQty.add(mpsLine.getProductionDemandQty()); } } for (ProductionDemandEntry entry : productionDemand.values()) { MpsLine findedMPSLine = null; for (MpsLine mpsLine : generatedMPSLines) { if (MathUtils.compareToZero(mpsLine.getProductionDemandQty()) <= 0 && mpsLine.getPlanningItem().getId() == entry.mpsLine.getPlanningItem().getId() && mpsLine.getBucketOffset() == entry.mpsLine.getBucketOffset()) { findedMPSLine = mpsLine; break; } } if (findedMPSLine == null) { findedMPSLine = initMPSLineItem(mps, entry.mpsLine.getPlanningItem(), entry.mpsLine.getBucketOffset(), 0); findedMPSLine.setMeasure(entry.mpsLine.getPlanningItem().getMeasure()); findedMPSLine.setLevelCode(lowLevelCode); generatedMPSLines.add(findedMPSLine); } findedMPSLine.setDependantDemand(findedMPSLine.getDependantDemand().add(entry.productionDemandQty)); } } private void calculateProductionPlan(short lowLevelCode) { //? PlanningItem, BucketOffset desc Collections.sort(generatedMPSLines, new Comparator<MpsLine>() { public int compare(MpsLine o1, MpsLine o2) { if (o1.getPlanningItem().getId() < o2.getPlanningItem().getId()) return 1; else if (o1.getPlanningItem().getId() > o2.getPlanningItem().getId()) return -1; else { if (o1.getBucketOffset() < o2.getBucketOffset()) return 1; else if (o1.getBucketOffset() > o2.getBucketOffset()) return -1; else return 0; } } }); BigDecimal availableOnBeginBucket = BigDecimal.ZERO; GenericItem currentPlanningItem = null; for (MpsLine mpsLine : generatedMPSLines) { if (MathUtils.compareToZero(mpsLine.getProductionDemandQty()) <= 0 && mpsLine.getLevelCode() == lowLevelCode) { if (currentPlanningItem == null || currentPlanningItem.getId() != mpsLine.getPlanningItem().getId()) { currentPlanningItem = mpsLine.getPlanningItem(); availableOnBeginBucket = BigDecimal.ZERO; } BigDecimal plannedQty = mpsLine.calculatePlannedQuantity(availableOnBeginBucket); Bom bom = bomService.findCurrentBOM(currentPlanningItem.getCatalog().getId()); if (bom != null) { BigDecimal MaxQty = bom.getMaxLotQty(), MinQty = bom.getMinLotQty(), Increment = bom.getLotIncrementQty(), Remainder, RemInc; if (!(MathUtils.compareToZeroOrNull(MaxQty) == 0 || MathUtils.compareToZeroOrNull(MinQty) == 0 || MathUtils.compareToZeroOrNull(Increment) == 0)) { //? ? ? if (bom.getCatalog().getMeasure1().getId() != mpsLine.getMeasure().getId()) { MaxQty = getMeasureConversionService().conversion(bom.getCatalog().getMeasure1(), mpsLine.getMeasure(), bom.getCatalog(), mpsLine.getBucketOffsetDate(), MaxQty); MinQty = getMeasureConversionService().conversion(bom.getCatalog().getMeasure1(), mpsLine.getMeasure(), bom.getCatalog(), mpsLine.getBucketOffsetDate(), MinQty); Increment = getMeasureConversionService().conversion(bom.getCatalog().getMeasure1(), mpsLine.getMeasure(), bom.getCatalog(), mpsLine.getBucketOffsetDate(), Increment); } long NumOfMax = plannedQty.divide(MaxQty).longValue(); Remainder = plannedQty.subtract(MaxQty.multiply(new BigDecimal(NumOfMax))); plannedQty = MaxQty.multiply(new BigDecimal(NumOfMax)); if (MathUtils.compareToZero(Remainder) != 0) { if (Remainder.compareTo(MinQty) == -1) plannedQty = plannedQty.add(MinQty); else { long NumOfInc = Remainder.subtract(MinQty).divide(Increment).longValue(); RemInc = Remainder.subtract(MinQty) .subtract(Increment.multiply(new BigDecimal(NumOfInc))); if (MathUtils.compareToZero(RemInc) != 0) plannedQty = plannedQty.add(MinQty) .add(Increment.multiply(new BigDecimal(NumOfInc))).add(Increment); else plannedQty = plannedQty.add(Remainder); } } } } availableOnBeginBucket = mpsLine.calculateAvailableQuantityOnEndBucket(plannedQty, availableOnBeginBucket); if (MathUtils.compareToZero(plannedQty) < 0) plannedQty = BigDecimal.ZERO; mpsLine.setPlannedQty(plannedQty); } } } private long mpsMaterialBreakdown(Bom bom, MpsLine mpsLine, long numberOfJobs, BigDecimal lotQty, long requiredDate) { long reqDate = requiredDate; List<BomRoute> routeList = ormTemplate .findByCriteria(OrmTemplate.createCriteria(BomRoute.class).add(Restrictions.eq("Bom", bom)) .add(Restrictions.le("EffOnDate", MfUtils.tickToDate(requiredDate))) .add(Restrictions.ge("EffOffDate", MfUtils.tickToDate(requiredDate))) .addOrder(Order.desc("OperNum"))); // for (BomRoute bomRoute : routeList) { //?? ? ? long timeOper = numberOfJobs * bomRoute.getSetupTicks() + lotQty.longValue() * numberOfJobs * bomRoute.getRunTicks(); //? ? ? TimeRange timeRange = MfUtils.getTimes(mps.getWeekCal().getId(), reqDate, timeOper, ScheduleDirection.BACKWARD); long operStartDate = timeRange.getStartDateTime(); List<BomMaterial> materialList = ormTemplate.findByCriteria( OrmTemplate.createCriteria(BomMaterial.class).add(Restrictions.eq("BomRoute", bomRoute)) .add(Restrictions.le("EffOnDate", MfUtils.tickToDate(operStartDate))) .add(Restrictions.ge("EffOffDate", MfUtils.tickToDate(operStartDate)))); for (BomMaterial bomMaterial : materialList) { GenericItem planningItem = findPlanningItem(bomMaterial.getCatalog()); if (planningItem == null) continue; BigDecimal MaterialQty = lotQty.multiply(new BigDecimal(numberOfJobs)) .multiply(MfUtils.calculateBOMMaterialQuan(bomMaterial, MfUtils.tickToDate(requiredDate), bom.getPlanningLotQty())); short bucketOffset = MfUtils.determineBucketOffset(mps.getPlanningLevel().getId(), MfUtils.tickToDate(operStartDate)); if (bucketOffset == -1) throw new BusinessException( "? ? ? ? dd/mm/yyyy"); BucketRange bucketRange = MfUtils.determineBucketRange(mps.getPlanningLevel().getId(), bucketOffset); MpsLine mpsl = prepareMPSLine(mps, planningItem, bucketOffset, mpsLine.getMpsSequence()); mpsl.setBucketOffset(bucketOffset); mpsl.setBucketOffsetDate(bucketRange.getBucketStart()); mpsl.setLevelCode(planningItem.getLowLevelCode()); if (bomMaterial.getMeasure().getId() != planningItem.getMeasure().getId()) MaterialQty = getMeasureConversionService().conversion(bomMaterial.getMeasure(), planningItem.getMeasure(), planningItem.getCatalog(), bucketRange.getBucketStart(), MaterialQty); mpsl.setProductionDemandQty(mpsl.getProductionDemandQty().add(MaterialQty)); mpsl.setMeasure(planningItem.getMeasure()); } timeRange = MfUtils.getTimes(mps.getWeekCal().getId(), operStartDate, bomRoute.getMoveTicks() * numberOfJobs, ScheduleDirection.BACKWARD); reqDate = timeRange.getStartDateTime();// ? ? } return reqDate; } private void calculateDependantDemand(short lowLevelCode) { for (MpsLine mpsLine : new ArrayList<MpsLine>(generatedMPSLines)) { // ? , .. ? ? ?? generatedMPSLines if (mpsLine.getLevelCode() == lowLevelCode && MathUtils.compareToZero(mpsLine.getPlannedQty()) > 0) { BucketRange bucketRange = MfUtils.determineBucketRange(mps.getPlanningLevel().getId(), mpsLine.getBucketOffset()); BigDecimal PlannedQty = mpsLine.getPlannedQty(), MaxLotQty, Remainder, OddJobSize; PlannedQty = getMeasureConversionService().conversion(mpsLine.getMeasure(), mpsLine.getPlanningItem().getCatalog().getMeasure1(), mpsLine.getPlanningItem().getCatalog(), bucketRange.getBucketStart(), PlannedQty); Bom bom = bomService.findCurrentBOM(mpsLine.getPlanningItem().getCatalog().getId()); if (bom == null) continue; MaxLotQty = bom.getMaxLotQty(); if (MathUtils.compareToZero(MaxLotQty) == 0) MaxLotQty = PlannedQty; //Infinite maximum size long NumberOfMaxJobs = PlannedQty.divide(MaxLotQty).longValue(); Remainder = PlannedQty.subtract(MaxLotQty.multiply(new BigDecimal(NumberOfMaxJobs))); OddJobSize = Remainder; long CurrentRequiredDate = MfUtils.dateToTick(DateTimeUtils.incDay(bucketRange.getBucketEnd(), 1)) - 1000; // ? mpsMaterialBreakdown(bom, mpsLine, 1, MaxLotQty.multiply(new BigDecimal(NumberOfMaxJobs)).add(OddJobSize), CurrentRequiredDate); } } } private void persistGeneratedMPSLines() { PersistentManager pm = ServerUtils.getPersistentManager(); for (MpsLine mpsLine : generatedMPSLines) { if (!mpsLine.isEmpty()) { if (pm.contains(mpsLine)) pm.merge(mpsLine); else pm.persist(mpsLine); } } } private RollUpMPSResult rollUpMPS(Mps mpsDst, MpsLine srcMpsLine, BigDecimal quan, Date countDay, int mpsSequence) { BigDecimal roundedQty = quan; if (srcMpsLine.getPlanningItem().getCatalog() != null) { Bom bom = bomService.findCurrentBOM(srcMpsLine.getPlanningItem().getCatalog().getId()); if (bom != null) { BigDecimal maxQty = bom.getMaxLotQty(); BigDecimal minQty = bom.getMinLotQty(); BigDecimal increment = bom.getLotIncrementQty(); if (!(MathUtils.compareToZeroOrNull(maxQty) == 0 || MathUtils.compareToZeroOrNull(minQty) == 0 || MathUtils.compareToZeroOrNull(increment) == 0)) { if (bom.getCatalog().getMeasure1().getId() != srcMpsLine.getPlanningItem().getMeasure() .getId()) { maxQty = getMeasureConversionService().conversion(bom.getCatalog().getMeasure1(), srcMpsLine.getPlanningItem().getMeasure(), bom.getCatalog(), srcMpsLine.getBucketOffsetDate(), maxQty); minQty = getMeasureConversionService().conversion(bom.getCatalog().getMeasure1(), srcMpsLine.getPlanningItem().getMeasure(), bom.getCatalog(), srcMpsLine.getBucketOffsetDate(), minQty); increment = getMeasureConversionService().conversion(bom.getCatalog().getMeasure1(), srcMpsLine.getPlanningItem().getMeasure(), bom.getCatalog(), srcMpsLine.getBucketOffsetDate(), increment); } long numOfMax = roundedQty.divide(maxQty).longValue(); roundedQty = maxQty.multiply(new BigDecimal(numOfMax)); BigDecimal remainder = roundedQty.add(roundedQty); if (MathUtils.compareToZero(remainder) != 0) { if (remainder.compareTo(minQty) < 0) { roundedQty = roundedQty.add(minQty); } else { long numOfInc = remainder.subtract(minQty).divide(increment).longValue(); BigDecimal remInc = remainder.subtract(minQty) .subtract(increment.multiply(new BigDecimal(numOfInc))); if (MathUtils.compareToZero(remInc) != 0) roundedQty = roundedQty.add(minQty) .add(increment.multiply(new BigDecimal(numOfInc))).add(increment); else roundedQty = roundedQty.add(remainder); } } } } } short bucket = MfUtils.determineBucketOffset(mpsDst.getPlanningLevel().getId(), countDay); MpsLine mpsLine = null; for (MpsLine line : generatedMPSLines) { if (MathUtils.compareToZero(line.getProductionDemandQty()) <= 0 && line.getPlanningItem().getId() == srcMpsLine.getPlanningItem().getId() && line.getBucketOffset() == bucket) { mpsLine = line; break; } } if (mpsLine == null) { mpsLine = mpsLineService.initialize(); mpsLine.setPlanningItem(srcMpsLine.getPlanningItem()); mpsLine.setLevelCode(srcMpsLine.getPlanningItem().getLowLevelCode()); mpsLine.setMps(mpsDst); mpsLine.setBucketOffset(bucket); BucketRange bucketRange = MfUtils.determineBucketRange(mpsDst.getPlanningLevel().getId(), bucket); mpsLine.setBucketOffsetDate(bucketRange.getBucketStart()); mpsLine.setDemandFenceDate(srcMpsLine.getDemandFenceDate()); mpsLine.setMpsSequence(mpsSequence); mpsLine.setOutputMpsSequence(null); mpsLine.setMeasure(srcMpsLine.getMeasure()); mpsLine.setPlannedQty(roundedQty); generatedMPSLines.add(mpsLine); // ? MPS return new RollUpMPSResult(roundedQty, mpsSequence + 1); } else { mpsLine.setPlannedQty(mpsLine.getPlannedQty().add(roundedQty)); return new RollUpMPSResult(roundedQty, mpsSequence); } } protected void internalMpsLevelTransfer(int mpsSrcId, int mpsDstId) { generatedMPSLines = new ArrayList<MpsLine>(); Mps mpsSrc = mpsService.load(mpsSrcId); Mps mpsDst = mpsService.load(mpsDstId); PlanningRange planningRange = calculateMPSPlanningRange(mpsDst); clearMPS(mpsDst); List<MpsLine> lines = ormTemplate .findByCriteria(OrmTemplate.createCriteria(MpsLine.class).add(Restrictions.eq("Mps", mpsSrc)) .add(Restrictions.or(Restrictions.gt("PlannedQty", BigDecimal.ZERO), Restrictions.gt("AdjustmentQty", BigDecimal.ZERO))) .addOrder(Order.asc("BucketOffset"))); BucketRange bucketRange = null; int mpsDstSequence = 1; boolean firstLine = true; long numberOfDays = 1; int currentBucketOffset = 1; for (MpsLine mpsLine : lines) { //? ? ? ? if- if (firstLine || currentBucketOffset != mpsLine.getBucketOffset()) { bucketRange = MfUtils.determineBucketRange(mpsSrc.getPlanningLevel().getId(), mpsLine.getBucketOffset()); //NumberOfDays = EndDay - StartDay + 1 numberOfDays = DateTimeUtils.getDaysBetween(bucketRange.getBucketStart(), bucketRange.getBucketEnd()) + 1; currentBucketOffset = mpsLine.getBucketOffset(); firstLine = false; } BigDecimal remainingQty = mpsLine.getPlannedQty().add(mpsLine.getAdjustmentQty()); // if PlanStartDay <= EndDay and PlanEndDay >= StartDay then // , ? ? ? int c1 = planningRange.startPlanningDate.compareTo(bucketRange.getBucketEnd()); int c2 = planningRange.endPlanningDate.compareTo(bucketRange.getBucketStart()); if (c1 <= 0 && c2 >= 0) { long remainingNumberOfDays = numberOfDays; //PlanStartDay > StartDay if (planningRange.startPlanningDate.compareTo(bucketRange.getBucketStart()) > 0) remainingNumberOfDays = numberOfDays - DateTimeUtils .getDaysBetween(planningRange.startPlanningDate, bucketRange.getBucketStart()); BigDecimal srcQty = MathUtils.divide(remainingQty, new BigDecimal(remainingNumberOfDays), Constants.QUANTITY_ROUND_CONTEXT); Date countDay = bucketRange.getBucketStart(); //while CountDay <= EndDay while (MathUtils.compareToZero(remainingQty) > 0 && countDay.compareTo(bucketRange.getBucketEnd()) <= 0) { //if CountDay >= PlanStartDay and CountDay <= PlanEndDay then if (countDay.compareTo(planningRange.startPlanningDate) >= 0 && countDay.compareTo(planningRange.endPlanningDate) <= 0) { RollUpMPSResult rollUpMPSResult = rollUpMPS(mpsDst, mpsLine, srcQty, countDay, mpsDstSequence); mpsDstSequence = rollUpMPSResult.mpsSequence; // ? remainingNumberOfDays -= 1; remainingQty = remainingQty.subtract(rollUpMPSResult.quan); if (remainingNumberOfDays > 0) srcQty = MathUtils.divide(remainingQty, new BigDecimal(remainingNumberOfDays), Constants.QUANTITY_ROUND_CONTEXT); } countDay = DateTimeUtils.incDay(countDay, 1); } } } persistGeneratedMPSLines(); } protected void internalGenerateMps() { generatedMPSLines = new ArrayList<MpsLine>(); mpsSequence = 0; //? ? PlanningRange planningRange = calculateMPSPlanningRange(mps); // if (mps.getSalesLive()) processOrders(planningRange.startPlanningDate, planningRange.endPlanningDate, OrderHeadCusServiceLocal.DOCSECTION); // if (mps.getSalesForecasts()) processSalesForecasts(planningRange); // ? if (mps.getPurchasesLive()) processOrders(planningRange.startPlanningDate, planningRange.endPlanningDate, OrderHeadSupServiceLocal.DOCSECTION); // ?? ? if (mps.getQtyOnHand()) processCurrentQuantityOnHand(planningRange.startPlanningDate, planningRange.startBucket); // ? ? if (mps.getProduction()) { processLiveProductionOutputs(planningRange.startPlanningDate, planningRange.endPlanningDate); processLiveProductionInputs(planningRange.startPlanningDate, planningRange.endPlanningDate); } // ? ? ?? if (mps.getInventoryForecast() != null) processQOHForecasts(planningRange.startPlanningDate, planningRange.endPlanningDate, mps.getInventoryForecast()); // ? ? processSafetyLevel(planningRange.startPlanningDate, planningRange.startBucket); // LLC short lowLevelCode = 1; while (lowLevelCode <= mps.getLevelProcessedTo()) { if (lowLevelCode > 1) processDependantDemand(lowLevelCode); calculateProductionPlan(lowLevelCode); calculateDependantDemand(lowLevelCode); lowLevelCode++; } //? ? ? persistGeneratedMPSLines(); // ? MPS mps.setLastRunDateTime(DateTimeUtils.nowDate()); mps.setMpsVersion(mps.getMpsVersion() + 1); mpsService.store(mps); } /* (non-Javadoc) * @see com.mg.merp.planning.MPSProcessorServiceLocal#generateMps(int) */ @Remove public void generateMps(int mpsId) { ServerUtils.setTransactionTimeout(86400);//? ? ? MPS, ? ? ormTemplate = OrmTemplate.getInstance(); mpsService = (MPSServiceLocal) ApplicationDictionaryLocator.locate() .getBusinessService(MPSServiceLocal.SERVICE_NAME); mpsLineService = (MPSLineServiceLocal) ApplicationDictionaryLocator.locate() .getBusinessService(MPSLineServiceLocal.SERVICE_NAME); bomService = (BOMServiceLocal) ApplicationDictionaryLocator.locate() .getBusinessService(BOMServiceLocal.SERVICE_NAME); mps = mpsService.load(mpsId); clearMPS(mps); internalGenerateMps(); } /* (non-Javadoc) * @see com.mg.merp.planning.MPSProcessorServiceLocal#mpsLevelTransfer(int, int) */ @Remove public void mpsLevelTransfer(int mpsSrcId, int mpsDstId) { if (mpsSrcId == mpsDstId) return; ormTemplate = OrmTemplate.getInstance(); mpsService = (MPSServiceLocal) ApplicationDictionaryLocator.locate() .getBusinessService(MPSServiceLocal.SERVICE_NAME); mpsLineService = (MPSLineServiceLocal) ApplicationDictionaryLocator.locate() .getBusinessService(MPSLineServiceLocal.SERVICE_NAME); bomService = (BOMServiceLocal) ApplicationDictionaryLocator.locate() .getBusinessService(BOMServiceLocal.SERVICE_NAME); internalMpsLevelTransfer(mpsSrcId, mpsDstId); } class PlanningRange { Date startPlanningDate; Date endPlanningDate; short startBucket; short endBucket; } class ProductDemandItem { GenericItem genericItem; Measure measure; Date requiredDate; BigDecimal quan; short bucketOffset; ForecastVersion forecastVersion; Catalog catalog; private ProductDemandItem(GenericItem genericItem, Catalog catalog, Measure measure, Date requiredDate, BigDecimal quan, short bucketOffset, ForecastVersion forecastVersion) { super(); this.genericItem = genericItem; this.catalog = catalog; this.measure = measure; this.requiredDate = requiredDate; this.quan = quan; this.bucketOffset = bucketOffset; this.forecastVersion = forecastVersion; } } class ProductionDemandKey { short bucketOffset; int planningItemId; int measureId; private ProductionDemandKey(short bucketOffset, int planningItemId, int measureId) { super(); this.bucketOffset = bucketOffset; this.planningItemId = planningItemId; this.measureId = measureId; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { ProductionDemandKey key = (ProductionDemandKey) obj; return this.bucketOffset == key.bucketOffset && this.planningItemId == key.planningItemId && this.measureId == key.measureId; } } class ProductionDemandEntry { BigDecimal productionDemandQty; MpsLine mpsLine; private ProductionDemandEntry(BigDecimal productionDemandQty, MpsLine mpsLine) { super(); this.productionDemandQty = productionDemandQty; this.mpsLine = mpsLine; } } class RollUpMPSResult { BigDecimal quan; int mpsSequence; private RollUpMPSResult(BigDecimal quan, int mpsSequence) { super(); this.quan = quan; this.mpsSequence = mpsSequence; } } }