• Este debate está vacío.
Viendo 5 entradas - de la 1 a la 5 (de un total de 5)
  • Autor
    Entradas
  • #31659
    Carranza Carlos
    Participante

    En los documentos del plugin de talle y color, se muestra un print screen de ingreso de pedido. El mismo es de pedido de proveedor.
    Imagino que funciona igual para pedido de cliente.
    Estoy queriendo ver esa matriz, pero no se presenta (las combinaciones se generaron, con el botón correspondiente en la ventana de artículos, es decir existen talles, colores y el comjunto obligatorio de atributos seleccionado).
    En qué momento se presenta la matriz para cargar las cantidades de cada talle y color para un artículo dado?
    Agradezco vuestra ayuda.

    #35421
    Carranza Carlos
    Participante

    Agrego más info.
    En uno de los párrafos del documento “features_componentes_talle_color.pdf” dice “Las ventanas de Ingreso de Pedidos tanto de Clientes como a Proveedores, así
    como las de remito de proveedor poseen una funcionalidad adicional: Una vez seleccionado un producto, se despliega una “Matriz de Talle/Color” que permite introducir las cantidades para cada par dentro de los casilleros de la matriz. De esta manera, se simplifica el proceso de pedido y se visualiza de una manera intuitiva el pedido”. Esto no funciona así.
    La ventana de pedido a proveedor (purchase order) sí tiene el botón “Matriz de Atributos”, la de pedido de clientes (sales order) no lo tiene. Se lo agregué, pero no funciona igual (no graba los n registros, de acuerdo a las cantidades agregadas para cada atributo).
    En donde reviso el funcionamiento de la matriz? Cómo se abre la matriz, si no tiene un callout el campo?

    #35427
    Federico Cristina
    Superadministrador

    Buenas,

    Voy a verificar lo que comentás. Mientras tanto,
    deberias ver la clase APanel, desde ahí se dispara la grilla de atributos correspondiente (OpenMatrix si mal no recuerdo en este momento).

    Saludos,
    Federico

    #35422
    Carranza Carlos
    Participante

    Más datos. La columna OpenMatrix (botón) sólo se agrega a la tabla c_OrderLine y el campo openmatrix sólo se agrega a la pestaña “PO Line” de la pantalla “Purchase Order”.
    En otras palabras la funcionalidad, como está al instalar el componente, sólo funciona en órdenes de compra.

    Agregué el campo openmatrix a la pestaña “Order Line” de la pantalla “Sales Order” y funciona (pedidos de clientes), pero no permite cargar una línea de pedido para un artículo sin stock (para un artículo que se produce, en una empresa que produce contra pedido puede ser necesario que no se realice el control). De todas formas este error va a INFO y no a la línea de mensajes como validación.

    Agregué la columna OpenMatrix a la tabla m_inoutline y el campo respectivo en las pestañas de línea en las pantallas “material receipt” y “shipment(customer)”, pero al presionar el botón la funcionalidad no responde. Seguramente deberé agregar algo para que M…. maneje todo esto.

    Después sigo contando (se aceptan ideas, detalles para correcciones, etc.

    #35454
    Federico Cristina
    Superadministrador

    Buenas,

    Es verdad lo que mencionás respecto de la matriz pedidos de proveedor. Dicha funcionalidad funcionalidad en principio fue diseñada para su uso en compras mayoristas, pero ventas minoristas, por lo que no es necesario su uso al vender.

    Más allá de este detalle, debería ser posible realizar la ampliación que requerís codificando un poco. Respecto a dicha grilla en remitos, te paso un “adelanto” del nuevo release, como para que puedas hacerte una idea:

    Clase APanel:

    Code:

    else if( col.equalsIgnoreCase( “OpenMatrix” ))
    {
    // Guardó el registro?
    if (m_curTab.needSave( true,false )) {
    ADialog.error(m_curWindowNo, this, “SaveErrorRowNotFound”);
    return;
    }

    // Instanciar según corresponda
    CDialog dialog = null;
    if (X_C_OrderLine.Table_Name.equalsIgnoreCase(tableName))
    dialog = new VOrderMatrixDetail(m_curWindowNo, (Frame)getRootPane().getParent() );
    if (X_M_InOutLine.Table_Name.equalsIgnoreCase(tableName))
    dialog = new VInOutMatrixDetail(m_curWindowNo, (Frame)getRootPane().getParent() );

    // Si el botón esta ubicado en cualquier otra tabla, no hacer nada
    if (dialog == null)
    return;

    // Abrir el dialogo
    AEnv.showCenterScreen( dialog );
    m_curTab.dataRefreshAll();
    m_curTab.processFieldChange(m_curTab.getField(“M_AttributeSetInstance_ID”));
    return;
    }

    Nueva clase VInOutMatrixDetail:

    Code:
    package org.openXpertya.apps.form;

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.Frame;
    import java.awt.GridLayout;
    import java.awt.Toolkit;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.FocusEvent;
    import java.awt.event.FocusListener;
    import java.math.BigDecimal;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.Vector;
    import java.util.logging.Level;

    import javax.swing.AbstractCellEditor;
    import javax.swing.BorderFactory;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.JTextField;
    import javax.swing.border.Border;
    import javax.swing.event.CellEditorListener;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.TableModelEvent;
    import javax.swing.event.TableModelListener;
    import javax.swing.table.DefaultTableModel;
    import javax.swing.table.TableCellEditor;
    import javax.swing.table.TableCellRenderer;
    import javax.swing.table.TableModel;

    import org.compiere.plaf.CompierePLAF;
    import org.compiere.swing.CButton;
    import org.compiere.swing.CDialog;
    import org.compiere.swing.CPanel;
    import org.openXpertya.apps.search.InfoProductAttribute;
    import org.openXpertya.model.MAttributeInstance;
    import org.openXpertya.model.MAttributeSetInstance;
    import org.openXpertya.model.MInOut;
    import org.openXpertya.model.MInOutLine;
    import org.openXpertya.util.CLogger;
    import org.openXpertya.util.DB;
    import org.openXpertya.util.Env;
    import org.openXpertya.util.Msg;

    public class VInOutMatrixDetail extends CDialog {

    static public CLogger s_log = CLogger.getCLogger(VInOutMatrixDetail.class);

    protected int m_srcWindowNo;

    protected MatrixTableModel tm;

    protected JScrollPane scrollPane;
    protected JTable table;

    protected CButton btnOk;
    protected CButton btnCancel;
    protected CButton btnReload;

    //

    protected int M_InOut_ID ;
    protected int M_InOutLine_ID ;
    protected int M_Product_ID;
    protected int M_Warehouse_ID;

    public VInOutMatrixDetail( int srcWindowNo, Frame owner ) {
    super(owner, “Matriz de remitos”, true);

    m_srcWindowNo = srcWindowNo;

    M_InOut_ID = Env.getContextAsInt(Env.getCtx(), srcWindowNo, “M_InOut_ID”);
    M_InOutLine_ID = Env.getContextAsInt(Env.getCtx(), srcWindowNo, “M_InOutLine_ID”);
    M_Product_ID = Env.getContextAsInt(Env.getCtx(), srcWindowNo, “M_Product_ID”);
    M_Warehouse_ID = Env.getContextAsInt(Env.getCtx(), srcWindowNo, “M_Warehouse_ID”);

    jbInit();
    refreshTableData();

    setDefaultCloseOperation(CDialog.DISPOSE_ON_CLOSE);

    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    d.width = (int)(d.width * 0.75);
    d.height = (int)(d.height * 0.5);

    setPreferredSize(d);
    }

    private void jbInit() {

    setTitle(DB.getSQLValueString(null, ” SELECT name FROM M_Product WHERE M_Product_ID = ? “, M_Product_ID));
    setLayout(new BorderLayout());

    tm = new MatrixTableModel();
    table = new JTable(tm);
    scrollPane = new JScrollPane(table);
    btnCancel = new CButton(Msg.getMsg(Env.getCtx(), “Cancel”));
    btnOk = new CButton(Msg.getMsg(Env.getCtx(), “OK”));
    btnReload = new CButton(Msg.getMsg(Env.getCtx(), “Refresh”));

    MatrixCellEditor mce = new MatrixCellEditor();

    table.setDefaultRenderer(MatrixItem.class, new MatrixCellRenderer());
    table.setDefaultEditor(MatrixItem.class, mce);
    table.putClientProperty(“terminateEditOnFocusLost”, Boolean.TRUE);

    table.addFocusListener(new FocusListener() {
    public void focusGained(FocusEvent e) {
    btnOk.setEnabled(!table.isEditing());
    }

    public void focusLost(FocusEvent e) {
    btnOk.setEnabled(!table.isEditing());
    }
    });

    mce.addCellEditorListener(new CellEditorListener() {
    public void editingCanceled(ChangeEvent e) {
    // btnOk.setEnabled(true);
    }

    public void editingStopped(ChangeEvent e) {
    // btnOk.setEnabled(true);
    }
    });

    DefaultTableModel tm = (DefaultTableModel)table.getModel();

    tm.addTableModelListener(new TableModelListener(){
    public void tableChanged(TableModelEvent e) {
    JTable t = table;
    TableModel tm = t.getModel();

    int rows = t.getRowCount();
    int cols = t.getColumnCount();

    if (rows < 1 || cols < 2) return; Object value = tm.getValueAt(0, 1); Component r = t.getCellRenderer(0, 1).getTableCellRendererComponent(t, value, false, false, 0, 1); // Actualiza el alto de las filas de la tabla en base a los Items t.setRowHeight(r.getMinimumSize().height + t.getRowMargin()); } }); table.revalidate(); GridLayout gr = new GridLayout(1,3); CPanel panel1 = new CPanel(gr); gr.setHgap(5); gr.setVgap(5); btnOk.setIcon(org.openXpertya.images.ImageFactory.getImageIcon("Ok24.gif")); btnCancel.setIcon(org.openXpertya.images.ImageFactory.getImageIcon("Cancel24.gif")); btnReload.setIcon(org.openXpertya.images.ImageFactory.getImageIcon("Refresh24.gif")); btnOk.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { onBtnOk(); } }); btnCancel.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { onBtnCancel(); } }); btnReload.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { refreshTableData(); } }); panel1.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); panel1.add(btnCancel); panel1.add(btnReload); panel1.add(btnOk); add(scrollPane, BorderLayout.CENTER); add(panel1, BorderLayout.SOUTH); } private void updateItemsWithCurrentLines(Vector> items, Map hm) {
    List lines = getCurrentInOutLines();

    lines.add(M_InOutLine_ID);

    // Dada la lista de lineas de la orden actual, actualiza la matriz con los
    // valores actualmente ingresados.

    for (Integer iol : lines) {

    // Busco en la linea de orden la combinacion de valores de la instancia del conjunto de atributos

    MInOutLine line = new MInOutLine(Env.getCtx(), iol, getTrxName());
    Set values = new HashSet( InfoProductAttribute.getAttrInstanceValues(line.getM_AttributeSetInstance_ID()) );

    // Busco en la matriz el elemento que contenga la misma combinacion de valores

    MatrixItem item = null;

    for (int row = 0; item == null && row < items.size(); row++) { for (int column = 0; item == null && column < items.get(row).size(); column++) { MatrixItem x = (MatrixItem)items.get(row).get(column); if (x.getValuesIds().equals(values)) item = x; } } // Si lo encuentro, actualizo la cantidad. if ( item != null ) { item.setEnteredQty(item.getEnteredQty().add(line.getQtyEntered())); // Para no crear varias instancias con la misma combinacion de valores, reuso las ya existentes. if (item.getMasi() < 1) item.setMasi(line.getM_AttributeSetInstance_ID()); } } } protected void refreshTableData() { DefaultTableModel tm = (DefaultTableModel)table.getModel(); Map hm = InfoProductAttribute.getAttributes(M_Product_ID);

    tm.setRowCount(0);
    tm.setColumnCount(0);

    if (hm.size() < 2) return; Iterator it = hm.keySet().iterator();

    if (!it.hasNext())
    return;

    // El atributo a mostrar en el encabezado
    int Attribute_ID = it.next();

    // La lista de nombres de encabezados de columnas

    Vector cols = InfoProductAttribute.getAttrValues(Attribute_ID);

    // La lista de nombres de encabezados de filas

    Vector cols2 = InfoProductAttribute.getAttrMatrixRowsLabels(Attribute_ID, M_Product_ID, hm);

    String primerOrden = hm.get(Attribute_ID);
    cols.insertElementAt(“/” + primerOrden, 0);

    tm.setColumnIdentifiers(cols);

    Vector> rows = getMatrixItems(Attribute_ID, hm);

    // Actualizo los elementos de la matriz con los valores ingresados en las lineas

    updateItemsWithCurrentLines(rows, hm);

    //

    int i = 0;

    for (Vectorr : rows) {
    r.insertElementAt(cols2.get(i++ % cols2.size()), 0);
    tm.addRow(r);
    }

    tm.fireTableStructureChanged();
    }

    private Vector> getMatrixItems(int M_Attribute_ID, Map atributos) {
    Vector> ret = new Vector>();
    String sql = getAttrMatrixItemsSql(M_Attribute_ID, M_Product_ID, M_Warehouse_ID, atributos);
    int columnsCount = DB.getSQLValue(null, “select count(*) from m_attributevalue where m_attribute_id = ?”, M_Attribute_ID);

    PreparedStatement ps = null;

    try {
    ps = DB.prepareStatement(sql, null);

    //

    int pn = 1;

    ps.setInt(pn++, M_Product_ID);

    for (Integer x : atributos.keySet())
    ps.setInt(pn++, x);

    if (M_Warehouse_ID != 0)
    ps.setInt(pn++, M_Warehouse_ID);

    ps.setInt(pn++, M_Product_ID);

    //

    ResultSet rs = ps.executeQuery();

    boolean go = rs.next();

    while (go) {
    int i;
    Vectorx = new Vector();
    for (i = 0; go && i < columnsCount; i++) { BigDecimal b = rs.getBigDecimal(1); b = b.setScale(2, BigDecimal.ROUND_HALF_UP); MatrixItem item = new MatrixItem(b, rs.getInt(2)); for (int w = 1; w <= atributos.size(); w++) item.addValueId(rs.getInt(w + 2)); x.add(item); go = rs.next(); } ret.add(x); } rs.close(); ps.close(); } catch (SQLException e) { s_log.log(Level.SEVERE, "", e); } finally { try{ if (ps != null) ps.close(); } catch (SQLException e) {} } return ret; } @Override public void dispose() { setVisible(false); super.dispose(); } public String getTrxName() { return null; } private List getCurrentInOutLines() {
    List
    ret = new ArrayList();
    PreparedStatement ps = null;

    try {
    ps = DB.prepareStatement(“SELECT M_InOutLine_ID FROM M_InOutLine WHERE M_InOut_ID = ? AND m_product_id = ? AND m_attributesetinstance_id > 0 AND M_InOutLine_ID != ? “, getTrxName());

    int pn = 1;
    ps.setInt(pn++, M_InOut_ID);
    ps.setInt(pn++, M_Product_ID);
    ps.setInt(pn++, M_InOutLine_ID);

    ResultSet rs = ps.executeQuery();

    while (rs.next()) {
    ret.add(rs.getInt(1));
    }

    rs.close();
    ps.close();
    } catch (SQLException e) {
    s_log.log(Level.SEVERE, “”, e);
    } finally {
    try {
    if (ps != null) ps.close();
    } catch (SQLException e) {}
    }

    return ret;
    }

    private MAttributeSetInstance createNewMasi(MatrixItem item) {
    int m_attributeset_id = DB.getSQLValue(getTrxName(), “SELECT m_attributeset_id FROM M_Product WHERE M_Product_ID = ?”, M_Product_ID);
    MAttributeSetInstance masi = new MAttributeSetInstance(Env.getCtx(), 0, m_attributeset_id, getTrxName());

    masi.save();

    for (Integer valueId : item.getValuesIds()) {
    int m_attribute_id = DB.getSQLValue(getTrxName(), ” SELECT m_attribute_id FROM m_attributevalue WHERE m_attributevalue_id = ? ” , valueId);
    String valueStr = DB.getSQLValueString(getTrxName(), ” SELECT value FROM m_attributevalue WHERE m_attributevalue_id = ? ” , valueId);

    MAttributeInstance mai = new MAttributeInstance(Env.getCtx(), m_attribute_id, masi.getM_AttributeSetInstance_ID(), valueId, valueStr, getTrxName());

    mai.save();
    }

    masi.setDescription();
    masi.save();

    return masi;
    }

    protected void onBtnOk() {
    MatrixTableModel tm = (MatrixTableModel)table.getModel();
    Vector itemList = new Vector();
    Vector lineList = new Vector();

    int column , row;

    // Busco las celdas de la tabla con un Qty ingresado > 0

    for ( row = 0; row < tm.getRowCount(); row++ ) { for ( column = 1; column < tm.getColumnCount(); column++ ) { MatrixItem item = (MatrixItem)tm.getValueAt(row, column); if (item.getEnteredQty().signum() > 0) {
    itemList.add(item);
    }
    }
    }

    // Cargo la Orden actual

    MInOut inout = new MInOut(Env.getCtx(), M_InOut_ID, getTrxName());

    // Cargo la Linea de Orden actual sobre la que se presionó el botón

    lineList.add(new MInOutLine(Env.getCtx(), M_InOutLine_ID, getTrxName()));

    // Cargo las demás lineas del pedido actual

    for ( Integer inOutLineId : getCurrentInOutLines() ) {
    lineList.add(new MInOutLine(Env.getCtx(), inOutLineId, getTrxName()));
    }

    // En caso de que hagan falta nuevas lineas, las creo

    while ( lineList.size() < itemList.size() ) { MInOutLine line = new MInOutLine(inout); MInOutLine.copyValues(lineList.firstElement(), line); lineList.add(line); } // Asigno los valores ingresados a las lineas del pedido for ( int i = 0; i < itemList.size(); i++ ) { MatrixItem item = itemList.get(i); MInOutLine line = lineList.get(i); line.setM_Product_ID(M_Product_ID); line.setQty(item.getEnteredQty()); int masi_id; // Tengo que crear un nuevo MASI ? if (item.getMasi() > 0)
    {
    // Si ya hay stock en el item seleccionado, utilizo el mismo MASI

    masi_id = item.getMasi();
    }
    else
    {
    // Si no existe MASI para la combinación elegida, crear uno nuevo

    MAttributeSetInstance masi = createNewMasi(item);

    masi_id = masi.getM_AttributeSetInstance_ID();
    }

    line.setM_AttributeSetInstance_ID(masi_id);

    line.save();
    }

    for ( int i = itemList.size(); i < lineList.size(); i++ ) { MInOutLine line = lineList.get(i); line.setQty(BigDecimal.ZERO); line.save(); } dispose(); } protected void onBtnCancel() { dispose(); } /* +++++++++++ */ private static String getAttrMatrixItemsSql(int M_Attribute_ID, int M_Product_ID, int M_Warehouse_ID, Map atributos) {
    StringBuffer sql = new StringBuffer();
    int w;

    sql.append(” SELECT SUM(COALESCE(sub1.qty, 0.0)) AS SumCant, MIN(sub1.M_ATTRIBUTESETINSTANCE_ID) “);

    for (w = 1; w <= atributos.size(); w++) { sql.append(" , mav" + w + "_id "); } sql.append( InfoProductAttribute.getAttrMatrixItemsSql(M_Attribute_ID, M_Product_ID, M_Warehouse_ID, atributos) ); sql.append(" order by "); for (w = 2; w <= atributos.size(); w++) { sql.append(" ma" + w + "_seqno asc, mav" + w + "_seqno asc, "); } sql.append(" ma1_seqno asc, mav1_seqno asc "); return sql.toString(); } /* +++++++++++ */ private static class MatrixTableModel extends DefaultTableModel { @Override public Class getColumnClass(int columnIndex) {
    if (columnIndex > 0)
    return MatrixItem.class;
    return String.class;
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
    return columnIndex > 0;
    }
    }

    private static class MatrixItem {
    private BigDecimal m_stockQty = BigDecimal.ZERO;
    private BigDecimal m_enteredQty = BigDecimal.ZERO;
    private int m_masi = 0;
    private Set valuesIds = new HashSet();

    public MatrixItem(BigDecimal stockQty, int masi) {
    this.m_stockQty = stockQty;
    this.m_masi = masi;
    }

    public BigDecimal getStockQty() {
    return this.m_stockQty;
    }

    public BigDecimal getEnteredQty() {
    return this.m_enteredQty;
    }

    public void setEnteredQty(BigDecimal enteredQty) {
    this.m_enteredQty = enteredQty;
    }

    public int getMasi() {
    return this.m_masi;
    }

    public void setMasi(int m) {
    this.m_masi = m;
    }

    public void addValueId(int vid) {
    valuesIds.add(vid);
    }

    public Set getValuesIds() {
    return valuesIds;
    }
    }

    private static class MatrixCellRenderer extends JPanel implements TableCellRenderer {

    private JTextField field1 = new JTextField();
    private JTextField field2 = new JTextField();

    Border unselectedBorder = null;
    Border selectedBorder = null;

    public MatrixCellRenderer() {
    GridLayout gl = new GridLayout(1,2);
    gl.setHgap(5);
    setLayout(gl);

    field1.setEditable(false);

    field1.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
    //field2.setBorder(BorderFactory.createEmptyBorder());

    field1.setHorizontalAlignment(JTextField.RIGHT);
    field2.setHorizontalAlignment(JTextField.RIGHT);

    add(field1);
    add(field2);

    Dimension d1 = new Dimension(new Dimension(field1.getMinimumSize()));
    d1.width += field2.getMinimumSize().width + 10;
    d1.height += 6;
    setMinimumSize(d1);
    setPreferredSize(d1);
    }

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    MatrixItem item = (MatrixItem)value;

    if (item != null) {
    field1.setText(item.getStockQty().toString());
    field2.setText(item.getEnteredQty().toString());

    if (item.getStockQty().signum() > 0)
    field1.setForeground(CompierePLAF.getTextColor_OK());
    else
    field1.setForeground(CompierePLAF.getTextColor_Issue());
    }

    if (isSelected) {
    if (selectedBorder == null)
    selectedBorder = BorderFactory.createMatteBorder(2,2,2,2,table.getSelectionBackground());

    setBorder(selectedBorder);
    } else {
    if (unselectedBorder == null)
    unselectedBorder = BorderFactory.createMatteBorder(2,2,2,2,table.getBackground());

    setBorder(unselectedBorder);
    }

    return this;
    }
    }

    private static class MatrixCellEditor extends AbstractCellEditor implements TableCellEditor {

    private MatrixItem currentItem;
    private JTextField field1;

    public MatrixCellEditor() {
    field1 = new JTextField();

    field1.setHorizontalAlignment(JTextField.RIGHT);
    }

    public Object getCellEditorValue() {
    return currentItem;
    }

    public Component getTableCellEditorComponent(JTable arg0, Object arg1, boolean arg2, int arg3, int arg4) {
    currentItem = (MatrixItem)arg1;
    field1.setText(currentItem.getEnteredQty().toString());
    return field1;
    }

    @Override
    public boolean stopCellEditing() {
    try {
    currentItem.setEnteredQty(new BigDecimal(field1.getText()));
    } catch (NumberFormatException e) {
    currentItem.setEnteredQty(BigDecimal.ZERO);
    }
    return super.stopCellEditing();
    }
    }

    }

    Saludos,
    Federico

Viendo 5 entradas - de la 1 a la 5 (de un total de 5)
  • Debes estar registrado para responder a este debate.