@Override
  public List<I_M_HU> retrieveTopLevelHUsForModel(final Object model, final String trxName) {
    final Properties ctx = InterfaceWrapperHelper.getCtx(model);
    final int adTableId = InterfaceWrapperHelper.getModelTableId(model);
    final int recordId = InterfaceWrapperHelper.getId(model);

    final IQueryBL queryBL = Services.get(IQueryBL.class);
    final IQueryBuilder<I_M_HU> queryBuilder =
        queryBL
            .createQueryBuilder(I_M_HU_Assignment.class, ctx, trxName)
            .addEqualsFilter(I_M_HU_Assignment.COLUMN_AD_Table_ID, adTableId)
            .addEqualsFilter(I_M_HU_Assignment.COLUMN_Record_ID, recordId)
            .addOnlyActiveRecordsFilter()
            //
            // Collect top level HUs
            .andCollect(I_M_HU_Assignment.COLUMN_M_HU_ID);

    //
    // 07612: Order by HU ID to preserve allocation order (i.e highest HU quantities / full HUs
    // first)
    queryBuilder.orderBy().addColumn(I_M_HU.COLUMN_M_HU_ID);

    final List<I_M_HU> husTopLevel = queryBuilder.create().list(I_M_HU.class);

    //
    // Guard: make sure all those HUs are really top level
    // Normally, this shall not happen. But we could have the case when the TU was joined to a LU
    // later and the HU assignment was not updated.
    final IHandlingUnitsBL handlingUnitsBL = Services.get(IHandlingUnitsBL.class);
    for (final Iterator<I_M_HU> husTopLevelIterator = husTopLevel.iterator();
        husTopLevelIterator.hasNext(); ) {
      final I_M_HU hu = husTopLevelIterator.next();
      if (!handlingUnitsBL.isTopLevel(hu)) {
        husTopLevelIterator.remove();
        continue;
      }
    }

    // NOTE: this method will NOT exclude destroyed HUs.
    // Before changing this, please carefully check the depending API.

    return husTopLevel;
  }
  @Override
  public ILUTUProducerAllocationDestination createLUTUProducerAllocationDestination(
      final I_M_HU_LUTU_Configuration lutuConfiguration) {
    Check.assumeNotNull(lutuConfiguration, "lutuConfiguration not null");

    final IHandlingUnitsBL handlingUnitsBL = Services.get(IHandlingUnitsBL.class);

    final ILUTUProducerAllocationDestination luProducerDestination = new LUTUProducerDestination();
    luProducerDestination.setM_HU_LUTU_Configuration(lutuConfiguration);

    //
    // LU Configuration
    final I_M_HU_PI_Item luPIItem = lutuConfiguration.getM_LU_HU_PI_Item();
    final int qtyLU = lutuConfiguration.getQtyLU().intValueExact();
    final boolean qtyLUInfinite = lutuConfiguration.isInfiniteQtyLU();
    final int qtyTU = lutuConfiguration.getQtyTU().intValueExact();
    final boolean qtyTUInfinite = lutuConfiguration.isInfiniteQtyTU();
    if (!handlingUnitsBL.isNoPI(luPIItem)) {
      final I_M_HU_PI luPI = luPIItem.getM_HU_PI_Version().getM_HU_PI();
      luProducerDestination.setLUItemPI(luPIItem);
      luProducerDestination.setLUPI(luPI);
      if (qtyLUInfinite) {
        luProducerDestination.setMaxLUsInfinite();

        //
        // 07378: Fix behavior when max LUs are infinite, created max TUs are the ones we specify
        // (otherwise we end up creating infinite HUs for 3 x Tomatoes)
        luProducerDestination.setMaxTUsForRemainingQty(qtyTU);
      } else {
        luProducerDestination.setMaxLUs(qtyLU);
      }

      // TU configuration
      Check.assume(!qtyTUInfinite, "qtyTUInfinite shall be false when dealing with concrete LUs");
      luProducerDestination.setMaxTUsPerLU(qtyTU);
      luProducerDestination.setCreateTUsForRemainingQty(false);
    } else {
      luProducerDestination.setLUItemPI(null);
      luProducerDestination.setLUPI(null);
      luProducerDestination.setMaxLUs(0);

      // TU configuration
      // luProducerDestination.setMaxTUsPerLU(0); // no need to set
      luProducerDestination.setCreateTUsForRemainingQty(true); // we will create only TUs

      if (qtyTUInfinite) {
        luProducerDestination.setMaxTUsForRemainingQtyInfinite();
      } else {
        luProducerDestination.setMaxTUsForRemainingQty(qtyTU);
      }
    }

    //
    // TU Configuration
    final I_M_HU_PI tuPI = lutuConfiguration.getM_TU_HU_PI();
    luProducerDestination.setTUPI(tuPI);
    // TU Capacity
    final I_M_Product cuProduct = lutuConfiguration.getM_Product();
    final I_C_UOM cuUOM = lutuConfiguration.getC_UOM();
    final boolean qtyCUInfinite = lutuConfiguration.isInfiniteQtyCU();
    final BigDecimal qtyCUPerTU =
        qtyCUInfinite ? IHUCapacityDefinition.INFINITY : lutuConfiguration.getQtyCU();
    luProducerDestination.addTUCapacity(cuProduct, qtyCUPerTU, cuUOM);

    //
    // Misc configuration
    luProducerDestination.setC_BPartner(lutuConfiguration.getC_BPartner());
    luProducerDestination.setC_BPartner_Location_ID(lutuConfiguration.getC_BPartner_Location_ID());
    luProducerDestination.setHUStatus(lutuConfiguration.getHUStatus());
    luProducerDestination.setM_Locator(lutuConfiguration.getM_Locator());

    //
    // Return it
    return luProducerDestination;
  }