OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 180 | Go to most recent revision | 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.supplychain.stock.element;

import org.openconcerto.erp.core.sales.product.model.ProductComponent;
import org.openconcerto.erp.core.sales.product.model.ProductHelper;
import org.openconcerto.erp.core.sales.product.model.ProductHelper.SupplierPriceField;
import org.openconcerto.erp.importer.ArrayTableModel;
import org.openconcerto.erp.importer.DataImporter;
import org.openconcerto.erp.preferences.GestionArticleGlobalPreferencePanel;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesCluster.StoreMode;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.preferences.SQLPreferences;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Tuple3;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.swing.JOptionPane;

import org.apache.commons.dbutils.ResultSetHandler;

public class InventaireFromEtatStockImporter {

    private Map<String, SQLRowValues> kits = new HashMap<String, SQLRowValues>();
    private List<String> codeKits = new ArrayList<String>();
    private SQLRowAccessor depot;
    private static String FAMILLE = "Famille";
    private static String CODE = "Code";
    private static String NOM = "Nom";
    private static String TAILLE = "Taille";
    private static String COULEUR = "Couleur";
    private static String QTE = "Qté réelle relevée";
    private static String QTE_OPENCONCERTO = "QTE OpenConcerto";
    private final Map<String, Integer> mapCouleur = new HashMap<String, Integer>();
    private final Map<String, Integer> mapTaille = new HashMap<String, Integer>();
    private final DBRoot root;
    private final SQLElement artElt;

    public InventaireFromEtatStockImporter(SQLElement articleElt, SQLRowAccessor depot) {
        this.depot = depot;
        this.root = articleElt.getTable().getDBRoot();
        this.artElt = articleElt;
        {
            SQLSelect sel = new SQLSelect();
            sel.addSelect(articleElt.getTable().getTable("ARTICLE_DECLINAISON_COULEUR").getKey());
            sel.addSelect(articleElt.getTable().getTable("ARTICLE_DECLINAISON_COULEUR").getField("NOM"));

            List<SQLRow> l = SQLRowListRSH.execute(sel);

            for (SQLRow sqlRow : l) {
                mapCouleur.put(sqlRow.getString("NOM").trim(), sqlRow.getID());
            }
        }

        {
            SQLSelect sel = new SQLSelect();
            sel.addSelect(articleElt.getTable().getTable("ARTICLE_DECLINAISON_TAILLE").getKey());
            sel.addSelect(articleElt.getTable().getTable("ARTICLE_DECLINAISON_TAILLE").getField("NOM"));

            List<SQLRow> l = SQLRowListRSH.execute(sel);

            for (SQLRow sqlRow : l) {
                mapTaille.put(sqlRow.getString("NOM").trim(), sqlRow.getID());
            }
        }
    }

    public void importArticles(File file, DBRoot root) throws IOException, SQLException {

        final SQLTable table = root.findTable("ARTICLE");
        final SQLTable tableArtElt = root.findTable("ARTICLE_ELEMENT");

        // Récupération des couples articles/stocks existant
        fillArticles();

        // Matching des colonnes
        Map<String, Integer> columnMapping = new HashMap<String, Integer>();
        columnMapping.put(CODE, null);
        columnMapping.put(NOM, null);
        columnMapping.put(TAILLE, null);
        columnMapping.put(FAMILLE, null);
        columnMapping.put(COULEUR, null);
        columnMapping.put(QTE, null);
        columnMapping.put(QTE_OPENCONCERTO, null);
        {
            // Searching column index from column Header
            final DataImporter importer = new DataImporter(table);
            importer.setSkipFirstLine(false);
            ArrayTableModel m = importer.createModelFrom(file);
            List<Object> line = m.getLineValuesAt(0);
            for (int i = 0; i < line.size(); i++) {
                Object object = line.get(i);
                if (object != null) {
                    for (String key : columnMapping.keySet()) {
                        if (object.toString().equalsIgnoreCase(key)) {
                            columnMapping.put(key, i);
                        }
                    }
                }
            }
        }

        String msg = "Colonnes importées : \n";
        final SQLPreferences prefs = SQLPreferences.getMemCached(table.getDBRoot());
        final boolean hasDeclinaison = prefs.getBoolean(GestionArticleGlobalPreferencePanel.ACTIVER_DECLINAISON, false);
        List<String> required;
        if (hasDeclinaison) {
            required = Arrays.asList(CODE, QTE, QTE_OPENCONCERTO, TAILLE, COULEUR);
        } else {
            required = Arrays.asList(CODE, QTE, QTE_OPENCONCERTO);
        }

        for (Entry<String, Integer> e : columnMapping.entrySet()) {
            if (e.getValue() != null) {
                msg += e.getKey() + " : " + getColumnName(e.getValue()) + "\n";
            } else {
                if (required.contains(e.getKey())) {
                    JOptionPane.showMessageDialog(null, "Aucune colonne " + e.getKey() + " trouvée, import annulé!\nCette colonne est obligatoire.");
                    return;
                }
                msg += e.getKey() + " : non importée\n";
            }
        }
        msg += "\nVoulez vous continuer ?";
        int a = JOptionPane.showConfirmDialog(null, msg);
        if (a == JOptionPane.YES_OPTION) {

            final DataImporter importer = new DataImporter(table) {
                @Override
                protected void customizeRowValuesToFetch(SQLRowValues vals) {

                    vals.putRowValues("ID_STOCK").putNulls("ID", "QTE_REEL", "QTE_TH", "ID_DEPOT_STOCK");
                }
            };
            importer.setSkipFirstLine(true);

            ArrayTableModel m = importer.createModelFrom(file);

            Calendar c = Calendar.getInstance();
            // c.set(Calendar.DAY_OF_MONTH, 1);
            // c.set(Calendar.MONTH, Calendar.JANUARY);
            // c.set(Calendar.HOUR_OF_DAY, 0);
            Date today = c.getTime();

            // TODO ne pas vider les stocks des kits, recalculer les stocks des kits

            SQLRowValues rowVals = new SQLRowValues(table.getTable("ETAT_STOCK"));
            rowVals.put("DATE", today);
            rowVals.put("INVENTAIRE", Boolean.TRUE);
            rowVals.put("ID_DEPOT_STOCK", this.depot.getID());
            SQLRow rowEtat = rowVals.commit();

            for (int i = 1; i < m.getRowCount(); i++) {
                List<Object> o = m.getLineValuesAt(i);
                if (o.size() >= 5) {
                    System.err.println(o);
                    String code = o.get(columnMapping.get(CODE)).toString();
                    if (code.trim().length() > 0) {

                        final String stringQty = o.get(columnMapping.get(QTE)).toString();
                        Double qty = stringQty.trim().length() == 0 ? 0 : Double.valueOf(stringQty);
                        final String stringQtyOld = o.get(columnMapping.get(QTE_OPENCONCERTO)).toString();
                        float qtyOld = stringQtyOld.trim().length() == 0 ? 0 : Float.valueOf(stringQtyOld);

                        String couleur = "";
                        if (columnMapping.get(COULEUR) != null) {
                            couleur = o.get(columnMapping.get(COULEUR)).toString();
                        }

                        String taille = "";
                        if (columnMapping.get(TAILLE) != null) {
                            taille = o.get(columnMapping.get(TAILLE)).toString();
                        }

                        // SQLRowAccessor match = findArticle(code, couleur, taille);

                        Tuple2<SQLRowValues, SQLRowValues> match = findArticle(code, couleur, taille);
                        if (match != null) {

                            SQLRowAccessor stockValues = match.get1();

                            final SQLTable tableMvt = table.getTable("MOUVEMENT_STOCK");
                            SQLRowValues rowValsMvtStockClotureFermeture = new SQLRowValues(tableMvt);
                            rowValsMvtStockClotureFermeture.put("QTE", -qtyOld);
                            rowValsMvtStockClotureFermeture.put("NOM", "Clôture stock avant inventaire");
                            rowValsMvtStockClotureFermeture.put("ID_ARTICLE", match.get0().getID());
                            rowValsMvtStockClotureFermeture.put("DATE", today);
                            rowValsMvtStockClotureFermeture.put("REEL", Boolean.TRUE);
                            rowValsMvtStockClotureFermeture.put("ID_STOCK", stockValues.getID());

                            BigDecimal prc = getPRC(match.get0(), Math.round(qtyOld), today);
                            if (prc == null) {
                                prc = BigDecimal.ZERO;
                            }
                            if (tableMvt.contains("PRICE")) {
                                rowValsMvtStockClotureFermeture.put("PRICE", prc);
                            }
                            rowValsMvtStockClotureFermeture.put("CLOTURE", Boolean.TRUE);
                            rowValsMvtStockClotureFermeture.put("ID_ETAT_STOCK", rowEtat.getID());
                            rowValsMvtStockClotureFermeture.getGraph().store(StoreMode.COMMIT, false);

                            SQLRowValues rowValsItem = new SQLRowValues(table.getTable("ETAT_STOCK_ELEMENT"));
                            rowValsItem.put("ID_ETAT_STOCK", rowEtat.getID());
                            rowValsItem.put("PA", prc);
                            rowValsItem.put("PV", BigDecimal.ZERO);
                            rowValsItem.put("QTE", qtyOld);
                            rowValsItem.put("T_PA", prc.multiply(new BigDecimal(qtyOld)));
                            rowValsItem.put("T_PV", BigDecimal.ZERO);
                            rowValsItem.put("CODE", match.get0().getString("CODE"));
                            rowValsItem.put("NOM", match.get0().getString("NOM"));
                            rowValsItem.put("ID_ARTICLE", match.get0().getID());
                            rowValsItem.getGraph().store(StoreMode.COMMIT, false);

                            SQLRowValues rowValsMvtStockClotureOuverture = new SQLRowValues(tableMvt);
                            rowValsMvtStockClotureOuverture.put("QTE", qty);
                            rowValsMvtStockClotureOuverture.put("NOM", "Mise en stock inventaire");
                            rowValsMvtStockClotureOuverture.put("ID_ETAT_STOCK", rowEtat.getID());
                            rowValsMvtStockClotureOuverture.put("ID_ARTICLE", match.get0().getID());
                            rowValsMvtStockClotureOuverture.put("DATE", today);
                            rowValsMvtStockClotureOuverture.put("REEL", Boolean.TRUE);
                            rowValsMvtStockClotureOuverture.put("ID_STOCK", stockValues.getID());
                            rowValsMvtStockClotureOuverture.put("OUVERTURE", Boolean.TRUE);
                            if (tableMvt.contains("PRICE")) {
                                rowValsMvtStockClotureOuverture.put("PRICE", getPRC(match.get0(), qty.intValue(), today));
                            }
                            rowValsMvtStockClotureOuverture.getGraph().store(StoreMode.COMMIT, false);

                            // if (!match.isForeignEmpty("ID_STOCK")) {
                            // match.getForeign("ID_STOCK").createEmptyUpdateRow().put("QTE_REEL",
                            // qty).commit();
                            // } else {
                            final SQLRowValues createEmptyUpdateRow = match.get1().createEmptyUpdateRow();
                            createEmptyUpdateRow.put("QTE_REEL", qty);
                            createEmptyUpdateRow.getGraph().store(StoreMode.COMMIT, false);

                            // }

                        } else {
                            System.err.println("Aucun article correspondant au code " + code);
                        }
                    }
                }
            }

            /**
             * Mise à jour des kits
             */

            List<String> reqs = new ArrayList<String>();
            for (String code : codeKits) {
                System.err.println(code);
                SQLRowValues rowValsKit = kits.get(code);
                StockItem item = new StockItem(rowValsKit, ProductComponent.findOrCreateStock(rowValsKit, depot));
                Collection<SQLRowValues> elts = rowValsKit.getReferentRows(tableArtElt.getField("ID_ARTICLE_PARENT"));
                for (SQLRowValues sqlRowValues : elts) {
                    if (sqlRowValues.getForeign("ID_ARTICLE") != null) {
                        item.addItemComponent(
                                new StockItemComponent(new StockItem(sqlRowValues.getForeign("ID_ARTICLE"), ProductComponent.findOrCreateStock(sqlRowValues.getForeign("ID_ARTICLE"), depot)),
                                        sqlRowValues.getBigDecimal("QTE_UNITAIRE"), sqlRowValues.getInt("QTE")));
                    }
                }
                item.updateQtyFromChildren();
                reqs.add(item.getUpdateRequest());
            }

            List<? extends ResultSetHandler> handlers = new ArrayList<ResultSetHandler>(reqs.size());
            for (String s : reqs) {
                handlers.add(null);
            }
            // FIXME FIRE TABLE CHANGED TO UPDATE ILISTE ??
            SQLUtils.executeMultiple(table.getDBSystemRoot(), reqs, handlers);

            /**
             * Mise à jour des prix mini
             */
            // for (SQLRowValues rowValsArt : rowValsArtNonSync) {
            // SQLRow rowArt = rowValsArt.asRow();
            // List<SQLRow> rowsPVMin =
            // rowArt.getReferentRows(tableArtElt.getTable("ARTICLE_PRIX_MIN_VENTE"));
            // List<SQLRow> rowsPA =
            // rowArt.getReferentRows(tableArtElt.getTable("ARTICLE_TARIF_FOURNISSEUR"));
            //
            // // On récupére les derniers prix min valides
            // Map<Integer, SQLRow> mapLastValidRows = new HashMap<Integer, SQLRow>();
            // for (SQLRow rowPVMin : rowsPVMin) {
            // final int qteMinPrice = rowPVMin.getInt("QTE");
            // SQLRow rowValsLastValid = mapLastValidRows.get(qteMinPrice);
            // if (rowValsLastValid == null || rowValsLastValid.getDate("DATE") == null ||
            // rowValsLastValid.getDate("DATE").before(rowPVMin.getDate("DATE"))) {
            // mapLastValidRows.put(qteMinPrice, rowPVMin);
            // }
            // }
            //
            // // On récupére les derniers Prix d'achat valide
            // Map<Integer, SQLRow> mapLastValidAchatRows = new HashMap<Integer, SQLRow>();
            // for (SQLRow rowPA : rowsPA) {
            // final int qtePRC = rowPA.getInt("QTE");
            // SQLRow rowValsLastValid = mapLastValidAchatRows.get(qtePRC);
            // if (rowValsLastValid == null || rowValsLastValid.getDate("DATE_PRIX") == null ||
            // rowValsLastValid.getDate("DATE_PRIX").before(rowPA.getDate("DATE_PRIX"))) {
            // mapLastValidAchatRows.put(qtePRC, rowPA);
            // }
            // }
            //
            // // Mise à jour, si Prix < au prix min, du PRC et des prix min
            // for (Integer qte : mapLastValidAchatRows.keySet()) {
            // SQLRow rowVals = mapLastValidAchatRows.get(qte);
            // checkMinPrice(rowVals, mapLastValidRows.get(qte));
            // }
            // }
        }
    }

    private void checkMinPrice(SQLRow rowValsSuplierLastValid, SQLRow lastValidRow) {
        boolean update = false;
        final ProductHelper helper = new ProductHelper(rowValsSuplierLastValid.getTable().getDBRoot());

        BigDecimal result = helper.getEnumPrice(rowValsSuplierLastValid, SupplierPriceField.COEF_PRIX_MINI);
        if (result != null) {
            final int qteSuplier = rowValsSuplierLastValid.getInt("QTE");

            final Calendar date2 = rowValsSuplierLastValid.getDate("DATE_PRIX");
            if (date2 != null) {
                if (lastValidRow != null) {
                    final Calendar date1 = lastValidRow.getDate("DATE");
                    if ((date1.get(Calendar.YEAR) == date2.get(Calendar.YEAR) && date1.get(Calendar.MONTH) == date2.get(Calendar.MONTH)
                            && date1.get(Calendar.DAY_OF_MONTH) == date2.get(Calendar.DAY_OF_MONTH)) || date1.after(date2)) {
                        if (lastValidRow.getBigDecimal("PRIX") != null && lastValidRow.getInt("QTE") <= qteSuplier) {
                            try {
                                lastValidRow.asRowValues().put("PRIX", result).commit();
                            } catch (SQLException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                            // purchaseMinPriceListTable.setPriceMin(result);
                            update = true;
                        }
                    } else {
                        if (date1.before(date2)) {
                            SQLRowValues rowValsToInsert = new SQLRowValues(lastValidRow.getTable());
                            rowValsToInsert.put("PRIX", result);
                            rowValsToInsert.put("DATE", rowValsSuplierLastValid.getObject("DATE_PRIX"));
                            rowValsToInsert.put("QTE", rowValsSuplierLastValid.getObject("QTE"));
                            rowValsToInsert.put("ID_ARTICLE", rowValsSuplierLastValid.getInt("ID_ARTICLE"));
                            try {
                                rowValsToInsert.commit();
                            } catch (SQLException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }

    }

    public BigDecimal getPRC(SQLRowValues rowVals, int qty, Date d) {
        // SQLTable table = rowVals.getTable().getDBRoot().getTable("ARTICLE_PRIX_REVIENT");
        // Collection<SQLRow> prcs = rowVals.asRow().getReferentRows(table);
        //
        // BigDecimal result = null;
        // final List<PriceByQty> prices = new ArrayList<PriceByQty>();
        //
        // for (SQLRow row : prcs) {
        // Calendar date = Calendar.getInstance();
        // date.set(Calendar.DAY_OF_MONTH, 1);
        // date.set(Calendar.MONTH, 1);
        // date.set(Calendar.YEAR, 2001);
        // if (row.getObject("DATE") != null) {
        // date = row.getDate("DATE");
        // }
        // prices.add(new PriceByQty(row.getLong("QTE"), row.getBigDecimal("PRIX"),
        // date.getTime()));
        // }
        //
        // result = PriceByQty.getPriceForQty(qty, prices, d);
        // if (result == null) {
        // // Can occur during editing
        // result = BigDecimal.ZERO;
        // }

        ProductComponent comp = new ProductComponent(rowVals, new BigDecimal(qty), null, null);
        return comp.getPRC(d);
        // return result;
    }

    private final Map<String, Tuple2<SQLRowValues, SQLRowValues>> mapArticle = new HashMap<String, Tuple2<SQLRowValues, SQLRowValues>>();
    private final Map<String, Tuple2<SQLRowValues, SQLRowValues>> mapArticleVirtuel = new HashMap<String, Tuple2<SQLRowValues, SQLRowValues>>();
    private final Map<Tuple3<String, String, String>, Tuple2<SQLRowValues, SQLRowValues>> mapDeclArticle = new HashMap<Tuple3<String, String, String>, Tuple2<SQLRowValues, SQLRowValues>>();

    private void fillArticles() throws SQLException {
        final SQLTable table = Configuration.getInstance().getRoot().findTable("ARTICLE");
        SQLRowValues graph = new SQLRowValues(table);
        graph.put("ID", null);
        graph.put("CODE", null);
        graph.put("NOM", null);
        graph.put("VIRTUEL", null);
        graph.putRowValues("ID_ARTICLE_DECLINAISON_COULEUR").putNulls("ID", "NOM");
        graph.putRowValues("ID_ARTICLE_DECLINAISON_TAILLE").putNulls("ID", "NOM");

        final SQLTable foreignTableStock = table.getForeignTable("ID_STOCK");
        SQLRowValues graphStock = new SQLRowValues(foreignTableStock);
        graphStock.putNulls("ID_DEPOT_STOCK", "ID", "QTE_REEL", "QTE_TH", "QTE_LIV_ATTENTE", "QTE_RECEPT_ATTENTE");
        graphStock.put("ID_ARTICLE", graph);

        SQLRowValues graphStockArt = new SQLRowValues(foreignTableStock);
        graphStockArt.putNulls("ID_DEPOT_STOCK", "ID", "QTE_REEL", "QTE_TH", "QTE_LIV_ATTENTE", "QTE_RECEPT_ATTENTE");
        graph.put("ID_STOCK", graphStockArt);

        final SQLTable tableArtElt = table.getTable("ARTICLE_ELEMENT");
        SQLRowValues artElt = new SQLRowValues(tableArtElt);
        artElt.put("ID", null);
        artElt.put("QTE", null);
        artElt.put("QTE_UNITAIRE", null);
        artElt.put("ID_ARTICLE_PARENT", graph);
        final SQLRowValues articleParent = artElt.putRowValues("ID_ARTICLE");
        articleParent.putNulls("ID", "CODE", "NOM", "VIRTUEL");
        articleParent.putRowValues("ID_ARTICLE_DECLINAISON_COULEUR").putNulls("ID", "NOM");
        articleParent.putRowValues("ID_ARTICLE_DECLINAISON_TAILLE").putNulls("ID", "NOM");

        SQLRowValues graphStockItem = new SQLRowValues(foreignTableStock);
        graphStockItem.put("ID_ARTICLE", articleParent);

        SQLRowValues graphStockArtItem = new SQLRowValues(foreignTableStock);
        graphStockArtItem.putNulls("ID_DEPOT_STOCK", "ID", "QTE_REEL", "QTE_TH", "QTE_LIV_ATTENTE", "QTE_RECEPT_ATTENTE");
        articleParent.put("ID_STOCK", graphStockArtItem);

        SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(graph);
        List<SQLRowValues> results = fetcher.fetch();

        Calendar c = Calendar.getInstance();
        // c.set(Calendar.DAY_OF_MONTH, 1);
        c.add(Calendar.MONTH, -2);
        c.set(Calendar.DAY_OF_MONTH, 31);
        Date dEndYear = c.getTime();

        for (SQLRowValues sqlRowValues : results) {
            final String code = sqlRowValues.getString("CODE");

            Collection<SQLRowValues> stocks = sqlRowValues.getReferentRows(foreignTableStock);

            SQLRowValues rowValsStock = null;
            for (SQLRowValues sqlRowValues2 : stocks) {
                if (sqlRowValues2.getForeignID("ID_DEPOT_STOCK") == depot.getID()) {
                    rowValsStock = sqlRowValues2;
                }
            }
            // if (rowValsStock == null) {
            // rowValsStock = ProductComponent.findOrCreateStock(sqlRowValues, depot).asRowValues();
            // }

            if (sqlRowValues.getBoolean("VIRTUEL")) {
                mapArticleVirtuel.put(sqlRowValues.getString("CODE"), Tuple2.create(sqlRowValues, rowValsStock));
            }

            final SQLRowAccessor couleur = sqlRowValues.getObject("ID_ARTICLE_DECLINAISON_COULEUR") == null ? null : sqlRowValues.getNonEmptyForeign("ID_ARTICLE_DECLINAISON_COULEUR");
            final SQLRowAccessor taille = sqlRowValues.getObject("ID_ARTICLE_DECLINAISON_TAILLE") == null ? null : sqlRowValues.getNonEmptyForeign("ID_ARTICLE_DECLINAISON_TAILLE");
            if (couleur == null && taille == null) {
                mapArticle.put(sqlRowValues.getString("CODE"), Tuple2.create(sqlRowValues, rowValsStock));
            } else if (couleur == null) {
                mapDeclArticle.put(Tuple3.create(sqlRowValues.getString("CODE"), null, taille.getString("NOM")), Tuple2.create(sqlRowValues, rowValsStock));
            } else if (taille == null) {
                mapDeclArticle.put(Tuple3.create(sqlRowValues.getString("CODE"), couleur.getString("NOM"), null), Tuple2.create(sqlRowValues, rowValsStock));
            } else {
                mapDeclArticle.put(Tuple3.create(sqlRowValues.getString("CODE"), couleur.getString("NOM"), taille.getString("NOM")), Tuple2.create(sqlRowValues, rowValsStock));
            }

            final Set<SQLRowValues> referentRows = sqlRowValues.getReferentRows(tableArtElt.getField("ID_ARTICLE_PARENT"));
            if (referentRows.size() == 0) {
                // if (!sqlRowValues.isForeignEmpty("ID_STOCK")) {
                // SQLRowAccessor rowValsStock = sqlRowValues.getForeign("ID_STOCK");
                // int qteReel = rowValsStock.getInt("QTE_REEL");
                // {
                // SQLRowValues rowValsMvtStockCloture = new
                // SQLRowValues(table.getTable("MOUVEMENT_STOCK"));
                // rowValsMvtStockCloture.put("QTE", -qteReel);
                // rowValsMvtStockCloture.put("NOM", "Clôture du stock avant inventaire");
                // rowValsMvtStockCloture.put("ID_ARTICLE", sqlRowValues.getID());
                // rowValsMvtStockCloture.put("DATE", dEndYear);
                // rowValsMvtStockCloture.put("REEL", Boolean.TRUE);
                // rowValsMvtStockCloture.put("PRICE", getPRC(sqlRowValues, qteReel, dEndYear));
                // rowValsMvtStockCloture.commit();
                //
                // rowValsStock.createEmptyUpdateRow().put("QTE_REEL", 0).commit();
                // }
                //
                // } else {
                // sqlRowValues.putRowValues("ID_STOCK").commit();
                // }
            } else {
                boolean contains = false;
                for (SQLRowValues sqlRowValues2 : referentRows) {
                    if (sqlRowValues2.getForeign("ID_ARTICLE") != null && !sqlRowValues2.isForeignEmpty("ID_ARTICLE") && sqlRowValues2.getForeign("ID_ARTICLE").getString("CODE") != null) {
                        if (codeKits.contains(sqlRowValues2.getForeign("ID_ARTICLE").getString("CODE"))) {
                            contains = true;
                            break;
                        }
                    }
                }
                if (!contains) {
                    codeKits.add(0, code);
                } else {
                    codeKits.add(code);
                }
                kits.put(code, sqlRowValues);
                // if (sqlRowValues.isForeignEmpty("ID_STOCK")) {
                // sqlRowValues.putRowValues("ID_STOCK").commit();
                // }
            }
        }
    }

    private Tuple2<SQLRowValues, SQLRowValues> findArticle(String code, String couleur, String taille) throws SQLException {
        if (!mapCouleur.containsKey(couleur)) {
            SQLRowValues rowVals = new SQLRowValues(root.getTable("ARTICLE_DECLINAISON_COULEUR"));
            rowVals.put("NOM", couleur);
            mapCouleur.put(couleur, rowVals.commit().getID());
        }
        if (!mapTaille.containsKey(taille)) {
            SQLRowValues rowVals = new SQLRowValues(root.getTable("ARTICLE_DECLINAISON_TAILLE"));
            rowVals.put("NOM", taille);
            mapTaille.put(taille, rowVals.commit().getID());
        }

        Tuple2<SQLRowValues, SQLRowValues> t;
        if ((couleur == null || couleur.trim().length() == 0) && (taille == null || taille.trim().length() == 0)) {

            t = mapArticle.get(code);
            if (t.get1() == null) {
                t = Tuple2.create(t.get0(), ProductComponent.findOrCreateStock(t.get0(), depot).asRowValues());
                mapArticle.put(code, t);
            }
        } else if (couleur == null || couleur.trim().length() == 0) {
            t = mapDeclArticle.get(Tuple3.create(code, null, taille.trim()));
            if (t == null) {
                SQLRowValues artRow = cloneFromArticle(mapArticleVirtuel.get(code).get0(), null, mapTaille.get(taille.trim())).asRowValues();
                final SQLRowValues stockRow = ProductComponent.findOrCreateStock(artRow, depot).asRowValues();
                t = Tuple2.create(artRow, stockRow);
                mapDeclArticle.put(Tuple3.create(code, null, taille.trim()), t);
            } else if (t.get1() == null) {
                t = Tuple2.create(t.get0(), ProductComponent.findOrCreateStock(t.get0(), depot).asRowValues());
                mapDeclArticle.put(Tuple3.create(code, null, taille.trim()), t);
            }
        } else if (taille == null || taille.trim().length() == 0) {
            t = mapDeclArticle.get(Tuple3.create(code, couleur.trim(), null));
            if (t == null) {
                SQLRowValues artRow = cloneFromArticle(mapArticleVirtuel.get(code).get0(), mapCouleur.get(couleur.trim()), null).asRowValues();
                final SQLRowValues stockRow = ProductComponent.findOrCreateStock(artRow, depot).asRowValues();
                t = Tuple2.create(artRow, stockRow);
                mapDeclArticle.put(Tuple3.create(code, couleur.trim(), null), t);
            } else if (t.get1() == null) {
                t = Tuple2.create(t.get0(), ProductComponent.findOrCreateStock(t.get0(), depot).asRowValues());
                mapDeclArticle.put(Tuple3.create(code, couleur.trim(), null), t);
            }
        } else {
            t = mapDeclArticle.get(Tuple3.create(code, couleur.trim(), taille.trim()));
            if (t == null) {
                if (mapArticle.get(code) != null) {
                    SQLRowValues artRow = cloneFromArticle(mapArticleVirtuel.get(code).get0(), mapCouleur.get(couleur.trim()), mapTaille.get(taille.trim())).asRowValues();
                    final SQLRowValues stockRow = ProductComponent.findOrCreateStock(artRow, depot).asRowValues();
                    t = Tuple2.create(artRow, stockRow);
                    mapDeclArticle.put(Tuple3.create(code, couleur.trim(), taille.trim()), t);
                }
            } else if (t.get1() == null) {
                t = Tuple2.create(t.get0(), ProductComponent.findOrCreateStock(t.get0(), depot).asRowValues());
                mapDeclArticle.put(Tuple3.create(code, couleur.trim(), taille.trim()), t);
            }
        }
        return t;
    }

    public SQLRow cloneFromArticle(SQLRowAccessor rArt, Integer idCouleur, Integer idTaille) throws SQLException {
        if (rArt == null) {
            return null;
        }
        SQLRowValues copy = artElt.createCopy(rArt.getID());
        copy.put("VIRTUEL", Boolean.FALSE);
        copy.put("ID_ARTICLE_VIRTUEL_PERE", rArt.getID());
        if (idCouleur != null) {
            copy.put("ID_ARTICLE_DECLINAISON_COULEUR", idCouleur);
        }
        if (idTaille != null) {
            copy.put("ID_ARTICLE_DECLINAISON_TAILLE", idTaille);
        }
        return copy.commit();
    }

    private String getColumnName(int columnNumber) {
        int dividend = columnNumber;
        String columnName = "";
        int modulo;

        while (dividend >= 0) {
            modulo = dividend % 26;
            columnName = String.valueOf((char) (65 + modulo)) + columnName;
            dividend = (int) ((dividend - modulo) / 26);
            if (dividend <= 0) {
                break;
            } else {
                dividend--;
            }
        }

        return columnName;
    }
}