/** @return Devuelve el remito origen de este CreateFrom. */
 public MInOut getInOut() {
   if (inOut == null) {
     inOut = new MInOut(getCtx(), (Integer) p_mTab.getValue("M_InOut_ID"), getTrxName());
   }
   inOut.set_TrxName(getTrxName());
   return inOut;
 }
  /**
   * Descripción de Método
   *
   * @return
   */
  protected void save() throws CreateFromSaveException {

    // La ubicación es obligatoria
    Integer locatorID = (Integer) locatorField.getValue();
    if (locatorID == null || (locatorID == 0)) {
      locatorField.setBackground(CompierePLAF.getFieldBackground_Error());
      throw new CreateFromSaveException("@NoLocator@");
    }

    // Actualiza el encabezado del remito (necesario para validaciones en las
    // líneas a crear del remito)
    MInOut inout = getInOut();
    log.config(inout + ", C_Locator_ID=" + locatorID);
    // Asocia el pedido
    if (p_order != null) {
      inout.setC_Order_ID(p_order.getC_Order_ID());
      inout.setDateOrdered(p_order.getDateOrdered());
      inout.setC_Project_ID(p_order.getC_Project_ID());
    }
    // Asocia la factura
    if ((m_invoice != null) && (m_invoice.getC_Invoice_ID() != 0)) {
      inout.setC_Invoice_ID(m_invoice.getC_Invoice_ID());
    }

    // Guarda el encabezado. Si hay error cancela la operación
    if (!inout.save()) {
      throw new CreateFromSaveException(CLogger.retrieveErrorAsString());
    }

    // Lines

    for (SourceEntity sourceEntity : getSelectedSourceEntities()) {
      DocumentLine docLine = (DocumentLine) sourceEntity;
      BigDecimal movementQty = docLine.remainingQty;
      int C_UOM_ID = docLine.uomID;
      int M_Product_ID = docLine.productID;

      // Crea la línea del remito

      MInOutLine iol = new MInOutLine(inout);
      iol.setM_Product_ID(M_Product_ID, C_UOM_ID); // Line UOM
      iol.setQty(movementQty); // Movement/Entered
      iol.setM_Locator_ID(locatorID); // Locator
      iol.setDescription(docLine.description);

      MInvoiceLine il = null;
      MOrderLine ol = null;

      // La línea del remito se crea a partir de una línea de pedido
      if (docLine.isOrderLine()) {
        OrderLine orderLine = (OrderLine) docLine;
        // Asocia línea remito -> línea pedido
        iol.setC_OrderLine_ID(orderLine.orderLineID);
        ol = new MOrderLine(Env.getCtx(), orderLine.orderLineID, getTrxName());
        // Proyecto
        iol.setC_Project_ID(ol.getC_Project_ID());
        if (ol.getQtyEntered().compareTo(ol.getQtyOrdered()) != 0) {
          iol.setMovementQty(
              movementQty
                  .multiply(ol.getQtyOrdered())
                  .divide(ol.getQtyEntered(), BigDecimal.ROUND_HALF_UP));
          iol.setC_UOM_ID(ol.getC_UOM_ID());
        }
        // Instancia de atributo
        if (ol.getM_AttributeSetInstance_ID() != 0) {
          iol.setM_AttributeSetInstance_ID(ol.getM_AttributeSetInstance_ID());
        }
        // Cargo (si no existe el artículo)
        if (M_Product_ID == 0 && ol.getC_Charge_ID() != 0) {
          iol.setC_Charge_ID(ol.getC_Charge_ID());
        }

        // La línea del remito se crea a partir de una línea de factura
      } else if (docLine.isInvoiceLine()) {
        InvoiceLine invoiceLine = (InvoiceLine) docLine;
        // Credit Memo - negative Qty
        if (m_invoice != null && m_invoice.isCreditMemo()) {
          movementQty = movementQty.negate();
        }
        il = new MInvoiceLine(Env.getCtx(), invoiceLine.invoiceLineID, getTrxName());
        // Proyecto
        iol.setC_Project_ID(il.getC_Project_ID());
        if (il.getQtyEntered().compareTo(il.getQtyInvoiced()) != 0) {
          iol.setQtyEntered(
              movementQty
                  .multiply(il.getQtyInvoiced())
                  .divide(il.getQtyEntered(), BigDecimal.ROUND_HALF_UP));
          iol.setC_UOM_ID(il.getC_UOM_ID());
        }
        // Cargo (si no existe el artículo)
        if (M_Product_ID == 0 && il.getC_Charge_ID() != 0) {
          iol.setC_Charge_ID(il.getC_Charge_ID());
        }
        // Si la línea de factura estaba relacionada con una línea de pedido
        // entonces se hace la asociación a la línea del remito. Esto es necesario
        // para que se actualicen los valores QtyOrdered y QtyReserved en el Storage
        // a la hora de completar el remito.
        if (invoiceLine.orderLineID > 0) {
          iol.setC_OrderLine_ID(invoiceLine.orderLineID);
        }
      }
      // Guarda la línea de remito
      if (!iol.save()) {
        throw new CreateFromSaveException(
            "@InOutLineSaveError@ (# "
                + docLine.lineNo
                + "):<br>"
                + CLogger.retrieveErrorAsString());

        // Create Invoice Line Link
      } else if (il != null) {
        il.setM_InOutLine_ID(iol.getM_InOutLine_ID());
        if (!il.save()) {
          throw new CreateFromSaveException(
              "@InvoiceLineSaveError@ (# "
                  + il.getLine()
                  + "):<br>"
                  + CLogger.retrieveErrorAsString());
        }
      }
    } // for all rows
  } // save