示例#1
0
  private void performDailyLearning() {
    updateStatusCode();
    if (statusCd != STATUS_CD.LEARNING || disableLearning == true) {
      return;
    }
    if (onRange && (rcBopInv > 0 || hasSale == true || rcInvIn > 0)) {
      initLearningMetrics();
      // Daily learning only applies to RC_AVG_DEMAND and begins immediately when the PL comes on
      // range
      double lastWeekLift = getDemandUplift(SystemDao.getReviewCycleStartDate());
      double defaultWeight = SystemDao.getDefaultWeight();
      Demand beginOfRunCycleDemand = getDemand(SystemDao.getReviewCycleStartDate());
      double beginOfRunCycleRcAvgDemand = 0;
      if (beginOfRunCycleDemand != null) {
        beginOfRunCycleRcAvgDemand = beginOfRunCycleDemand.getRcAvgDemand();
      }

      if (onRange && !disableLearning) {
        rcAvgDemand =
            getWeightedWeight1(learningWeekCounter, defaultWeight) * rcDemand / lastWeekLift
                + (1 - getWeightedWeight1(learningWeekCounter, defaultWeight))
                    * beginOfRunCycleRcAvgDemand;
      }
    }
  }
示例#2
0
  private void processInventory() {
    LocalDate crc = SystemDao.getCrc();
    if (isStockedOut) {
      Demand d = getDemand(SystemDao.getCrc());
      if (crc.getDayOfWeek() == DateTimeConstants.SUNDAY) {
        d = getDemand(SystemDao.getReviewCycleStartDate());
      }
      int targetInv = (int) d.getRcAvgDemand() - inventory;

      setInventory(targetInv > 0 ? targetInv : (int) d.getRcAvgDemand());
      isStockedOut = false;
    }

    if (crc.getDayOfWeek() == DateTimeConstants.SUNDAY) {
      rcBopInv = inventory;
    }
    // daily inventory updates
    updateEpEopInv();
    epEopInv = inventory;
    rcInvOut += epInvOut;
    rcInvIn += epInvIn;
    ProductInventory p = getInventory(SystemDao.getReviewCycleStartDate());
    double beginOfPeriodEpAvgInv = 0;
    if (p != null) {
      beginOfPeriodEpAvgInv = p.getEpAvgInv();
    }
    double weight_5 = SystemDao.getWeight_5();
    epAvgInv =
        weight_5 * ((epEopInv >= 0) ? epEopInv : 0) + (((1 - weight_5) * beginOfPeriodEpAvgInv));
    epAvgInv = Math.max(0, epAvgInv);
  }
示例#3
0
  private void initLearningMetrics() {
    if (learningMetricsInitialized) {
      return;
    }
    double defaultWeight = SystemDao.getDefaultWeight();
    double lastWeekLift = getDemandUplift(SystemDao.getReviewCycleStartDate());
    Sales beginOfRunCycleSales = getSales(SystemDao.getReviewCycleStartDate());
    double beginOfRunCycleRcAvgSales = 0;
    if (beginOfRunCycleSales != null) {
      beginOfRunCycleRcAvgSales = beginOfRunCycleSales.getRcAvgSales();
    }

    rcAvgSales =
        getWeightedWeight1(learningWeekCounter, defaultWeight) * epSales / lastWeekLift
            + (1 - getWeightedWeight1(learningWeekCounter, defaultWeight))
                * beginOfRunCycleRcAvgSales;

    // Tim's documentation states:
    // Its important sales metrics are initialized to AVG_WEEKLY_SALES based on the initialization
    // logic.
    // This estimates initial values based on different combinations of the PLs product and location
    // hierarchies dependent on the specific situation for that PL
    rcAvgSalesActual = rcAvgSales;
    rcAvgDemand = rcAvgSales;
    rcOldAvgDemand = rcAvgSales;
    rcAvgDemandActual = rcAvgSales;
    epAvgInv = rcAvgSales;
    rcWass2 = Math.pow(rcAvgSales, 2);
    learningMetricsInitialized = true;
  }
示例#4
0
 private Double getWeight1(long age) {
   // Weight that will be used when status_cd = ACTIVE
   if (age <= 0) {
     return SystemDao.getDefaultWeight();
   }
   return Math.max(0.2, 1.0 / age);
 }
示例#5
0
 public void setFirstSalesDate(LocalDate firstSalesDate) {
   if (firstSalesDate == null && epSalesActual > 0) {
     this.firstSalesDate = SystemDao.getCrc();
   } else {
     this.firstSalesDate = firstSalesDate;
   }
 }
示例#6
0
 // Hook: WeeklyLearningSummationHook.java
 public void performWeeklyMetricsProcessing(String locationId) {
   System.out.println(
       "Starting the Weekly Metrics Processing for product/location: " + locationId);
   if (SystemDao.getCrc().getDayOfWeek() == DateTimeConstants.SUNDAY) {
     processWeeklyMetrics();
   }
 }
示例#7
0
 public void setFirstReceiptDate(LocalDate firstReceiptDate) {
   if (this.firstReceiptDate == null && epEopInv > 0 || rcInvIn > 0) {
     this.firstReceiptDate = SystemDao.getCrc();
   } else if (this.firstReceiptDate == null && firstSalesDate != null) {
     this.firstReceiptDate = firstSalesDate;
   }
   this.firstReceiptDate = firstReceiptDate;
 }
示例#8
0
  // Hook: MSSalesOutlierCheckHook.java
  public void performOutlierProcessing(String locId) {
    // only apply constraint if we are not in a seasonal period
    System.out.println(
        "Starting the Outlier/Unreported Sales Calculation for product/location: " + locId);

    int specialPuchaseOrderWassMult = SystemDao.getSpecialPurchaseOrderWassMultiplier();
    int specialPuchaseOrderSizeMult = SystemDao.getSpecialPurchaseOrderSizeMultipler();
    double rcWass2 = Math.pow(rcAvgSales, 2);
    Double maxValue =
        Math.max(
            rcAvgSales + specialPuchaseOrderSizeMult * Math.sqrt(Math.max(0, rcWass2)),
            specialPuchaseOrderWassMult * innerPackQty);
    if (epSalesActual > maxValue && eventSeasonalIndicator == false) {
      epSales = maxValue;
    } else {
      epSales = epSalesActual;
    }
  }
示例#9
0
 public void setDisableLearning(Boolean disableLearning) {
   // Learning can only be turned on on a SUNDAY
   if (disableLearning) {
     if (SystemDao.getCrc().plusDays(1).getDayOfWeek() == DateTimeConstants.SUNDAY)
       this.disableLearning = disableLearning;
   } else {
     this.disableLearning = disableLearning;
   }
 }
示例#10
0
 public void updateStatusCode() {
   switch (this.statusCd) {
     case NEW:
       if (this.statusCd == STATUS_CD.NEW
           && !firstReceiptDate.isAfter(SystemDao.getCrc())
           && !storeOpenDate.isAfter(SystemDao.getCrc())) {
         this.statusCd = STATUS_CD.LEARNING;
       }
       break;
     case LEARNING:
       // provided there have been no non-demand events or events that lasted most of the week and
       // the PL has been on
       // range the entire time, the PL is moved to status_cd = ACTIVE after the 3rd full week.
       if (!hasBeenOffRange && learningWeekCounter > 3) {
         statusCd = STATUS_CD.ACTIVE;
       }
       break;
     case INACTIVE:
       // item only goes inactive during integration, when PL drops from the file
   }
 }
示例#11
0
  private void processWeeklyMetrics() {
    // On the end of the review cycle (Sat night) the rcAvgDemand does not undergo weekly learning
    // For this exercise we do not have time granulity  so weekly processing is done Sunday for the
    // prior week

    LocalDate crc = SystemDao.getCrc();
    LocalDate prevCRCStartDate = SystemDao.getReviewCycleStartDate(); // getPreviousCRCStartDate();
    Sales salesData = getSales(crc);

    Sales beginOfPeriodSalesData = getSales(prevCRCStartDate);
    double beginOfPeriodRcAvgSales = 0;
    double beginOfPeriodRcActualAvgSales = 0;
    if (beginOfPeriodSalesData != null) {
      beginOfPeriodRcAvgSales = beginOfPeriodSalesData.getRcAvgSales();
      beginOfPeriodRcActualAvgSales = beginOfPeriodSalesData.getRcAvgSalesActual();
    }

    Demand demandData = getDemand(crc);
    Demand beginOfPeriodDemandData = getDemand(prevCRCStartDate);
    double beginOfPeriodRcAvgDemand = 0;
    double beginOfPeriodRcAvgActualDemand = 0;
    if (beginOfPeriodDemandData != null) {
      beginOfPeriodRcAvgDemand = beginOfPeriodDemandData.getRcAvgDemand();
      beginOfPeriodRcAvgActualDemand = beginOfPeriodDemandData.getRcAvgDemandActual();
    }
    double defaultWeight = SystemDao.getDefaultWeight();

    double lastWeekLift = getDemandUplift(prevCRCStartDate);
    double weight = 1.0;
    if (statusCd == STATUS_CD.LEARNING) {
      weight = getWeightedWeight1(learningWeekCounter, defaultWeight);
    } else if (statusCd == STATUS_CD.ACTIVE) {
      weight = getWeight1(learningWeekCounter);
    }

    rcAvgSalesActual =
        (weight * (salesData.getRcSalesActual() / lastWeekLift))
            + ((1 - weight) * beginOfPeriodRcActualAvgSales);
    rcAvgSales =
        (weight * (salesData.getRcSales() / lastWeekLift))
            + ((1 - weight) * beginOfPeriodRcAvgSales);
    rcAvgDemand =
        (weight * (demandData.getRcDemand() / lastWeekLift))
            + ((1 - weight) * beginOfPeriodRcAvgDemand);
    rcAvgDemandActual =
        (weight * (demandData.getRcDemandActual() / lastWeekLift))
            + ((1 - weight) * beginOfPeriodRcAvgActualDemand);

    // error checking
    if (rcAvgDemand == 0 && statusCd != STATUS_CD.INACTIVE) {
      System.out.println("Error: 0 demand when product status is not inactive");
    }
    if (rcAvgDemand >= 4 * rcAvgSales) {
      rcAvgSales = 4 * rcAvgSalesActual;
      System.out.println("Error: RC Actual Sales greater then 4 times RC Average Sales");
    }
    if (rcAvgDemand >= 3 * rcAvgSalesActual) {
      rcAvgSales = 3 * rcAvgSalesActual;
      System.out.println("Error: RC Actual Sales greater then 3 times RC Actual Average Sales");
    }

    storeWeeklyMetrics(crc);
    this.learningWeekCounter++;
    // this is the end of the review cycle reset hasBeenOffRange
    if (hasBeenOffRange) {
      hasBeenOffRange = false;
    }
    resetRcAccumulators();
  }
示例#12
0
  /** Outlier filtering has been done prior to processing daily metrics * */
  private void processDailyMetrics() {
    LocalDate crc = SystemDao.getCrc();
    double lostSales = getLostSales();

    rcSalesActual = rcSalesActual + epSalesActual;
    // rcSales is outlier filtered sales and has been calculated in outlier processing
    rcSales = rcSales + epSales;

    Years yr = Years.years(crc.getYear());
    Map<LocalDate, Sales> currSalesMap = salesMap.get(yr);
    if (currSalesMap == null) {
      currSalesMap = new TreeMap<LocalDate, Sales>();
    }
    Sales s = currSalesMap.get(crc);
    if (s == null) {
      s = new Sales();
    }
    s.setEpSalesActual(epSalesActual);
    s.setEpSales(epSales);
    s.setRcSales(rcSales);
    s.setRcSalesActual(rcSalesActual);
    s.setLostSales(lostSales);

    currSalesMap.put(crc, s);
    salesMap.put(yr, currSalesMap);

    /** * Daily Demand Calculations **** */
    // daily demand
    epDemand = getEpDemand();
    // demand = sales + lostsales
    // outlier filtered sales used for rcDemand
    rcDemand = rcSales + lostSales;
    rcDemandActual += (epSalesActual + lostSales);

    Map<LocalDate, Demand> currDemandMap = demandMap.get(yr);
    if (currDemandMap == null) {
      currDemandMap = new TreeMap<LocalDate, Demand>();
    }
    Demand d = currDemandMap.get(crc);
    if (d == null) {
      d = new Demand();
    }
    d.setEpDemand(epDemand);
    d.setRcDemand(rcDemand);
    d.setRcDemandActual(rcDemandActual);
    currDemandMap.put(crc, d);
    demandMap.put(yr, currDemandMap);

    /** **** Daily Inventory Calculations ****** */
    processInventory();

    if (epSales > rcMaxSales) {
      rcMaxSales = epSales;
      weekSinceMaxSales = 0;
    }

    if (epEopInv > demoStock) {
      daysSinceWalk = daysSinceWalk + 1;
    } else {
      daysSinceWalk = 0;
    }

    if (epSalesActual == 0) {
      daysSinceSale = daysSinceSale + 1;
    } else {
      daysSinceSale = 0;
    }

    Map<LocalDate, ProductInventory> currInventoryMap = inventoryMap.get(yr);
    if (currInventoryMap == null) {
      currInventoryMap = new TreeMap<LocalDate, ProductInventory>();
    }
    ProductInventory inv = currInventoryMap.get(crc);
    if (inv == null) {
      inv = new ProductInventory();
    }
    inv.setEpAvgInv(epAvgInv);
    inv.setEpEopInv(epEopInv);
    inv.setEpInvOut(epInvOut);
    inv.setEpInvIn(epInvIn);
    inv.setRcBopInv(rcBopInv);
    inv.setRcBopInv(rcBopInv);
    inv.setRcInvIn(rcInvIn);
    inv.setRcInvOut(rcInvOut);
    inv.setInventory(inventory);

    currInventoryMap.put(crc, inv);
    inventoryMap.put(yr, currInventoryMap);

    if (statusCd == STATUS_CD.LEARNING) {
      performDailyLearning();
    }
    resetEpAccumulators();
  }