OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 182 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
 * 
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each file.
 */
 
 package org.openconcerto.erp.core.common.ui;

import org.openconcerto.erp.core.finance.accounting.model.Currency;
import org.openconcerto.erp.core.finance.accounting.model.CurrencyConverter;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.view.list.BaseSQLTableModelColumn;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.ListSQLLine;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.JLabelBold;
import org.openconcerto.utils.TableSorter;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Tuple3;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeListener;
import java.math.BigDecimal;
import java.math.MathContext;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

public class IListTotalPanel extends JPanel {
    CurrencyConverter cc = new CurrencyConverter();

    public enum Type {
        // Pourcentage moyen d'une colonne
        MOYENNE_POURCENT,
        // Moyenne d'une colonne
        MOYENNE_DEVISE,
        // Somme total d'une colonne
        SOMME,
        // Somme total d'une colonne
        SOMME_QTE,
        // Marge en pourcentage requiert dans la liste la colonne achat en premier et vente en
        // deuxieme
        MOYENNE_MARGE,
        // Requiert le field TTC
        AVANCEMENT_TTC,
        // TOTAL DES LIGNES
        COUNT,

        // DIfference entre parama 1 et 2
        DIFF;
    };

    DecimalFormat decimalFormat = new DecimalFormat("##,##0.00");

    EventListenerList loadingListener = new EventListenerList();
    private final IListe list;
    private final Map<SQLTableModelColumn, JLabel> map = new HashMap<SQLTableModelColumn, JLabel>();

    public IListTotalPanel(IListe l, final List<SQLField> listField) {
        this(l, initListe(l, listField), null, null);
    }

    public IListTotalPanel(IListe l, final List<SQLField> listField, String title) {
        this(l, initListe(l, listField), null, title);
    }

    public static List<Tuple2<? extends SQLTableModelColumn, Type>> initListe(IListe iL, List<SQLField> l) {
        List<Tuple2<? extends SQLTableModelColumn, Type>> lFinal = new ArrayList<Tuple2<? extends SQLTableModelColumn, Type>>();

        for (SQLField field : l) {
            final SQLTableModelColumn col = iL.getSource().getColumn(field);
            if (col == null)
                throw new IllegalArgumentException("No column with just " + field + " : " + iL.getSource().getColumns());
            lFinal.add(Tuple2.create(col, Type.SOMME));
        }
        return lFinal;
    }

    public IListTotalPanel(IListe l, final List<Tuple2<? extends SQLTableModelColumn, Type>> listField, final List<Tuple2<SQLField, ?>> filters, String title) {
        this(l, listField, filters, null, title, false);
    }

    public IListTotalPanel(IListe l, final List<Tuple2<? extends SQLTableModelColumn, Type>> listField, final List<Tuple2<SQLField, ?>> filters, final List<Tuple2<SQLField, ?>> filtersNot,
            String title) {
        this(l, listField, filters, filtersNot, title, false);
    }

    private final boolean onSelection;

    /**
     * 
     * @param l
     * @param listField Liste des fields à totaliser
     * @param filters filtre ex : Tuple((SQLField)NATEXIER,(Boolean)FALSE)
     */
    final GridBagConstraints c = new DefaultGridBagConstraints();

    public IListTotalPanel(IListe l, final List<Tuple2<? extends SQLTableModelColumn, Type>> listField, final List<Tuple2<SQLField, ?>> filters, final List<Tuple2<SQLField, ?>> filtersNot,
            String title, boolean onSelection) {
        super(new GridBagLayout());
        this.list = l;
        this.setOpaque(false);
        this.onSelection = onSelection;
        c.gridx = GridBagConstraints.RELATIVE;
        c.weightx = 0;
        if (title != null && title.trim().length() > 0) {
            JLabel sep = new JLabel(title);
            c.weightx = 1;
            c.gridwidth = GridBagConstraints.REMAINDER;
            this.add(sep, c);
            c.gridy++;
            c.gridwidth = 1;
        }
        // Filtre
        for (Tuple2<? extends SQLTableModelColumn, Type> field2 : listField) {
            c.weightx = 0;
            final SQLTableModelColumn col = field2.get0();
            if (col == null) {
                throw new IllegalStateException("null SQLTableModelColumn in " + listField);
            }
            final JLabelBold comp = new JLabelBold(col.getName());
            comp.setHorizontalAlignment(SwingConstants.RIGHT);
            this.add(comp, c);
            JLabelBold textField = new JLabelBold("0");
            textField.setHorizontalAlignment(SwingConstants.RIGHT);
            this.map.put(field2.get0(), textField);
            c.weightx = 1;
            this.add(textField, c);
            c.weightx = 0;
            if (field2.get1() == Type.SOMME || field2.get1() == Type.MOYENNE_DEVISE || field2.get1() == Type.AVANCEMENT_TTC) {
                this.add(new JLabelBold(Currency.getSymbol(cc.getCompanyCurrencyCode())), c);
            } else if (field2.get1() == Type.MOYENNE_POURCENT || field2.get1() == Type.MOYENNE_MARGE) {
                this.add(new JLabelBold("%"), c);
            }
            c.gridy++;
        }

        if (this.onSelection) {
            this.list.getJTable().getSelectionModel().addListSelectionListener(new ListSelectionListener() {

                @Override
                public void valueChanged(ListSelectionEvent e) {

                    final List<ListSQLLine> listLines = list.getSelectedLines();
                    for (Tuple2<? extends SQLTableModelColumn, Type> field : listField) {
                        if (field.get1() == Type.COUNT) {
                            map.get(field.get0()).setText(String.valueOf(listLines.size()));
                        }
                    }
                    computeValues(listField, filters, filtersNot, listLines);
                }
            });
        } else {

            this.list.addListener(new TableModelListener() {

                @Override
                public void tableChanged(TableModelEvent e) {
                    final TableModel model = (TableModel) e.getSource();
                    final ITableModel sqlModel;
                    if (model instanceof ITableModel)
                        sqlModel = (ITableModel) model;
                    else
                        sqlModel = (ITableModel) ((TableSorter) model).getTableModel();

                    final List<ListSQLLine> listLines = new ArrayList<>();
                    for (int i = 0; i < sqlModel.getRowCount(); i++) {
                        listLines.add(sqlModel.getRow(i));
                    }
                    for (Tuple2<? extends SQLTableModelColumn, Type> field : listField) {
                        if (field.get1() == Type.COUNT) {
                            map.get(field.get0()).setText(String.valueOf(model.getRowCount()));
                        }
                    }
                    computeValues(listField, filters, filtersNot, listLines);
                }

            });
        }
    }

    private SQLTableModelColumn fieldDebit, fieldCredit;
    private SQLTableModelColumn soldeEcrColumn;

    public void addSubtract(SQLTableModelColumn fieldDebit, SQLTableModelColumn fieldCredit) {
        c.weightx = 0;

        this.fieldCredit = fieldCredit;
        this.fieldDebit = fieldDebit;
        final JLabelBold comp = new JLabelBold("Solde");
        comp.setHorizontalAlignment(SwingConstants.RIGHT);
        this.add(comp, c);
        JLabelBold textField = new JLabelBold("0");
        textField.setHorizontalAlignment(SwingConstants.RIGHT);
        this.soldeEcrColumn = new BaseSQLTableModelColumn("SoldeEcr", BigDecimal.class) {

            @Override
            protected Object show_(SQLRowAccessor r) {
                // TODO Auto-generated method stub
                return null;
            }

            @Override
            public Set<FieldPath> getPaths() {
                // TODO Auto-generated method stub
                return null;
            }
        };
        this.map.put(soldeEcrColumn, textField);
        c.weightx = 1;
        this.add(textField, c);
        c.weightx = 0;
        this.add(new JLabelBold(Currency.getSymbol(cc.getCompanyCurrencyCode())), c);
        c.gridy++;
    }

    public void fireUpdated() {
        for (PropertyChangeListener l : this.loadingListener.getListeners(PropertyChangeListener.class)) {
            l.propertyChange(null);
        }
    }

    public void addListener(PropertyChangeListener l) {
        this.loadingListener.add(PropertyChangeListener.class, l);
    }

    private Object getValueAt(final ListSQLLine line, final SQLTableModelColumn col, final List<SQLTableModelColumn> columns) {
        final int indexOf = columns.indexOf(col);
        final Object res = line.getValueAt(indexOf);
        if (res == null)
            throw new IllegalStateException("Null value for " + col + " in " + line);
        return res;
    }

    private void computeValues(final List<Tuple2<? extends SQLTableModelColumn, Type>> listField, final List<Tuple2<SQLField, ?>> filters, final List<Tuple2<SQLField, ?>> filtersNot,
            final List<ListSQLLine> listLines) {

        SwingWorker<Tuple3<Map<SQLTableModelColumn, BigDecimal>, Map<SQLTableModelColumn, Double>, Map<SQLTableModelColumn, Integer>>, Object> worker = new SwingWorker<Tuple3<Map<SQLTableModelColumn, BigDecimal>, Map<SQLTableModelColumn, Double>, Map<SQLTableModelColumn, Integer>>, Object>() {
            @Override
            protected Tuple3<Map<SQLTableModelColumn, BigDecimal>, Map<SQLTableModelColumn, Double>, Map<SQLTableModelColumn, Integer>> doInBackground() throws Exception {
                Map<SQLTableModelColumn, BigDecimal> mapTotal = new HashMap<SQLTableModelColumn, BigDecimal>();
                Map<SQLTableModelColumn, Double> mapPourcent = new HashMap<SQLTableModelColumn, Double>();
                Map<SQLTableModelColumn, Integer> mapPourcentSize = new HashMap<SQLTableModelColumn, Integer>();
                for (ListSQLLine line : listLines) {

                    final SQLRowAccessor rowAt = line.getRowAccessor();
                    final List<SQLTableModelColumn> columns = line.getColumns().getColumns();

                    for (final Tuple2<? extends SQLTableModelColumn, Type> field : listField) {
                        final Type type = field.get1();

                        if (type == Type.MOYENNE_POURCENT) {
                            final Double n2 = (Double) getValueAt(line, field.get0(), columns);

                            boolean in = true;

                            if (filters != null) {
                                for (Tuple2<SQLField, ?> tuple2 : filters) {
                                    in = in && rowAt.getObject(tuple2.get0().getName()).equals(tuple2.get1());
                                }
                            }

                            if (filtersNot != null) {
                                for (Tuple2<SQLField, ?> tuple2 : filtersNot) {
                                    in = in && !rowAt.getObject(tuple2.get0().getName()).equals(tuple2.get1());
                                }
                            }

                            if (in) {

                                if (mapPourcent.get(field.get0()) == null) {
                                    mapPourcent.put(field.get0(), n2);
                                } else {
                                    mapPourcent.put(field.get0(), n2 + mapPourcent.get(field.get0()));
                                }

                                if (mapPourcentSize.get(field.get0()) == null) {
                                    mapPourcentSize.put(field.get0(), 1);
                                } else {
                                    mapPourcentSize.put(field.get0(), mapPourcentSize.get(field.get0()).intValue() + 1);
                                }

                            }
                        } else if (type == Type.AVANCEMENT_TTC) {

                            BigDecimal n = mapTotal.get(field.get0());
                            Number objectAs = line.getRow().getObjectAs("T_TTC", Number.class);
                            BigDecimal ttc;
                            if (objectAs instanceof Long) {
                                ttc = BigDecimal.valueOf(objectAs.doubleValue() / 100.0);
                            } else {
                                ttc = BigDecimal.valueOf(objectAs.doubleValue());
                            }
                            BigDecimal av = BigDecimal.valueOf(((Number) getValueAt(line, field.get0(), columns)).doubleValue());

                            boolean in = true;

                            if (filters != null) {
                                for (Tuple2<SQLField, ?> tuple2 : filters) {
                                    in = in && rowAt.getObject(tuple2.get0().getName()).equals(tuple2.get1());
                                }
                            }
                            if (filtersNot != null) {
                                for (Tuple2<SQLField, ?> tuple2 : filtersNot) {
                                    in = in && !rowAt.getObject(tuple2.get0().getName()).equals(tuple2.get1());
                                }
                            }

                            if (in) {
                                if (n == null) {
                                    mapTotal.put(field.get0(), ttc.multiply(av).movePointLeft(2));
                                } else {
                                    mapTotal.put(field.get0(), n.add(ttc.multiply(av).movePointLeft(2)));
                                }
                            }

                        } else if (type != Type.MOYENNE_MARGE && type != Type.COUNT) {

                            // FIXME Test si la colonne existe sinon exception dans liste des
                            // articles quand
                            // on passe de la vue normal à virtuel
                            if (columns.indexOf(field.get0()) != -1) {

                                BigDecimal n = mapTotal.get(field.get0());

                                final Object value = getValueAt(line, field.get0(), columns);
                                final BigDecimal n2 = BigDecimal.valueOf(((Number) value).doubleValue());

                                boolean in = true;

                                if (filters != null) {
                                    for (Tuple2<SQLField, ?> tuple2 : filters) {
                                        in = in && rowAt.getObject(tuple2.get0().getName()).equals(tuple2.get1());
                                    }
                                }
                                if (filtersNot != null) {
                                    for (Tuple2<SQLField, ?> tuple2 : filtersNot) {
                                        in = in && !rowAt.getObject(tuple2.get0().getName()).equals(tuple2.get1());
                                    }
                                }

                                if (in) {
                                    if (n == null) {
                                        mapTotal.put(field.get0(), n2);
                                    } else {
                                        mapTotal.put(field.get0(), n.add(n2));
                                    }
                                }
                            }
                        }
                    }
                }
                return Tuple3.create(mapTotal, mapPourcent, mapPourcentSize);
            }

            @Override
            protected void done() {
                try {
                    Tuple3<Map<SQLTableModelColumn, BigDecimal>, Map<SQLTableModelColumn, Double>, Map<SQLTableModelColumn, Integer>> tuple3 = get();

                    Map<SQLTableModelColumn, BigDecimal> mapTotal = tuple3.get0();
                    Map<SQLTableModelColumn, Double> mapPourcent = tuple3.get1();
                    Map<SQLTableModelColumn, Integer> mapPourcentSize = tuple3.get2();

                    for (Tuple2<? extends SQLTableModelColumn, Type> field : listField) {
                        if (field.get1() == Type.MOYENNE_MARGE) {

                            BigDecimal totalVT = mapTotal.get(listField.get(0).get0());
                            BigDecimal totalHA = mapTotal.get(listField.get(1).get0());
                            if (totalHA != null && totalVT != null && totalVT.longValue() != 0) {
                                map.get(field.get0()).setText(decimalFormat.format(totalVT.subtract(totalHA).divide(totalVT, MathContext.DECIMAL32).doubleValue() * 100.0D));
                            } else {
                                map.get(field.get0()).setText(decimalFormat.format(0));
                            }
                        } else if (field.get1() == Type.MOYENNE_POURCENT) {
                            Double l = mapPourcent.get(field.get0());
                            Integer d = mapPourcentSize.get(field.get0());
                            if (l != null && d != null && d != 0) {
                                map.get(field.get0()).setText(decimalFormat.format(l / (double) d));
                            } else {
                                map.get(field.get0()).setText(decimalFormat.format(0));
                            }
                        } else if (field.get1() != Type.COUNT) {
                            BigDecimal l = mapTotal.get(field.get0());
                            if (l != null) {
                                map.get(field.get0()).setText(decimalFormat.format(l.doubleValue()));
                            } else {
                                map.get(field.get0()).setText(decimalFormat.format(0));
                            }
                        }
                    }

                    if (map.containsKey(soldeEcrColumn)) {
                        BigDecimal d = mapTotal.get(fieldDebit);
                        BigDecimal c = mapTotal.get(fieldCredit);

                        if (d != null && c != null) {
                            map.get(soldeEcrColumn).setText(decimalFormat.format(d.doubleValue() - c.doubleValue()));
                        } else {
                            map.get(soldeEcrColumn).setText(decimalFormat.format(0));
                        }
                    }

                    fireUpdated();
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        };
        worker.execute();

    }
}