83 |
ilm |
1 |
/*
|
|
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
|
|
3 |
*
|
|
|
4 |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
|
|
|
5 |
*
|
|
|
6 |
* The contents of this file are subject to the terms of the GNU General Public License Version 3
|
|
|
7 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
|
|
|
8 |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
|
|
|
9 |
* language governing permissions and limitations under the License.
|
|
|
10 |
*
|
|
|
11 |
* When distributing the software, include this License Header Notice in each file.
|
|
|
12 |
*/
|
|
|
13 |
|
|
|
14 |
package org.openconcerto.erp.core.supplychain.stock.element;
|
|
|
15 |
|
|
|
16 |
import org.openconcerto.sql.model.DBRoot;
|
156 |
ilm |
17 |
import org.openconcerto.sql.model.SQLRow;
|
83 |
ilm |
18 |
import org.openconcerto.sql.model.SQLRowAccessor;
|
|
|
19 |
import org.openconcerto.sql.model.SQLRowValues;
|
|
|
20 |
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
|
|
|
21 |
import org.openconcerto.sql.model.SQLSelect;
|
|
|
22 |
import org.openconcerto.sql.model.SQLSelectJoin;
|
|
|
23 |
import org.openconcerto.sql.model.SQLTable;
|
180 |
ilm |
24 |
import org.openconcerto.sql.model.SQLTableEvent;
|
|
|
25 |
import org.openconcerto.sql.model.SQLTableEvent.Mode;
|
83 |
ilm |
26 |
import org.openconcerto.sql.model.Where;
|
|
|
27 |
import org.openconcerto.sql.request.UpdateBuilder;
|
|
|
28 |
import org.openconcerto.sql.utils.SQLUtils;
|
156 |
ilm |
29 |
import org.openconcerto.utils.ExceptionHandler;
|
|
|
30 |
import org.openconcerto.utils.Tuple2;
|
83 |
ilm |
31 |
import org.openconcerto.utils.cc.ITransformer;
|
|
|
32 |
|
|
|
33 |
import java.sql.SQLException;
|
|
|
34 |
import java.util.ArrayList;
|
156 |
ilm |
35 |
import java.util.Collection;
|
83 |
ilm |
36 |
import java.util.HashMap;
|
93 |
ilm |
37 |
import java.util.HashSet;
|
83 |
ilm |
38 |
import java.util.List;
|
|
|
39 |
import java.util.Map;
|
93 |
ilm |
40 |
import java.util.Set;
|
83 |
ilm |
41 |
|
|
|
42 |
import org.apache.commons.dbutils.ResultSetHandler;
|
|
|
43 |
|
|
|
44 |
public class ComposedItemStockUpdater {
|
|
|
45 |
|
|
|
46 |
private final List<StockItem> itemsUpdated;
|
|
|
47 |
private final DBRoot root;
|
|
|
48 |
|
156 |
ilm |
49 |
/// FIXME mettre à jour les stocks des kits à partir des feuilles
|
|
|
50 |
|
83 |
ilm |
51 |
/**
|
93 |
ilm |
52 |
* Met à jour les stocks des nomenclature composé par un des articles de itemsUpdated
|
83 |
ilm |
53 |
*
|
|
|
54 |
* @param root
|
|
|
55 |
* @param itemsUpdated liste des StockItem non composés qui ont été mis à jour
|
|
|
56 |
*/
|
|
|
57 |
public ComposedItemStockUpdater(DBRoot root, List<StockItem> itemsUpdated) {
|
|
|
58 |
this.itemsUpdated = itemsUpdated;
|
|
|
59 |
this.root = root;
|
|
|
60 |
}
|
|
|
61 |
|
|
|
62 |
/**
|
|
|
63 |
* Mise à jour des stocks en fonction des composants de l'article
|
|
|
64 |
*
|
|
|
65 |
* @throws SQLException
|
|
|
66 |
*/
|
|
|
67 |
public void update() throws SQLException {
|
142 |
ilm |
68 |
// Liste des nomenclatures dépendantes des itemsUpdated
|
83 |
ilm |
69 |
List<StockItem> items = getAllComposedItemToUpdate();
|
156 |
ilm |
70 |
updateNomenclature(items);
|
|
|
71 |
}
|
83 |
ilm |
72 |
|
156 |
ilm |
73 |
public void updateNomenclature(List<StockItem> items) throws SQLException {
|
|
|
74 |
|
83 |
ilm |
75 |
// Fecth des articles liés
|
|
|
76 |
getAllChildren(items);
|
|
|
77 |
|
156 |
ilm |
78 |
List<StockItem> removedBadItem = new ArrayList<>();
|
83 |
ilm |
79 |
// Mise à jour des stocks
|
|
|
80 |
for (StockItem stockItem : items) {
|
156 |
ilm |
81 |
if (!stockItem.updateQtyFromChildren()) {
|
|
|
82 |
removedBadItem.add(stockItem);
|
|
|
83 |
}
|
83 |
ilm |
84 |
}
|
156 |
ilm |
85 |
items.removeAll(removedBadItem);
|
83 |
ilm |
86 |
|
|
|
87 |
SQLTable stockTable = root.getTable("STOCK");
|
|
|
88 |
List<String> requests = new ArrayList<String>();
|
|
|
89 |
for (StockItem stockItem : items) {
|
|
|
90 |
if (stockItem.isStockInit()) {
|
|
|
91 |
UpdateBuilder update = new UpdateBuilder(stockTable);
|
156 |
ilm |
92 |
update.setWhere(new Where(stockTable.getKey(), "=", stockItem.stock.getID()));
|
83 |
ilm |
93 |
update.setObject("QTE_REEL", stockItem.getRealQty());
|
|
|
94 |
update.setObject("QTE_TH", stockItem.getVirtualQty());
|
|
|
95 |
update.setObject("QTE_LIV_ATTENTE", stockItem.getDeliverQty());
|
|
|
96 |
update.setObject("QTE_RECEPT_ATTENTE", stockItem.getReceiptQty());
|
|
|
97 |
requests.add(update.asString());
|
|
|
98 |
} else {
|
|
|
99 |
SQLRowValues rowVals = new SQLRowValues(stockTable);
|
|
|
100 |
rowVals.put("QTE_REEL", stockItem.getRealQty());
|
|
|
101 |
rowVals.put("QTE_TH", stockItem.getVirtualQty());
|
|
|
102 |
rowVals.put("QTE_LIV_ATTENTE", stockItem.getDeliverQty());
|
|
|
103 |
rowVals.put("QTE_RECEPT_ATTENTE", stockItem.getReceiptQty());
|
156 |
ilm |
104 |
rowVals.put("ID_ARTICLE", stockItem.getArticle().getID());
|
|
|
105 |
rowVals.put("ID_DEPOT_STOCK", stockItem.stock.getForeignID("ID_DEPOT_STOCK"));
|
|
|
106 |
rowVals.commit();
|
|
|
107 |
if (stockItem.getArticle().getForeignID("ID_DEPOT_STOCK") == stockItem.stock.getForeignID("ID_DEPOT_STOCK")) {
|
|
|
108 |
SQLRowValues rowValsArt = stockItem.getArticle().createEmptyUpdateRow();
|
|
|
109 |
rowValsArt.put("ID_STOCK", rowVals);
|
|
|
110 |
rowValsArt.commit();
|
|
|
111 |
}
|
83 |
ilm |
112 |
}
|
|
|
113 |
}
|
|
|
114 |
|
|
|
115 |
List<? extends ResultSetHandler> handlers = new ArrayList<ResultSetHandler>(requests.size());
|
|
|
116 |
for (String s : requests) {
|
|
|
117 |
handlers.add(null);
|
|
|
118 |
}
|
180 |
ilm |
119 |
|
83 |
ilm |
120 |
SQLUtils.executeMultiple(stockTable.getDBSystemRoot(), requests, handlers);
|
180 |
ilm |
121 |
stockTable.fire(new SQLTableEvent(stockTable, SQLRow.NONEXISTANT_ID, Mode.ROW_UPDATED));
|
83 |
ilm |
122 |
}
|
|
|
123 |
|
|
|
124 |
/**
|
|
|
125 |
* Associe les StockItems liés aux items passés en parametres
|
|
|
126 |
*
|
|
|
127 |
* @param items liste des stockitems d'article composé
|
|
|
128 |
*/
|
|
|
129 |
private void getAllChildren(List<StockItem> items) {
|
|
|
130 |
final SQLTable tableArticle = this.root.getTable("ARTICLE");
|
156 |
ilm |
131 |
final int undefDepot = tableArticle.getTable("DEPOT_STOCK").getUndefinedID();
|
83 |
ilm |
132 |
final SQLRowValues rowValsArt = new SQLRowValues(tableArticle);
|
|
|
133 |
rowValsArt.put(tableArticle.getKey().getName(), null);
|
|
|
134 |
|
156 |
ilm |
135 |
SQLRowValues rowValsStock = new SQLRowValues(this.root.getTable("STOCK"));
|
83 |
ilm |
136 |
rowValsStock.put("QTE_REEL", null);
|
|
|
137 |
rowValsStock.put("QTE_TH", null);
|
|
|
138 |
rowValsStock.put("QTE_RECEPT_ATTENTE", null);
|
|
|
139 |
rowValsStock.put("QTE_LIV_ATTENTE", null);
|
156 |
ilm |
140 |
rowValsStock.put("ID_DEPOT_STOCK", null);
|
|
|
141 |
rowValsStock.put("ID_ARTICLE", rowValsArt);
|
83 |
ilm |
142 |
|
|
|
143 |
final SQLTable tableArticleElt = this.root.getTable("ARTICLE_ELEMENT");
|
|
|
144 |
SQLRowValues rowValsArtItem = new SQLRowValues(tableArticleElt);
|
|
|
145 |
rowValsArtItem.put("ID_ARTICLE", rowValsArt);
|
|
|
146 |
rowValsArtItem.put("QTE", null);
|
|
|
147 |
rowValsArtItem.put("QTE_UNITAIRE", null);
|
|
|
148 |
rowValsArtItem.put("ID_ARTICLE_PARENT", null);
|
|
|
149 |
|
|
|
150 |
final List<Integer> ids = new ArrayList<Integer>();
|
156 |
ilm |
151 |
Map<Tuple2<Integer, Integer>, StockItem> mapItem = new HashMap<Tuple2<Integer, Integer>, StockItem>();
|
83 |
ilm |
152 |
for (StockItem stockItem : items) {
|
|
|
153 |
final int id = stockItem.getArticle().getID();
|
|
|
154 |
ids.add(id);
|
156 |
ilm |
155 |
if (stockItem.stock.getForeignID("ID_DEPOT_STOCK") != undefDepot) {
|
|
|
156 |
mapItem.put(Tuple2.create(id, stockItem.stock.getForeignID("ID_DEPOT_STOCK")), stockItem);
|
|
|
157 |
}
|
83 |
ilm |
158 |
}
|
|
|
159 |
|
|
|
160 |
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowValsArtItem);
|
|
|
161 |
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
|
|
|
162 |
|
|
|
163 |
@Override
|
|
|
164 |
public SQLSelect transformChecked(SQLSelect input) {
|
|
|
165 |
Where w = new Where(tableArticleElt.getField("ID_ARTICLE_PARENT"), ids);
|
|
|
166 |
input.setWhere(w);
|
|
|
167 |
return input;
|
|
|
168 |
}
|
|
|
169 |
});
|
|
|
170 |
|
|
|
171 |
List<SQLRowValues> values = fetcher.fetch();
|
|
|
172 |
for (SQLRowValues sqlRowValues : values) {
|
|
|
173 |
|
|
|
174 |
final SQLRowAccessor article = sqlRowValues.getForeign("ID_ARTICLE");
|
|
|
175 |
final SQLRowAccessor articleParent = sqlRowValues.getForeign("ID_ARTICLE_PARENT");
|
156 |
ilm |
176 |
if (article != null && !article.isUndefined()) {
|
|
|
177 |
final Collection<? extends SQLRowAccessor> referentStockRows = article.getReferentRows(this.root.getTable("STOCK"));
|
|
|
178 |
|
|
|
179 |
{
|
|
|
180 |
// Init Stock if no depot
|
|
|
181 |
if (referentStockRows.size() == 0) {
|
|
|
182 |
// init default stock depot
|
|
|
183 |
SQLRowValues rowVals = new SQLRowValues(article.getTable().getTable("STOCK"));
|
|
|
184 |
rowVals.put("ID_ARTICLE", article.getID());
|
|
|
185 |
rowVals.put("ID_DEPOT_STOCK", DepotStockSQLElement.DEFAULT_ID);
|
|
|
186 |
try {
|
|
|
187 |
SQLRow rowStock = rowVals.commit();
|
|
|
188 |
article.createEmptyUpdateRow().put("ID_STOCK", rowStock.getID()).commit();
|
|
|
189 |
|
|
|
190 |
System.err.println("NO DEPOT STOCK FOR ITEM " + articleParent.getID() + " -- PARENT " + articleParent.getID());
|
|
|
191 |
StockItem stockItem = mapItem.get(Tuple2.create(articleParent.getID(), DepotStockSQLElement.DEFAULT_ID));
|
|
|
192 |
if (stockItem != null) {
|
|
|
193 |
stockItem.addItemComponent(new StockItemComponent(new StockItem(article, rowStock), sqlRowValues.getBigDecimal("QTE_UNITAIRE"), sqlRowValues.getInt("QTE")));
|
|
|
194 |
} else {
|
|
|
195 |
System.err.println("Unable to find stock of item ARTICLE " + articleParent.getID() + " DEPOT " + DepotStockSQLElement.DEFAULT_ID);
|
|
|
196 |
}
|
|
|
197 |
} catch (SQLException e) {
|
|
|
198 |
ExceptionHandler.handle("Erreur lors de l'initialisation du stock de l'article", e);
|
|
|
199 |
}
|
|
|
200 |
}
|
|
|
201 |
}
|
|
|
202 |
|
|
|
203 |
for (SQLRowAccessor sqlRowAccessor : referentStockRows) {
|
|
|
204 |
StockItem stockItem = mapItem.get(Tuple2.create(articleParent.getID(), sqlRowAccessor.getForeignID("ID_DEPOT_STOCK")));
|
|
|
205 |
if (stockItem != null) {
|
|
|
206 |
stockItem.addItemComponent(new StockItemComponent(new StockItem(article, sqlRowAccessor), sqlRowValues.getBigDecimal("QTE_UNITAIRE"), sqlRowValues.getInt("QTE")));
|
|
|
207 |
} else if (sqlRowAccessor.getForeignID("ID_DEPOT_STOCK") == sqlRowAccessor.getTable().getForeignTable("ID_DEPOT_STOCK").getUndefinedID()) {
|
|
|
208 |
stockItem = mapItem.get(Tuple2.create(articleParent.getID(), DepotStockSQLElement.DEFAULT_ID));
|
|
|
209 |
stockItem.addItemComponent(new StockItemComponent(new StockItem(article, sqlRowAccessor), sqlRowValues.getBigDecimal("QTE_UNITAIRE"), sqlRowValues.getInt("QTE")));
|
|
|
210 |
} else {
|
|
|
211 |
System.err.println("Unable to find stock of item ARTICLE " + articleParent.getID() + " DEPOT " + sqlRowAccessor.getForeignID("ID_DEPOT_STOCK"));
|
|
|
212 |
}
|
|
|
213 |
}
|
|
|
214 |
}
|
83 |
ilm |
215 |
}
|
|
|
216 |
}
|
|
|
217 |
|
|
|
218 |
/**
|
|
|
219 |
* @return l'ensemble des stockItems composés à mettre à jour
|
|
|
220 |
*/
|
|
|
221 |
private List<StockItem> getAllComposedItemToUpdate() {
|
93 |
ilm |
222 |
// Liste des ids des artciles non composé mis à jour
|
|
|
223 |
Set<Integer> ids = new HashSet<Integer>(itemsUpdated.size());
|
83 |
ilm |
224 |
for (StockItem stockItem : itemsUpdated) {
|
|
|
225 |
ids.add(stockItem.getArticle().getID());
|
|
|
226 |
}
|
142 |
ilm |
227 |
// Liste des nomenclatures dépendantes des itemsUpdated
|
83 |
ilm |
228 |
List<SQLRowValues> list = getComposedItemToUpdate(ids);
|
|
|
229 |
int size = list.size();
|
|
|
230 |
|
93 |
ilm |
231 |
Map<Integer, SQLRowValues> result = new HashMap<Integer, SQLRowValues>(ids.size());
|
|
|
232 |
for (SQLRowValues sqlRowValues : list) {
|
|
|
233 |
result.put(sqlRowValues.getID(), sqlRowValues);
|
|
|
234 |
}
|
156 |
ilm |
235 |
// Liste des nomenclatures dépendantes des nomenclatures (kit dans kits)
|
83 |
ilm |
236 |
while (size > 0) {
|
|
|
237 |
|
|
|
238 |
List<SQLRowValues> l = getComposedItemToUpdate(ids);
|
93 |
ilm |
239 |
for (SQLRowValues sqlRowValues : l) {
|
|
|
240 |
result.put(sqlRowValues.getID(), sqlRowValues);
|
|
|
241 |
}
|
83 |
ilm |
242 |
size = l.size();
|
|
|
243 |
if (size > 0) {
|
|
|
244 |
ids.clear();
|
|
|
245 |
for (SQLRowValues r : l) {
|
156 |
ilm |
246 |
ids.add(r.getForeignID("ID_ARTICLE"));
|
83 |
ilm |
247 |
}
|
|
|
248 |
}
|
|
|
249 |
}
|
|
|
250 |
|
93 |
ilm |
251 |
List<StockItem> items = new ArrayList<StockItem>(result.size());
|
|
|
252 |
for (SQLRowValues rowVals : result.values()) {
|
83 |
ilm |
253 |
|
156 |
ilm |
254 |
StockItem item = new StockItem(rowVals.getForeign("ID_ARTICLE"), rowVals);
|
83 |
ilm |
255 |
items.add(item);
|
|
|
256 |
}
|
|
|
257 |
return items;
|
|
|
258 |
}
|
|
|
259 |
|
|
|
260 |
/**
|
|
|
261 |
*
|
|
|
262 |
* @param ids
|
|
|
263 |
* @return l'ensemble des Articles composés avec un des articles en parametres
|
|
|
264 |
*/
|
93 |
ilm |
265 |
private List<SQLRowValues> getComposedItemToUpdate(final Set<Integer> ids) {
|
83 |
ilm |
266 |
|
|
|
267 |
final SQLTable tableArticle = this.root.getTable("ARTICLE");
|
|
|
268 |
final SQLRowValues rowValsArt = new SQLRowValues(tableArticle);
|
|
|
269 |
rowValsArt.put(tableArticle.getKey().getName(), null);
|
|
|
270 |
|
156 |
ilm |
271 |
SQLRowValues rowValsStock = new SQLRowValues(this.root.getTable("STOCK"));
|
83 |
ilm |
272 |
rowValsStock.put("QTE_REEL", null);
|
|
|
273 |
rowValsStock.put("QTE_TH", null);
|
|
|
274 |
rowValsStock.put("QTE_RECEPT_ATTENTE", null);
|
|
|
275 |
rowValsStock.put("QTE_LIV_ATTENTE", null);
|
156 |
ilm |
276 |
rowValsStock.put("ID_ARTICLE", rowValsArt);
|
|
|
277 |
rowValsStock.put("ID_DEPOT_STOCK", null);
|
83 |
ilm |
278 |
|
|
|
279 |
final SQLTable tableArticleElt = this.root.getTable("ARTICLE_ELEMENT");
|
156 |
ilm |
280 |
// SQLRowValues rowValsArtItem = new SQLRowValues(tableArticleElt);
|
|
|
281 |
// rowValsArtItem.put("ID_ARTICLE_PARENT", rowValsArt);
|
83 |
ilm |
282 |
// rowValsArtItem.put("QTE", null);
|
|
|
283 |
// rowValsArtItem.put("QTE_UNITAIRE", null);
|
|
|
284 |
|
156 |
ilm |
285 |
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowValsStock);
|
83 |
ilm |
286 |
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
|
|
|
287 |
|
|
|
288 |
@Override
|
|
|
289 |
public SQLSelect transformChecked(SQLSelect input) {
|
156 |
ilm |
290 |
SQLSelectJoin joinFromField = input.addJoin("RIGHT", tableArticleElt, new Where(tableArticleElt.getField("ID_ARTICLE_PARENT"), "=", input.getTable("STOCK").getField("ID_ARTICLE")));
|
83 |
ilm |
291 |
Where w = new Where(joinFromField.getJoinedTable().getField("ID_ARTICLE"), ids);
|
|
|
292 |
joinFromField.setWhere(w);
|
156 |
ilm |
293 |
input.clearOrder();
|
|
|
294 |
input.setDistinct(true);
|
83 |
ilm |
295 |
return input;
|
|
|
296 |
}
|
|
|
297 |
});
|
|
|
298 |
|
|
|
299 |
return fetcher.fetch();
|
|
|
300 |
}
|
|
|
301 |
}
|