@Override
 public String toString() {
   StringBuilder resultado = new StringBuilder();
   resultado.append("Traspaso\n");
   MWarehouse warehouse = new MWarehouse(Env.getCtx(), origen, null);
   resultado.append(" " + warehouse.getValue());
   warehouse = new MWarehouse(Env.getCtx(), destino, null);
   resultado.append(" -> " + warehouse.getValue() + "\n");
   MProduct product = null;
   resultado.append("[");
   for (int i = 0; i < cantidades.size(); i++) {
     product = new MProduct(Env.getCtx(), this.productos.get(i), null);
     resultado.append(product.getValue() + "-" + product.getName());
     resultado.append(" - " + cantidades.get(i) + "\n");
   }
   resultado.append("]");
   return resultado.toString();
 }
  /** Procesa los traspasos de el archivo excel */
  public StringBuffer procesarMovimientos(Vector<Movimiento> traspasos) {

    // Iterar sobre cada uno de los traspasos
    Iterator<Movimiento> itr = traspasos.iterator();
    Movimiento mov = null;

    MMovement movimiento = null;
    MMovementLine linea = null;
    StringBuffer buffer = new StringBuffer();

    String nl = " ----- ";

    // Consulta que me dice cuanto me queda en inventario de ese producto
    String sql =
        " WITH  DISPONIBLE AS ( select m_product_id, available from (SELECT M_PRODUCT_ID, sum(available) as available FROM  (SELECT M_PRODUCT_ID, SUM(QTY) AS AVAILABLE FROM M_STORAGEDETAIL  "
            + " WHERE M_LOCATOR_ID =? AND QTYTYPE = 'H'  AND M_AttributeSetInstance_ID>=0  AND M_lOCATOR_ID >= 0  GROUP BY M_PRODUCT_ID HAVING SUM(QTY) > 0  union all  SELECT M_PRODUCT_ID, "
            + " -1*SUM(CANT) AS NOTAVAILABLE FROM  (SELECT M_PRODUCT_ID,SUM(XX_DESIREDQUANTITY) AS CANT FROM XX_VMR_DISTRIBDETAILTEMP where m_warehouse_id=? GROUP BY M_PRODUCT_ID  union all  SELECT M_PRODUCT_ID, SUM(XX_DISTRIBUTEDQTY) AS CANT "
            + " from XX_VMR_PO_PRODUCTDISTRIB D JOIN XX_VMR_ORDER P ON (P.XX_VMR_DISTRIBUTIONHEADER_ID = D.XX_VMR_DISTRIBUTIONHEADER_ID) WHERE P.XX_ORDERREQUESTSTATUS = 'PE' GROUP BY M_PRODUCT_ID  union all  SELECT M_PRODUCT_ID,"
            + " SUM(XX_DISTRIBUTEDQTY) AS CANT from XX_VMR_PO_PRODUCTDISTRIB D JOIN XX_VMR_DistributionHeader H ON (h.XX_VMR_DISTRIBUTIONHEADER_ID = D.XX_VMR_DISTRIBUTIONHEADER_ID) WHERE H.XX_DistributionStatus IN ('QR', 'QT') GROUP BY M_PRODUCT_ID  )"
            + " GROUP BY M_PRODUCT_ID  ) GROUP BY M_PRODUCT_ID) where available>0) SELECT sum(IV.available) FROM  DISPONIBLE iv "
            + " JOIN M_PRODUCT p ON ( IV.M_PRODUCT_ID = p.M_PRODUCT_ID) JOIN XX_VMR_VENDORPRODREF vr ON ( vr.XX_VMR_VENDORPRODREF_ID = p.XX_VMR_VENDORPRODREF_ID)  LEFT OUTER JOIN M_ATTRIBUTESETINSTANCE att ON (p.M_ATTRIBUTESETINSTANCE_ID = att.M_ATTRIBUTESETINSTANCE_ID ) "
            + " WHERE    IV.M_PRODUCT_ID = ? GROUP BY iv.M_PRODUCT_ID, p.VALUE||'-'||p.NAME, iv.M_PRODUCT_ID, att.description, p.M_ATTRIBUTESETINSTANCE_ID HAVING SUM(IV.available)>0  ORDER BY iv.M_PRODUCT_ID";
    // System.out.println(sql);
    PreparedStatement ps = DB.prepareStatement(sql, null);
    ResultSet rs = null;

    while (itr.hasNext()) {
      mov = itr.next();
      movimiento = new MMovement(Env.getCtx(), 0, get_TrxName());

      // Se deben llenar los campos necesarios
      movimiento.setC_DocType_ID(1000335); // Movimiento entre CDs
      String mss = Msg.getMsg(Env.getCtx(), "XX_ImportedMovement", new String[] {archivo});
      movimiento.setDescription(mss);
      movimiento.setMovementDate(new Timestamp(Calendar.getInstance().getTimeInMillis()));

      // Si el origen es centro de distribucion, entonces es el locator chequeado
      MLocator desde = Utilities.obtenerLocatorEnTienda(mov.origen);
      movimiento.setM_Locator_ID(desde.get_ID());

      // El locator hasta, que es el locator chequeado del almacen destino
      MLocator hasta = Utilities.obtenerLocatorEnTransito(mov.destino);
      movimiento.setM_LocatorTo_ID(hasta.get_ID());

      // El resto de los campos
      movimiento.setXX_VMR_Department_ID(mov.departamento);
      /**
       * movimiento.setXX_TransferMotive_ID(
       * Env.getCtx().getContextAsInt("#XX_L_AUTOMATICTRANSFER_ID"));
       */
      movimiento.setM_WarehouseFrom_ID(mov.origen);
      movimiento.setM_WarehouseTo_ID(mov.destino);
      MWarehouse origen = new MWarehouse(getCtx(), mov.origen, null);
      movimiento.setAD_Org_ID(origen.getAD_Org_ID());

      try {
        if (!movimiento.save()) continue;
        commit();
        movimiento.load(get_TrxName());

        // Se copian cada una de las lineas al movimiento
        MProduct producto = null;
        BigDecimal precioVenta = null, costoCompra = null;
        Integer consecutivo = null;
        BigDecimal cantidadMovimiento = null,
            cantidadDisponible = null,
            cantidadDisponibleTotal = null;

        int created_lines = 0;
        for (int i = 0; i < mov.productos.size(); i++) {

          producto = new MProduct(Env.getCtx(), mov.productos.get(i), get_TrxName());
          System.out.println("Producto: " + producto.getValue());
          // Calcular los consecutivos en funcion del inventario
          try {
            ps.setInt(1, Utilities.obtenerLocatorEnTienda(mov.origen).getM_Locator_ID());
            ps.setInt(2, mov.origen);
            ps.setInt(3, producto.get_ID());
            cantidadMovimiento = mov.cantidades.get(i);
            cantidadDisponibleTotal = Env.ZERO;

            rs = ps.executeQuery();

            // Debo buscar las cantidades que tengo en el almacen origen de ese producto

            int cantidadInventario = 0;

            if (rs.next()) {

              cantidadInventario = rs.getInt(1);

              // Crear la linea - si la cantidad disponible es positiva
              if (cantidadInventario > 0) {

                if (cantidadMovimiento.intValue() > cantidadInventario)
                  cantidadMovimiento = new BigDecimal(cantidadInventario);

                // Si la cantidad total en inventario es positiva, ahora buscamos la cantidad que
                // hay por lote
                String sql3 =
                    " SELECT STO.M_ATTRIBUTESETINSTANCE_ID, STO.QTY AS QTYONHAND "
                        + " FROM M_STORAGEDETAIL STO WHERE STO.M_PRODUCT_ID = "
                        + producto.get_ID()
                        + " AND STO.M_LOCATOR_ID = "
                        + Utilities.obtenerLocatorEnTienda(mov.origen).getM_Locator_ID()
                        + " AND STO.QTYTYPE = '"
                        + X_Ref_Quantity_Type.ON_HAND.getValue()
                        + "' "
                        + " AND STO.QTY > 0 "
                        + " AND STO.M_AttributeSetInstance_ID>=0"
                        + " AND STO.M_lOCATOR_ID >= 0"
                        + " ORDER BY STO.M_ATTRIBUTESETINSTANCE_ID ASC";
                PreparedStatement ps3 = DB.prepareStatement(sql3, null);
                ResultSet rs3 = ps3.executeQuery();
                while (rs3.next() && cantidadMovimiento.intValue() > 0) {
                  linea = new MMovementLine(Env.getCtx(), 0, get_TrxName());
                  linea.setM_LocatorTo_ID(movimiento.getM_LocatorTo_ID());
                  linea.setM_Locator_ID(movimiento.getM_Locator_ID());
                  linea.setM_Movement_ID(movimiento.get_ID());
                  linea.setM_Product_ID(producto.get_ID());
                  linea.setM_AttributeSetInstance_ID(rs3.getInt(1));
                  linea.setAD_Org_ID(origen.getAD_Org_ID());
                  linea.setXX_SalePrice(new BigDecimal(0.01));

                  if (producto.getXX_VMR_Brand_ID() != 0)
                    linea.setXX_VMR_Brand_ID(producto.getXX_VMR_Brand_ID());
                  if (producto.getXX_VMR_Line_ID() != 0)
                    linea.setXX_VMR_Line_ID(producto.getXX_VMR_Line_ID());
                  if (producto.getXX_VMR_Section_ID() != 0)
                    linea.setXX_VMR_Section_ID(producto.getXX_VMR_Section_ID());

                  if (producto.getC_TaxCategory_ID() != 0) {
                    linea.setC_TaxCategory_ID(producto.getC_TaxCategory_ID());

                    // Si es mayor que la cantidad solicitada
                    if (rs3.getInt(2) > cantidadMovimiento.intValue()) {

                      linea.setQtyRequired(cantidadMovimiento);
                      linea.setMovementQty(cantidadMovimiento);
                      cantidadMovimiento = Env.ZERO;

                    } else {

                      linea.setQtyRequired(new BigDecimal(rs3.getInt(2)));
                      linea.setMovementQty(new BigDecimal(rs3.getInt(2)));
                      cantidadMovimiento =
                          cantidadMovimiento.subtract(new BigDecimal(rs3.getInt(2)));
                    }
                    // En este caso se almacena
                    if (linea.save()) created_lines++;
                  }
                }
                DB.closeStatement(ps3);
                DB.closeResultSet(rs3);
              }
            }

            // No fueron suficientes piezas
            if (cantidadMovimiento.compareTo(Env.ZERO) == 1) {

              if (mov.cantidades.get(i).compareTo(new BigDecimal(cantidadInventario)) == 1) {

                buffer.append(producto.getValue());
                buffer.append(" " + producto.getName() + " ");
                String msg =
                    Msg.getMsg(
                        Env.getCtx(),
                        "XX_ReqLessThanAvail",
                        new String[] {
                          "" + mov.cantidades.get(i),
                          "" + cantidadInventario,
                          Msg.translate(getCtx(), "All")
                        });
                buffer.append(msg);
                buffer.append(nl);
              }
            }

          } catch (SQLException e) {
            buffer.append(Msg.translate(Env.getCtx(), "XX_ProductPConsecNotFound"));
            buffer.append(" : ");
            buffer.append(producto.getValue() + "-" + producto.getName());
            buffer.append(" - ");
            buffer.append(nl);
          } finally {

          }
        }
        // System.out.println("MOVIMIENTO: "+movimiento.getM_Movement_ID());
        // Si no se creo ninguna linea
        if (created_lines == 0) {
          movimiento.delete(true, get_TrxName());
          buffer.append(Msg.translate(Env.getCtx(), "XX_MovementIgnored") + " ");
          buffer.append(mov.toString());
          buffer.append(nl);
          // AGREGADO POR GHUCHET
        } else {
          //					completarMovimiento(movimiento);
        }
        // HASTA AQUI AGREGADO POR GHUCHET
      } catch (Exception e) {
        log.log(Level.SEVERE, Msg.translate(Env.getCtx(), "XX_DatabaseAccessError"), e);
        buffer.append(Msg.translate(Env.getCtx(), "XX_DatabaseAccessError"));
        buffer.append(nl);
      }
    }
    return buffer;
  }
  public void print_labels(PrintService psZebra, int row, boolean glued) {
    try {

      IDColumn column = (IDColumn) xProductTable.getValueAt(row, 0);
      KeyNamePair knp_product = (KeyNamePair) xProductTable.getValueAt(row, 3);
      KeyNamePair knp_att = (KeyNamePair) xProductTable.getValueAt(row, 11);

      MVMRDiscountAppliDetail detail =
          new MVMRDiscountAppliDetail(Env.getCtx(), column.getRecord_ID(), null);

      int cantidadEtiquetas = ((Number) xProductTable.getValueAt(row, 6)).intValue();

      MProduct producto = new MProduct(Env.getCtx(), knp_product.getKey(), null);
      String name = producto.getName();
      /*
       * Caracteristica larga
       * */
      X_XX_VMR_LongCharacteristic caracLarga =
          new X_XX_VMR_LongCharacteristic(
              Env.getCtx(), producto.getXX_VMR_LongCharacteristic_ID(), null);
      X_M_AttributeSet attrSet =
          new X_M_AttributeSet(Env.getCtx(), producto.getM_AttributeSet_ID(), null);

      DecimalFormat formato = new DecimalFormat(".##");

      // String attr = "AMARILLO T=G                  ";
      // "CHEMISE CABALLERO             "

      X_XX_VMR_Department dep =
          new X_XX_VMR_Department(Env.getCtx(), producto.getXX_VMR_Department_ID(), null);
      String departmentCode = dep.getValue();

      X_XX_VMR_Line lin = new X_XX_VMR_Line(Env.getCtx(), producto.getXX_VMR_Line_ID(), null);
      String lineCode = lin.getValue();

      X_XX_VMR_Section sec =
          new X_XX_VMR_Section(Env.getCtx(), producto.getXX_VMR_Section_ID(), null);
      String seccionCode = sec.getValue();
      String precio = formato.format(detail.getXX_PriceBeforeDiscount());

      MVMRDiscountRequest headerDiscount =
          new MVMRDiscountRequest(Env.getCtx(), detail.getXX_VMR_DiscountRequest_ID(), null);
      MWarehouse tienda = new MWarehouse(Env.getCtx(), headerDiscount.getM_Warehouse_ID(), null);

      X_XX_VMR_PriceConsecutive consecutivoViejo =
          new X_XX_VMR_PriceConsecutive(Env.getCtx(), detail.getXX_VMR_PriceConsecutive_ID(), null);
      // Debo buscar semana, mes y año de la fecha de creacion del consecutivo

      Date date = (Date) consecutivoViejo.getCreated();
      Calendar cal = new GregorianCalendar();
      cal.setTime(date);
      int mes = cal.get(Calendar.MONTH) + 1;
      int año = cal.get(Calendar.YEAR);
      int semana = cal.get(Calendar.WEEK_OF_YEAR);

      BigDecimal impuesto = new BigDecimal(0);

      if (producto.getC_TaxCategory_ID() != 0) {

        String sql_rate =
            " SELECT (RATE) FROM C_TAX "
                + " WHERE C_TaxCategory_ID= "
                + producto.getC_TaxCategory_ID()
                + " AND ValidFrom <= to_date('"
                + date.toString().substring(0, 10)
                + "','yyyy-mm-dd')"
                + " and rownum = 1 "
                + " order by ValidFrom desc ";
        try {
          PreparedStatement prst_tax = DB.prepareStatement(sql_rate, null);
          ResultSet rs_tax = prst_tax.executeQuery();
          if (rs_tax.next()) {

            impuesto = rs_tax.getBigDecimal(1).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
          }
          rs_tax.close();
          prst_tax.close();
        } catch (Exception e) {
          System.out.println("error al calcular el impuesto");
        }
      }

      String product_plus_correlative =
          "" + producto.getValue() + consecutivoTostring(consecutivoViejo.getXX_PriceConsecutive());

      String s = "";
      DocPrintJob job = psZebra.createPrintJob();

      if (impuesto.compareTo(new BigDecimal(0)) > 0) {
        precio =
            formato.format(
                (detail
                        .getXX_PriceBeforeDiscount()
                        .add((detail.getXX_PriceBeforeDiscount()).multiply(impuesto)))
                    .setScale(2, BigDecimal.ROUND_HALF_UP));
        s =
            "^XA^PRD^XZ\n"
                + "^XA^JMA^\n"
                + "^LH07,02^FS\n"
                + "^FO10,03^BE,25,N^BY3, 0.5,45^FD"
                + product_plus_correlative
                + "^FS\n"
                + "^FO10,62^AA,15,12^FD"
                + departmentCode
                + "-"
                + lineCode
                + "-"
                + seccionCode
                + "-"
                + product_plus_correlative
                + "       ^FS\n"
                + "^FO10,82^AA,20,10^FD"
                + name
                + "^FS\n";
        if (!attrSet.getName().isEmpty()
            && attrSet.get_ID() != Env.getCtx().getContextAsInt("#XX_L_P_ATTRIBUTESETST_ID")) {
          s =
              s
                  + "^FO10,97^AA,20,10^FD"
                  + (attrSet.getName().length() > 30
                      ? attrSet.getName().substring(0, 29)
                      : attrSet.getName())
                  + "^FS\n";
        } else if (caracLarga != null
            && caracLarga.getName() != null
            && !caracLarga.getName().isEmpty()) {
          s =
              s
                  + "^FO10,97^AA,20,10^FD"
                  + (caracLarga.getName().length() > 30
                      ? caracLarga.getName().substring(0, 29)
                      : caracLarga.getName())
                  + "^FS\n";
        }
        s =
            s
                + "^FO10,116^AA,14,10^FDPRECIO BS^FS\n"
                + "^FO10,170^AB,11,07^FDRIF J-00046517-7   Incluye IVA "
                + impuesto.multiply(new BigDecimal(100))
                + "%^FS\n"
                + "^FO10,153^AB,11,07^CI10^FD"
                + semana
                + " "
                + mes
                + " "
                + año
                + "^FS\n"
                + "^FO10,138^AA,11,09^FDBsF.^FS\n"
                + "^FO35,136^AB,11,07^CI10^FD         "
                + precio
                + "^FS\n"
                + "^PQ"
                + cantidadEtiquetas
                + "^FS\n"
                + "^XZ\n"
                +
                // Control label
                "^XA^PRD^XZ\n"
                + "^XA^JMA^\n"
                + "^LH00,15^FS\n"
                + "^FO2,5^AD,38,10^FD*CONTROL*     "
                + semana
                + " "
                + mes
                + ""
                + año
                + "^FS\n"
                + "^FO05,45^A0,30,07^FD                  TDA:  "
                + tienda.getValue()
                + "^FS\n"
                + "^FO28,48^A0,15,14^FDCANT:     "
                + cantidadEtiquetas
                + "      PRECIO      "
                + precio
                + "^FS\n"
                + "^FO05,95^A0,18,10^FD"
                + departmentCode
                + "-"
                + lineCode
                + "-"
                + seccionCode
                + "- "
                + product_plus_correlative
                + "^FS\n"
                + "^FO05,120^A0,18,10^FD"
                + name
                + "^FS\n"
                + "^FO05,140^A0,18,10^FD                                                  ^FS\n"
                + "^PQ1^FS\n"
                + "^XZ";
      } else {
        s =
            "^XA^PRD^XZ\n"
                + "^XA^JMA^\n"
                + "^LH07,02^FS\n"
                + "^FO10,03^BE,25,N^BY3, 0.5,45^FD"
                + product_plus_correlative
                + "^FS\n"
                + "^FO10,62^AA,15,12^FD"
                + departmentCode
                + "-"
                + lineCode
                + "-"
                + seccionCode
                + "-"
                + product_plus_correlative
                + "       ^FS\n"
                + "^FO10,82^AA,20,10^FD"
                + name
                + "^FS\n"
                + "^FO10,97^AA,20,10^FD                                                  ^FS\n"
                + "^FO10,116^AA,14,10^FDPRECIO BS^FS\n"
                + "^FO10,170^AB,11,07^FDRIF J-00046517-7   Exento de Iva%^FS\n"
                + "^FO10,153^AB,11,07^CI10^FD"
                + semana
                + " "
                + mes
                + " "
                + año
                + "^FS\n"
                + "^FO10,138^AA,11,09^FDBsF.^FS\n"
                + "^FO35,136^AB,11,07^CI10^FD         "
                + precio
                + "^FS\n"
                + "^PQ"
                + cantidadEtiquetas
                + "^FS\n"
                + "^XZ\n"
                +
                // Control label
                "^XA^PRD^XZ\n"
                + "^XA^JMA^\n"
                + "^LH00,15^FS\n"
                + "^FO2,5^AD,38,10^FD*CONTROL*     "
                + semana
                + " "
                + mes
                + ""
                + año
                + "^FS\n"
                + "^FO05,45^A0,30,07^FD                  TDA:  "
                + tienda.getValue()
                + "^FS\n"
                + "^FO28,48^A0,15,14^FDCANT:     "
                + cantidadEtiquetas
                + "      PRECIO      "
                + precio
                + "^FS\n"
                + "^FO05,95^A0,18,10^FD"
                + departmentCode
                + "-"
                + lineCode
                + "-"
                + seccionCode
                + "- "
                + product_plus_correlative
                + "^FS\n"
                + "^FO05,120^A0,18,10^FD"
                + name
                + "^FS\n"
                + "^FO05,140^A0,18,10^FD                                                  ^FS\n"
                + "^PQ1^FS\n"
                + "^XZ";
      }

      byte[] by = s.getBytes();
      DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
      Doc doc = new SimpleDoc(by, flavor, null);
      job.print(doc, null);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }