OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2011 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.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSelectJoin;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.SQLTableEvent;
import org.openconcerto.sql.model.SQLTableEvent.Mode;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.ITransformer;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.dbutils.ResultSetHandler;

public class ComposedItemStockUpdater {

    private final List<StockItem> itemsUpdated;
    private final DBRoot root;

    /// FIXME mettre à jour les stocks des kits à partir des feuilles

    /**
     * Met à jour les stocks des nomenclature composé par un des articles de itemsUpdated
     * 
     * @param root
     * @param itemsUpdated liste des StockItem non composés qui ont été mis à jour
     */
    public ComposedItemStockUpdater(DBRoot root, List<StockItem> itemsUpdated) {
        this.itemsUpdated = itemsUpdated;
        this.root = root;
    }

    /**
     * Mise à jour des stocks en fonction des composants de l'article
     * 
     * @throws SQLException
     */
    public void update() throws SQLException {
        // Liste des nomenclatures dépendantes des itemsUpdated
        List<StockItem> items = getAllComposedItemToUpdate();
        updateNomenclature(items);
    }

    public void updateNomenclature(List<StockItem> items) throws SQLException {

        // Fecth des articles liés
        getAllChildren(items);

        List<StockItem> removedBadItem = new ArrayList<>();
        // Mise à jour des stocks
        for (StockItem stockItem : items) {
            if (!stockItem.updateQtyFromChildren()) {
                removedBadItem.add(stockItem);
            }
        }
        items.removeAll(removedBadItem);

        SQLTable stockTable = root.getTable("STOCK");
        List<String> requests = new ArrayList<String>();
        for (StockItem stockItem : items) {
            if (stockItem.isStockInit()) {
                UpdateBuilder update = new UpdateBuilder(stockTable);
                update.setWhere(new Where(stockTable.getKey(), "=", stockItem.stock.getID()));
                update.setObject("QTE_REEL", stockItem.getRealQty());
                update.setObject("QTE_TH", stockItem.getVirtualQty());
                update.setObject("QTE_LIV_ATTENTE", stockItem.getDeliverQty());
                update.setObject("QTE_RECEPT_ATTENTE", stockItem.getReceiptQty());
                requests.add(update.asString());
            } else {
                SQLRowValues rowVals = new SQLRowValues(stockTable);
                rowVals.put("QTE_REEL", stockItem.getRealQty());
                rowVals.put("QTE_TH", stockItem.getVirtualQty());
                rowVals.put("QTE_LIV_ATTENTE", stockItem.getDeliverQty());
                rowVals.put("QTE_RECEPT_ATTENTE", stockItem.getReceiptQty());
                rowVals.put("ID_ARTICLE", stockItem.getArticle().getID());
                rowVals.put("ID_DEPOT_STOCK", stockItem.stock.getForeignID("ID_DEPOT_STOCK"));
                rowVals.commit();
                if (stockItem.getArticle().getForeignID("ID_DEPOT_STOCK") == stockItem.stock.getForeignID("ID_DEPOT_STOCK")) {
                    SQLRowValues rowValsArt = stockItem.getArticle().createEmptyUpdateRow();
                    rowValsArt.put("ID_STOCK", rowVals);
                    rowValsArt.commit();
                }
            }
        }

        List<? extends ResultSetHandler> handlers = new ArrayList<ResultSetHandler>(requests.size());
        for (String s : requests) {
            handlers.add(null);
        }

        SQLUtils.executeMultiple(stockTable.getDBSystemRoot(), requests, handlers);
        stockTable.fire(new SQLTableEvent(stockTable, SQLRow.NONEXISTANT_ID, Mode.ROW_UPDATED));
    }

    /**
     * Associe les StockItems liés aux items passés en parametres
     * 
     * @param items liste des stockitems d'article composé
     */
    private void getAllChildren(List<StockItem> items) {
        final SQLTable tableArticle = this.root.getTable("ARTICLE");
        final int undefDepot = tableArticle.getTable("DEPOT_STOCK").getUndefinedID();
        final SQLRowValues rowValsArt = new SQLRowValues(tableArticle);
        rowValsArt.put(tableArticle.getKey().getName(), null);

        SQLRowValues rowValsStock = new SQLRowValues(this.root.getTable("STOCK"));
        rowValsStock.put("QTE_REEL", null);
        rowValsStock.put("QTE_TH", null);
        rowValsStock.put("QTE_RECEPT_ATTENTE", null);
        rowValsStock.put("QTE_LIV_ATTENTE", null);
        rowValsStock.put("ID_DEPOT_STOCK", null);
        rowValsStock.put("ID_ARTICLE", rowValsArt);

        final SQLTable tableArticleElt = this.root.getTable("ARTICLE_ELEMENT");
        SQLRowValues rowValsArtItem = new SQLRowValues(tableArticleElt);
        rowValsArtItem.put("ID_ARTICLE", rowValsArt);
        rowValsArtItem.put("QTE", null);
        rowValsArtItem.put("QTE_UNITAIRE", null);
        rowValsArtItem.put("ID_ARTICLE_PARENT", null);

        final List<Integer> ids = new ArrayList<Integer>();
        Map<Tuple2<Integer, Integer>, StockItem> mapItem = new HashMap<Tuple2<Integer, Integer>, StockItem>();
        for (StockItem stockItem : items) {
            final int id = stockItem.getArticle().getID();
            ids.add(id);
            if (stockItem.stock.getForeignID("ID_DEPOT_STOCK") != undefDepot) {
                mapItem.put(Tuple2.create(id, stockItem.stock.getForeignID("ID_DEPOT_STOCK")), stockItem);
            }
        }

        SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowValsArtItem);
        fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {

            @Override
            public SQLSelect transformChecked(SQLSelect input) {
                Where w = new Where(tableArticleElt.getField("ID_ARTICLE_PARENT"), ids);
                input.setWhere(w);
                return input;
            }
        });

        List<SQLRowValues> values = fetcher.fetch();
        for (SQLRowValues sqlRowValues : values) {

            final SQLRowAccessor article = sqlRowValues.getForeign("ID_ARTICLE");
            final SQLRowAccessor articleParent = sqlRowValues.getForeign("ID_ARTICLE_PARENT");
            if (article != null && !article.isUndefined()) {
                final Collection<? extends SQLRowAccessor> referentStockRows = article.getReferentRows(this.root.getTable("STOCK"));

                {
                    // Init Stock if no depot
                    if (referentStockRows.size() == 0) {
                        // init default stock depot
                        SQLRowValues rowVals = new SQLRowValues(article.getTable().getTable("STOCK"));
                        rowVals.put("ID_ARTICLE", article.getID());
                        rowVals.put("ID_DEPOT_STOCK", DepotStockSQLElement.DEFAULT_ID);
                        try {
                            SQLRow rowStock = rowVals.commit();
                            article.createEmptyUpdateRow().put("ID_STOCK", rowStock.getID()).commit();

                            System.err.println("NO DEPOT STOCK FOR ITEM " + articleParent.getID() + " -- PARENT " + articleParent.getID());
                            StockItem stockItem = mapItem.get(Tuple2.create(articleParent.getID(), DepotStockSQLElement.DEFAULT_ID));
                            if (stockItem != null) {
                                stockItem.addItemComponent(new StockItemComponent(new StockItem(article, rowStock), sqlRowValues.getBigDecimal("QTE_UNITAIRE"), sqlRowValues.getInt("QTE")));
                            } else {
                                System.err.println("Unable to find stock of item ARTICLE " + articleParent.getID() + " DEPOT " + DepotStockSQLElement.DEFAULT_ID);
                            }
                        } catch (SQLException e) {
                            ExceptionHandler.handle("Erreur lors de l'initialisation du stock de l'article", e);
                        }
                    }
                }

                for (SQLRowAccessor sqlRowAccessor : referentStockRows) {
                    StockItem stockItem = mapItem.get(Tuple2.create(articleParent.getID(), sqlRowAccessor.getForeignID("ID_DEPOT_STOCK")));
                    if (stockItem != null) {
                        stockItem.addItemComponent(new StockItemComponent(new StockItem(article, sqlRowAccessor), sqlRowValues.getBigDecimal("QTE_UNITAIRE"), sqlRowValues.getInt("QTE")));
                    } else if (sqlRowAccessor.getForeignID("ID_DEPOT_STOCK") == sqlRowAccessor.getTable().getForeignTable("ID_DEPOT_STOCK").getUndefinedID()) {
                        stockItem = mapItem.get(Tuple2.create(articleParent.getID(), DepotStockSQLElement.DEFAULT_ID));
                        stockItem.addItemComponent(new StockItemComponent(new StockItem(article, sqlRowAccessor), sqlRowValues.getBigDecimal("QTE_UNITAIRE"), sqlRowValues.getInt("QTE")));
                    } else {
                        System.err.println("Unable to find stock of item ARTICLE " + articleParent.getID() + " DEPOT " + sqlRowAccessor.getForeignID("ID_DEPOT_STOCK"));
                    }
                }
            }
        }
    }

    /**
     * @return l'ensemble des stockItems composés à mettre à jour
     */
    private List<StockItem> getAllComposedItemToUpdate() {
        // Liste des ids des artciles non composé mis à jour
        Set<Integer> ids = new HashSet<Integer>(itemsUpdated.size());
        for (StockItem stockItem : itemsUpdated) {
            ids.add(stockItem.getArticle().getID());
        }
        // Liste des nomenclatures dépendantes des itemsUpdated
        List<SQLRowValues> list = getComposedItemToUpdate(ids);
        int size = list.size();

        Map<Integer, SQLRowValues> result = new HashMap<Integer, SQLRowValues>(ids.size());
        for (SQLRowValues sqlRowValues : list) {
            result.put(sqlRowValues.getID(), sqlRowValues);
        }
        // Liste des nomenclatures dépendantes des nomenclatures (kit dans kits)
        while (size > 0) {

            List<SQLRowValues> l = getComposedItemToUpdate(ids);
            for (SQLRowValues sqlRowValues : l) {
                result.put(sqlRowValues.getID(), sqlRowValues);
            }
            size = l.size();
            if (size > 0) {
                ids.clear();
                for (SQLRowValues r : l) {
                    ids.add(r.getForeignID("ID_ARTICLE"));
                }
            }
        }

        List<StockItem> items = new ArrayList<StockItem>(result.size());
        for (SQLRowValues rowVals : result.values()) {

            StockItem item = new StockItem(rowVals.getForeign("ID_ARTICLE"), rowVals);
            items.add(item);
        }
        return items;
    }

    /**
     * 
     * @param ids
     * @return l'ensemble des Articles composés avec un des articles en parametres
     */
    private List<SQLRowValues> getComposedItemToUpdate(final Set<Integer> ids) {

        final SQLTable tableArticle = this.root.getTable("ARTICLE");
        final SQLRowValues rowValsArt = new SQLRowValues(tableArticle);
        rowValsArt.put(tableArticle.getKey().getName(), null);

        SQLRowValues rowValsStock = new SQLRowValues(this.root.getTable("STOCK"));
        rowValsStock.put("QTE_REEL", null);
        rowValsStock.put("QTE_TH", null);
        rowValsStock.put("QTE_RECEPT_ATTENTE", null);
        rowValsStock.put("QTE_LIV_ATTENTE", null);
        rowValsStock.put("ID_ARTICLE", rowValsArt);
        rowValsStock.put("ID_DEPOT_STOCK", null);

        final SQLTable tableArticleElt = this.root.getTable("ARTICLE_ELEMENT");
        // SQLRowValues rowValsArtItem = new SQLRowValues(tableArticleElt);
        // rowValsArtItem.put("ID_ARTICLE_PARENT", rowValsArt);
        // rowValsArtItem.put("QTE", null);
        // rowValsArtItem.put("QTE_UNITAIRE", null);

        SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowValsStock);
        fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {

            @Override
            public SQLSelect transformChecked(SQLSelect input) {
                SQLSelectJoin joinFromField = input.addJoin("RIGHT", tableArticleElt, new Where(tableArticleElt.getField("ID_ARTICLE_PARENT"), "=", input.getTable("STOCK").getField("ID_ARTICLE")));
                Where w = new Where(joinFromField.getJoinedTable().getField("ID_ARTICLE"), ids);
                joinFromField.setWhere(w);
                input.clearOrder();
                input.setDistinct(true);
                return input;
            }
        });

        return fetcher.fetch();
    }
}