public I_AD_Org createOrg(final String name) {
    final I_AD_Org org = InterfaceWrapperHelper.create(ctx, I_AD_Org.class, ITrx.TRXNAME_None);
    org.setValue(name);
    org.setName(name);
    InterfaceWrapperHelper.save(org);

    final I_AD_OrgInfo orgInfo = InterfaceWrapperHelper.newInstance(I_AD_OrgInfo.class, org);
    orgInfo.setAD_Org_ID(org.getAD_Org_ID());

    //
    // InTransit Warehouse
    final I_M_Warehouse warehouseInTransit = createWarehouse(name + "_InTransit", org);
    warehouseInTransit.setIsInTransit(true);
    InterfaceWrapperHelper.save(warehouseInTransit);

    //
    // BP Org Link
    final I_C_BPartner bpartner = createBPartner("BPOrg_" + name);
    // bpartner.setAD_OrgBP_ID(String.valueOf(org.getAD_Org_ID()));
    bpartner.setAD_OrgBP_ID(org.getAD_Org_ID());
    InterfaceWrapperHelper.save(bpartner);
    //
    final I_C_BPartner_Location bpLocation = createBPLocation(bpartner);
    orgInfo.setOrgBP_Location(bpLocation);
    InterfaceWrapperHelper.save(orgInfo);

    return org;
  }
  private int getAD_Org_ID_ToUse() {
    if (_adOrgId != null) {
      return _adOrgId;
    } else if (_mrpContext != null) {
      final I_AD_Org org = _mrpContext.getAD_Org();
      if (org != null) {
        return org.getAD_Org_ID();
      }
    }

    return -1;
  }
  private void setupContext(final boolean initEnvironment) {
    ctx = Env.getCtx();
    trxName = ITrx.TRXNAME_None;

    //
    // Setup context: #AD_Client_ID
    int adClientId = Env.getAD_Client_ID(ctx);
    if (adClientId <= 0) {
      adClient = InterfaceWrapperHelper.create(ctx, I_AD_Client.class, ITrx.TRXNAME_None);
      InterfaceWrapperHelper.save(adClient);
      adClientId = adClient.getAD_Client_ID();
      Env.setContext(ctx, Env.CTXNAME_AD_Client_ID, adClientId);
    } else {
      adClient =
          InterfaceWrapperHelper.create(ctx, adClientId, I_AD_Client.class, ITrx.TRXNAME_None);
    }

    int adOrgId = Env.getAD_Org_ID(ctx);
    if (adOrgId <= 0) {
      adOrg01 = createOrg("Org01");
      adOrgId = adOrg01.getAD_Org_ID();
      Env.setContext(ctx, Env.CTXNAME_AD_Org_ID, adOrgId);
    } else {
      adOrg01 = InterfaceWrapperHelper.create(ctx, adOrgId, I_AD_Org.class, ITrx.TRXNAME_None);
    }

    SystemTime.setTimeSource(
        new TimeSource() {
          @Override
          public long millis() {
            return _today.getTime();
          }
        });
  }
  public I_C_DocType createDocType(final String docBaseType) {
    final I_C_DocType docType =
        InterfaceWrapperHelper.newInstance(I_C_DocType.class, contextProvider);
    docType.setAD_Org_ID(adOrg01.getAD_Org_ID());
    docType.setDocBaseType(docBaseType);
    docType.setName(docBaseType);

    InterfaceWrapperHelper.save(docType);
    return docType;
  }
  public I_M_Warehouse createWarehouse(
      final String name, final I_AD_Org org, final I_S_Resource plant) {
    final I_M_Warehouse warehouse =
        InterfaceWrapperHelper.newInstance(I_M_Warehouse.class, contextProvider);
    warehouse.setAD_Org_ID(org.getAD_Org_ID());
    warehouse.setValue(name);
    warehouse.setName(name);
    warehouse.setIsInTransit(false);
    warehouse.setPP_Plant(plant);
    InterfaceWrapperHelper.save(warehouse);

    return warehouse;
  }
  @Override
  public I_AD_Note createMRPNote() {
    final Properties ctx = getCtx();
    final I_AD_Org org = getAD_Org_ToUse();
    final int AD_Org_ID = org == null ? 0 : org.getAD_Org_ID();
    final I_M_Warehouse warehouse = getM_Warehouse_ToUse();
    final I_S_Resource plant = getPlant_ToUse();
    final I_M_Product product = getM_Product_ToUse();
    final int productPlanningId = getPP_Product_Planning_ID_ToUse();
    final int panner_AD_User_ID = getPlanner_AD_Use_ID_ToUse();

    //
    // Note's TextMsg
    final I_AD_Message adMessageToUse = getMRPCode_AD_Message_ToUse();
    final StringBuilder noteTextMsg = new StringBuilder();
    noteTextMsg
        .append(adMessageToUse.getValue())
        .append(" - ")
        .append(messagesBL.getMsg(ctx, adMessageToUse.getValue()));

    //
    // Note's Reference text
    final String noteReference;
    if (product != null) {
      noteReference =
          messagesBL.translate(ctx, "M_Product_ID")
              + ": "
              + product.getValue()
              + " "
              + product.getName();
    } else {
      noteReference = "";
    }

    //
    // Append DocumentNos to note's TextMsg
    final Set<String> documentNos = getDocumentNos_ToUse();
    if (documentNos != null && !documentNos.isEmpty()) {
      final String documentNoPropertyName =
          messagesBL.translate(ctx, I_PP_Order.COLUMNNAME_DocumentNo);
      for (final String documentNo : documentNos) {
        noteTextMsg.append("\n" + documentNoPropertyName + ":" + documentNo);
      }
    }

    //
    // Append additional parameters to TextMsg
    final String parametersStr = getParametersAsString();
    if (!Check.isEmpty(parametersStr, true)) {
      noteTextMsg.append("\n").append(parametersStr);
    }

    //
    // Apppend Comment (if any) to note's TextMsg
    final String comment = getComment_ToUse();
    if (!Check.isEmpty(comment, true)) {
      noteTextMsg.append("\n").append(comment);
    }

    //
    // Append Exception (if any)
    final Exception exception = getException_ToUse();
    if (exception != null) {
      String exceptionStr = exception.getLocalizedMessage();
      if (exceptionStr == null || exceptionStr.length() <= 5) {
        // comment to small, better use whole exception string
        exceptionStr = exception.toString();
      }

      noteTextMsg.append("\nException: ").append(exceptionStr);

      // NOTE: since the exception is not logged anywhere, we are printing here to console
      // FIXME: create an AD_Issue and link it to create AD_Note.
      logger.log(Level.WARNING, exception.getLocalizedMessage(), exception);
    }

    //
    // Create AD_Note and return it
    {
      final I_PP_MRP mrp = getPP_MRP_ToUse();
      final int mrpId = mrp == null ? 0 : mrp.getPP_MRP_ID();

      final I_AD_Note note =
          InterfaceWrapperHelper.create(ctx, I_AD_Note.class, ITrx.TRXNAME_ThreadInherited);
      note.setAD_Org_ID(AD_Org_ID);
      note.setAD_Message_ID(adMessageToUse.getAD_Message_ID());
      note.setAD_User_ID(panner_AD_User_ID);

      // NOTE: we always shall set the AD_Table_ID=PP_MRP because else the MRP cleanup won't delete
      // this note (see org.eevolution.mrp.api.impl.MRPNoteDAO.deleteMRPNotes(IMRPContext))
      note.setAD_Table_ID(InterfaceWrapperHelper.getTableId(I_PP_MRP.class));

      if (mrpId > 0) {
        note.setRecord_ID(mrpId);
      }
      note.setM_Warehouse(warehouse);
      note.setPP_Plant(plant);
      note.setM_Product(product);
      note.setPP_Product_Planning_ID(productPlanningId);
      note.setReference(noteReference);
      note.setTextMsg(noteTextMsg.toString());
      InterfaceWrapperHelper.save(note);
      return note;
    }
  }
  @Override
  public void createSupply(final IMRPCreateSupplyRequest request) {
    final IMRPContext mrpContext = request.getMRPContext();
    final IMRPExecutor executor = request.getMRPExecutor();

    final Properties ctx = mrpContext.getCtx();
    final I_PP_Product_Planning productPlanningData = mrpContext.getProductPlanning();
    final I_AD_Org org = mrpContext.getAD_Org();
    final I_S_Resource plant = mrpContext.getPlant();
    final Timestamp supplyDateFinishSchedule = TimeUtil.asTimestamp(request.getDemandDate());

    // QtyToSupply: qty for which we need to produce the supply
    final BigDecimal qtyToSupply = request.getQtyToSupply();

    // TODO vpj-cd I need to create logic for DRP-040 Shipment Due Action Notice
    // Indicates that a shipment for a Order Distribution is due.
    // Action should be taken at the source warehouse to ensure that the order is received on time.

    // TODO vpj-cd I need to create logic for DRP-050 Shipment Pas Due Action Notice
    // Indicates that a shipment for a Order Distribution is past due. You should either delay the
    // orders created the requirement for the product
    // or expedite them when the product does arrive.

    if (productPlanningData.getDD_NetworkDistribution_ID() <= 0) {
      // Indicates that the Product Planning Data for this product does not specify a valid network
      // distribution.
      executor.newMRPNote(mrpContext, ERR_DRP_060_NoSourceOfSupply).collect();
      //
      return;
    }

    final I_DD_NetworkDistribution network = productPlanningData.getDD_NetworkDistribution();
    final List<I_DD_NetworkDistributionLine> networkLines =
        Services.get(IDistributionNetworkDAO.class)
            .retrieveNetworkLinesByTargetWarehouse(
                network, productPlanningData.getM_Warehouse_ID());
    if (networkLines.isEmpty()) {
      // No network lines were found for our target warehouse
      final I_M_Warehouse warehouseTo = productPlanningData.getM_Warehouse();
      executor
          .newMRPNote(mrpContext, ERR_DRP_060_NoSourceOfSupply)
          .setComment("@NotFound@ @DD_NetworkDistributionLine_ID@")
          .addParameter(
              I_DD_NetworkDistribution.COLUMNNAME_DD_NetworkDistribution_ID,
              network == null ? "?" : network.getName())
          .addParameter("M_Warehouse_Dest_ID", warehouseTo == null ? "?" : warehouseTo.getName())
          .collect();
      //
      return;
    }

    int M_Shipper_ID = -1;
    I_DD_Order order = null;

    BigDecimal qtyToSupplyRemaining = qtyToSupply;
    for (final I_DD_NetworkDistributionLine networkLine : networkLines) {
      //
      // Check: if we created DD Orders for all qty that needed to be supplied, stop here
      if (qtyToSupplyRemaining.signum() <= 0) {
        break;
      }

      // get supply source warehouse and locator
      final I_M_Warehouse warehouseFrom = networkLine.getM_WarehouseSource();
      final I_M_Locator locatorFrom =
          Services.get(IWarehouseBL.class).getDefaultLocator(warehouseFrom);

      // get supply target warehouse and locator
      final I_M_Warehouse warehouseTo = networkLine.getM_Warehouse();
      final I_M_Locator locatorTo = Services.get(IWarehouseBL.class).getDefaultLocator(warehouseTo);

      if (locatorFrom == null || locatorTo == null) {
        executor
            .newMRPNote(mrpContext, "DRP-001") // FIXME: DRP-001 error code does not exist
            .addParameter(
                I_DD_NetworkDistribution.COLUMNNAME_DD_NetworkDistribution_ID,
                network == null ? "?" : network.getName())
            .addParameter(
                I_DD_NetworkDistributionLine.COLUMNNAME_M_WarehouseSource_ID,
                warehouseFrom.getName())
            .addParameter(
                I_DD_NetworkDistributionLine.COLUMNNAME_M_Warehouse_ID, warehouseTo.getName())
            .setComment("No locators found for source or target warehouse")
            .collect();
        //
        continue;
      }

      //
      // Get the warehouse in transit
      final I_M_Warehouse warehouseInTrasit =
          retrieveInTransitWarehouse(ctx, warehouseFrom.getAD_Org_ID());
      if (warehouseInTrasit == null) {
        // DRP-010: Do not exist Transit Warehouse to this Organization
        executor
            .newMRPNote(mrpContext, ERR_DRP_010_InTransitWarehouseNotFound)
            .addParameter(I_AD_Org.COLUMNNAME_AD_Org_ID, org.getName())
            .collect();
        //
        continue;
      }

      //
      // DRP-030: Do not exist Shipper for Create Distribution Order
      if (networkLine.getM_Shipper_ID() <= 0) {
        executor
            .newMRPNote(mrpContext, "DRP-030")
            .addParameter(
                I_DD_NetworkDistribution.COLUMNNAME_DD_NetworkDistribution_ID,
                network == null ? "?" : network.getName())
            .addParameter(
                I_DD_NetworkDistributionLine.COLUMNNAME_DD_NetworkDistributionLine_ID, networkLine)
            .collect();
        //
        continue;
      }

      if (M_Shipper_ID != networkLine.getM_Shipper_ID()) {
        // Org Must be linked to BPartner
        final I_AD_Org locatorToOrg = locatorTo.getAD_Org();
        final IBPartnerOrgBL bpartnerOrgBL = Services.get(IBPartnerOrgBL.class);
        final I_C_BPartner orgBPartner = bpartnerOrgBL.retrieveLinkedBPartner(locatorToOrg);
        if (orgBPartner == null) {
          // DRP-020: Target Org has no BP linked to it
          executor
              .newMRPNote(mrpContext, "DRP-020")
              .addParameter(I_AD_Org.COLUMNNAME_AD_Org_ID, locatorToOrg.getName())
              .collect();
          //
          continue;
        }

        final I_C_BPartner_Location orgBPLocation =
            bpartnerOrgBL.retrieveOrgBPLocation(
                mrpContext.getCtx(), locatorToOrg.getAD_Org_ID(), ITrx.TRXNAME_None);

        //
        // Try found some DD_Order with Shipper , Business Partner and Doc Status = Draft
        // Consolidate the demand in a single order for each Shipper , Business Partner ,
        // DemandDateStartSchedule
        order =
            getDDOrderFromCache(
                org,
                plant,
                warehouseInTrasit,
                networkLine.getM_Shipper_ID(),
                orgBPartner.getC_BPartner_ID(),
                supplyDateFinishSchedule);
        if (order == null) {
          order = InterfaceWrapperHelper.newInstance(I_DD_Order.class, mrpContext);
          order.setMRP_Generated(true);
          order.setMRP_AllowCleanup(true);
          order.setAD_Org_ID(warehouseTo.getAD_Org_ID());
          order.setPP_Plant(plant);
          order.setC_BPartner(orgBPartner);
          order.setC_BPartner_Location(orgBPLocation);
          // order.setAD_User_ID(productPlanningData.getPlanner_ID()); // FIXME: improve
          // performances/cache and retrive Primary BP's User
          order.setSalesRep_ID(productPlanningData.getPlanner_ID());

          final int docTypeDO_ID =
              getC_DocType_ID(mrpContext, X_C_DocType.DOCBASETYPE_DistributionOrder);
          order.setC_DocType_ID(docTypeDO_ID);
          order.setM_Warehouse(warehouseInTrasit);
          order.setDocStatus(X_DD_Order.DOCSTATUS_Drafted);
          order.setDocAction(X_DD_Order.DOCACTION_Complete);
          order.setDateOrdered(mrpContext.getDateAsTimestamp());
          order.setDatePromised(supplyDateFinishSchedule);
          order.setM_Shipper_ID(networkLine.getM_Shipper_ID());
          order.setIsInDispute(false);
          order.setIsInTransit(false);

          InterfaceWrapperHelper.save(order);

          executor.addGeneratedSupplyDocument(order);
          addToCache(order);
        }
        M_Shipper_ID = networkLine.getM_Shipper_ID();
      }

      //
      // Crate DD order line
      final BigDecimal qtyToMove =
          calculateQtyToMove(qtyToSupplyRemaining, networkLine.getPercent());
      createDD_OrderLine(
          mrpContext,
          order,
          networkLine,
          locatorFrom,
          locatorTo,
          qtyToMove,
          supplyDateFinishSchedule,
          request);

      qtyToSupplyRemaining = qtyToSupplyRemaining.subtract(qtyToMove);
    }

    //
    // Check: remaining qtyToSupply shall be ZERO
    if (qtyToSupplyRemaining.signum() != 0) {
      // TODO: introduce DRP-XXX notice
      throw new LiberoException(
          "Cannot create DD Order for required Qty To Supply."
              + "\nQtyToSupply: "
              + qtyToSupply
              + "\nQtyToSupply (remaining): "
              + qtyToSupplyRemaining
              + "\n@DD_NetworkDistribution_ID@: "
              + network
              + "\n@DD_NetworkDistributionLine_ID@: "
              + networkLines
              + "\nMRPContext: "
              + mrpContext);
    }
  }