18 |
ilm |
1 |
/*
|
|
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
|
|
3 |
*
|
182 |
ilm |
4 |
* Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
|
18 |
ilm |
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.sales.pos.ui;
|
|
|
15 |
|
|
|
16 |
import org.openconcerto.erp.core.sales.pos.model.Article;
|
182 |
ilm |
17 |
import org.openconcerto.erp.core.sales.pos.model.ArticleCache;
|
18 |
ilm |
18 |
import org.openconcerto.erp.core.sales.pos.model.Categorie;
|
149 |
ilm |
19 |
import org.openconcerto.erp.core.sales.pos.model.RegisterFiles.DifferentDayException;
|
182 |
ilm |
20 |
import org.openconcerto.erp.core.sales.pos.model.TarifQuantite;
|
149 |
ilm |
21 |
import org.openconcerto.erp.core.sales.pos.model.Ticket;
|
182 |
ilm |
22 |
import org.openconcerto.erp.core.sales.pos.model.TicketItem;
|
|
|
23 |
import org.openconcerto.erp.core.supplychain.stock.element.StockSQLElement;
|
|
|
24 |
import org.openconcerto.erp.preferences.TemplateNXProps;
|
18 |
ilm |
25 |
import org.openconcerto.sql.element.SQLElement;
|
144 |
ilm |
26 |
import org.openconcerto.sql.element.SQLElementDirectory;
|
182 |
ilm |
27 |
import org.openconcerto.sql.model.SQLField;
|
18 |
ilm |
28 |
import org.openconcerto.sql.model.SQLRow;
|
|
|
29 |
import org.openconcerto.sql.model.SQLRowListRSH;
|
174 |
ilm |
30 |
import org.openconcerto.sql.model.SQLRowValues;
|
|
|
31 |
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
|
18 |
ilm |
32 |
import org.openconcerto.sql.model.SQLSelect;
|
142 |
ilm |
33 |
import org.openconcerto.sql.model.SQLTable;
|
144 |
ilm |
34 |
import org.openconcerto.sql.model.SQLTable.VirtualFields;
|
142 |
ilm |
35 |
import org.openconcerto.sql.model.Where;
|
19 |
ilm |
36 |
import org.openconcerto.utils.ExceptionHandler;
|
182 |
ilm |
37 |
import org.openconcerto.utils.FileUtils;
|
144 |
ilm |
38 |
import org.openconcerto.utils.StringUtils;
|
182 |
ilm |
39 |
import org.openconcerto.utils.cc.ITransformer;
|
18 |
ilm |
40 |
|
|
|
41 |
import java.awt.Color;
|
|
|
42 |
import java.awt.Font;
|
|
|
43 |
import java.awt.Graphics;
|
|
|
44 |
import java.awt.Graphics2D;
|
|
|
45 |
import java.awt.GridBagConstraints;
|
|
|
46 |
import java.awt.GridBagLayout;
|
142 |
ilm |
47 |
import java.awt.Insets;
|
18 |
ilm |
48 |
import java.awt.RenderingHints;
|
142 |
ilm |
49 |
import java.awt.event.ActionEvent;
|
|
|
50 |
import java.awt.event.ActionListener;
|
18 |
ilm |
51 |
import java.awt.geom.Rectangle2D;
|
182 |
ilm |
52 |
import java.io.File;
|
|
|
53 |
import java.io.FileOutputStream;
|
|
|
54 |
import java.io.IOException;
|
|
|
55 |
import java.math.BigDecimal;
|
142 |
ilm |
56 |
import java.text.DecimalFormat;
|
149 |
ilm |
57 |
import java.util.ArrayList;
|
144 |
ilm |
58 |
import java.util.Arrays;
|
182 |
ilm |
59 |
import java.util.Calendar;
|
18 |
ilm |
60 |
import java.util.HashMap;
|
182 |
ilm |
61 |
import java.util.HashSet;
|
149 |
ilm |
62 |
import java.util.List;
|
18 |
ilm |
63 |
import java.util.Map;
|
149 |
ilm |
64 |
import java.util.Set;
|
18 |
ilm |
65 |
|
83 |
ilm |
66 |
import javax.swing.JOptionPane;
|
18 |
ilm |
67 |
import javax.swing.JPanel;
|
|
|
68 |
|
|
|
69 |
public class CaissePanel extends JPanel implements CaisseListener {
|
142 |
ilm |
70 |
|
|
|
71 |
public static final Color LIGHT_BLUE = new Color(83, 129, 172);
|
|
|
72 |
public static final Color DARK_BLUE = new Color(0, 98, 159);
|
|
|
73 |
|
18 |
ilm |
74 |
private CaisseControler controler;
|
25 |
ilm |
75 |
|
18 |
ilm |
76 |
private StatusBar st;
|
83 |
ilm |
77 |
private ArticleSelectorPanel articleSelectorPanel;
|
|
|
78 |
private ArticleSearchPanel articleSearchPanel;
|
18 |
ilm |
79 |
|
174 |
ilm |
80 |
private JPanel selector;
|
182 |
ilm |
81 |
final SQLElementDirectory dir;
|
83 |
ilm |
82 |
|
144 |
ilm |
83 |
public CaissePanel(final CaisseFrame caisseFrame) throws Exception {
|
182 |
ilm |
84 |
this.dir = caisseFrame.getConf().getDirectory();
|
|
|
85 |
loadArticles(this.dir);
|
18 |
ilm |
86 |
this.setLayout(new GridBagLayout());
|
|
|
87 |
this.setBackground(Color.WHITE);
|
|
|
88 |
this.setOpaque(isOpaque());
|
|
|
89 |
GridBagConstraints c = new GridBagConstraints();
|
174 |
ilm |
90 |
|
|
|
91 |
// Column 1
|
18 |
ilm |
92 |
c.gridx = 0;
|
|
|
93 |
c.gridy = 0;
|
83 |
ilm |
94 |
c.weightx = 0;
|
18 |
ilm |
95 |
c.weighty = 0;
|
|
|
96 |
this.controler = new CaisseControler(caisseFrame);
|
|
|
97 |
c.fill = GridBagConstraints.HORIZONTAL;
|
142 |
ilm |
98 |
this.st = createStatusBar(caisseFrame);
|
18 |
ilm |
99 |
this.add(this.st, c);
|
|
|
100 |
|
|
|
101 |
TicketPanel t = new TicketPanel(this.controler);
|
182 |
ilm |
102 |
|
18 |
ilm |
103 |
c.gridy++;
|
|
|
104 |
c.weighty = 1;
|
|
|
105 |
c.gridwidth = 1;
|
|
|
106 |
c.anchor = GridBagConstraints.SOUTHWEST;
|
|
|
107 |
c.fill = GridBagConstraints.NONE;
|
|
|
108 |
this.add(t, c);
|
174 |
ilm |
109 |
// Column 2
|
18 |
ilm |
110 |
c.fill = GridBagConstraints.BOTH;
|
|
|
111 |
c.gridx++;
|
174 |
ilm |
112 |
c.gridy = 0;
|
18 |
ilm |
113 |
c.weightx = 1;
|
|
|
114 |
c.gridheight = 2;
|
174 |
ilm |
115 |
this.articleSelectorPanel = new ArticleSelectorPanel(this.controler);
|
|
|
116 |
this.articleSearchPanel = new ArticleSearchPanel(this.controler);
|
|
|
117 |
this.selector = this.articleSelectorPanel;
|
|
|
118 |
this.add(this.selector, c);
|
|
|
119 |
// Column 3
|
18 |
ilm |
120 |
c.gridx++;
|
|
|
121 |
c.weightx = 0;
|
177 |
ilm |
122 |
this.add(new PaiementPanel(this), c);
|
18 |
ilm |
123 |
this.controler.addCaisseListener(this);
|
|
|
124 |
}
|
|
|
125 |
|
142 |
ilm |
126 |
private StatusBar createStatusBar(final CaisseFrame caisseFrame) {
|
|
|
127 |
final StatusBar s = new StatusBar();
|
|
|
128 |
s.setLayout(new GridBagLayout());
|
|
|
129 |
final GridBagConstraints c = new GridBagConstraints();
|
174 |
ilm |
130 |
if (this.controler.getPOSConf().getScreenWidth() < 1280) {
|
|
|
131 |
c.insets = new Insets(0, 2, 0, 2);
|
|
|
132 |
} else {
|
|
|
133 |
c.insets = new Insets(0, 10, 0, 10);
|
|
|
134 |
}
|
142 |
ilm |
135 |
c.gridx = 0;
|
|
|
136 |
c.gridy = 0;
|
|
|
137 |
c.fill = GridBagConstraints.NONE;
|
|
|
138 |
c.anchor = GridBagConstraints.CENTER;
|
|
|
139 |
c.weightx = 0;
|
|
|
140 |
final POSButton bValidate = new POSButton("Valider");
|
|
|
141 |
bValidate.setForeground(Color.WHITE);
|
|
|
142 |
bValidate.setBackground(DARK_BLUE);
|
|
|
143 |
s.add(bValidate, c);
|
|
|
144 |
c.weightx = 1;
|
|
|
145 |
c.gridx++;
|
|
|
146 |
final POSButton bClients = new POSButton("Clients");
|
|
|
147 |
bClients.setForeground(Color.WHITE);
|
|
|
148 |
bClients.setBackground(DARK_BLUE);
|
|
|
149 |
s.add(bClients, c);
|
|
|
150 |
c.gridx++;
|
|
|
151 |
final POSButton bMenu = new POSButton("Menu");
|
|
|
152 |
bMenu.setForeground(Color.WHITE);
|
|
|
153 |
bMenu.setBackground(DARK_BLUE);
|
|
|
154 |
s.add(bMenu, c);
|
|
|
155 |
bValidate.addActionListener(new ActionListener() {
|
|
|
156 |
|
|
|
157 |
@Override
|
|
|
158 |
public void actionPerformed(ActionEvent e) {
|
182 |
ilm |
159 |
checkStock(getControler().getPOSConf().getDepotID(), new Runnable() {
|
|
|
160 |
|
|
|
161 |
@Override
|
|
|
162 |
public void run() {
|
|
|
163 |
if (caisseFrame.getPOSConf().askPostalCode()) {
|
|
|
164 |
caisseFrame.showPostalCodeFrame(CaissePanel.this);
|
|
|
165 |
} else {
|
|
|
166 |
validateTicket(caisseFrame);
|
|
|
167 |
}
|
|
|
168 |
|
144 |
ilm |
169 |
}
|
182 |
ilm |
170 |
});
|
149 |
ilm |
171 |
|
142 |
ilm |
172 |
}
|
|
|
173 |
});
|
|
|
174 |
bClients.addActionListener(new ActionListener() {
|
|
|
175 |
|
|
|
176 |
@Override
|
|
|
177 |
public void actionPerformed(ActionEvent e) {
|
|
|
178 |
// Clients
|
|
|
179 |
try {
|
|
|
180 |
caisseFrame.showClients();
|
|
|
181 |
} catch (Throwable ex) {
|
|
|
182 |
ExceptionHandler.handle("Erreur d'affichage du menu", ex);
|
|
|
183 |
}
|
|
|
184 |
|
|
|
185 |
}
|
|
|
186 |
});
|
|
|
187 |
|
|
|
188 |
bMenu.addActionListener(new ActionListener() {
|
|
|
189 |
|
|
|
190 |
@Override
|
|
|
191 |
public void actionPerformed(ActionEvent e) {
|
|
|
192 |
// Menu
|
|
|
193 |
try {
|
|
|
194 |
caisseFrame.showMenu();
|
|
|
195 |
} catch (Throwable ex) {
|
|
|
196 |
ExceptionHandler.handle("Erreur d'affichage du menu", ex);
|
|
|
197 |
}
|
|
|
198 |
|
|
|
199 |
}
|
|
|
200 |
});
|
|
|
201 |
|
|
|
202 |
return s;
|
|
|
203 |
}
|
|
|
204 |
|
182 |
ilm |
205 |
protected void checkStock(int idDepot, Runnable runnable) {
|
|
|
206 |
final List<TicketItem> items = this.controler.getItems();
|
|
|
207 |
final List<Integer> articleIds = new ArrayList<>();
|
|
|
208 |
final Map<Integer, TicketItem> mapTicketItem = new HashMap<>();
|
|
|
209 |
for (TicketItem item : items) {
|
|
|
210 |
articleIds.add(item.getArticle().getId());
|
|
|
211 |
mapTicketItem.put(item.getArticle().getId(), item);
|
|
|
212 |
}
|
|
|
213 |
|
|
|
214 |
final SQLTable stockTable = this.dir.getElement(StockSQLElement.class).getTable();
|
|
|
215 |
|
|
|
216 |
final SQLSelect selStock = new SQLSelect();
|
|
|
217 |
selStock.addSelect(stockTable.getField("ID"));
|
|
|
218 |
selStock.addSelect(stockTable.getField("ID_DEPOT_STOCK"));
|
|
|
219 |
selStock.addSelect(stockTable.getField("QTE_REEL"));
|
|
|
220 |
selStock.addSelect(stockTable.getField("ID_ARTICLE"));
|
|
|
221 |
selStock.setWhere(Where.inValues(stockTable.getField("ID_ARTICLE"), articleIds).and(new Where(stockTable.getField("ID_DEPOT_STOCK"), "=", idDepot)));
|
|
|
222 |
Map<TicketItem, Integer> missingQty = new HashMap<>();
|
|
|
223 |
for (SQLRow row : SQLRowListRSH.execute(selStock)) {
|
|
|
224 |
int idArticle = row.getInt("ID_ARTICLE");
|
|
|
225 |
int qte = (int) Math.round(row.getFloat("QTE_REEL"));
|
|
|
226 |
TicketItem item = mapTicketItem.get(idArticle);
|
|
|
227 |
if (item == null) {
|
|
|
228 |
System.err.println("Pas d'entrée dans STOCK pour l'article " + idArticle);
|
|
|
229 |
} else {
|
|
|
230 |
if (qte < item.getQty().intValue()) {
|
|
|
231 |
int delta = item.getQty().intValue() - qte;
|
|
|
232 |
missingQty.put(item, delta);
|
|
|
233 |
}
|
|
|
234 |
}
|
|
|
235 |
|
|
|
236 |
}
|
|
|
237 |
if (missingQty.isEmpty()) {
|
|
|
238 |
runnable.run();
|
|
|
239 |
} else {
|
|
|
240 |
// Transfert de stock, Annulation ou bypass
|
|
|
241 |
getControler().openStockErrorPanel(missingQty, runnable);
|
|
|
242 |
}
|
|
|
243 |
}
|
|
|
244 |
|
|
|
245 |
public Set<Integer> loadFavoriteProductsIds() {
|
|
|
246 |
final TemplateNXProps nxprops = (TemplateNXProps) TemplateNXProps.getInstance();
|
|
|
247 |
final File f = new File(nxprops.getDefaultStringValue(), "favorites.txt");
|
|
|
248 |
System.out.println("CaisseControler.saveFavoriteProductsIds() loading favorites from " + f.getAbsolutePath());
|
|
|
249 |
final Set<Integer> result = new HashSet<>();
|
|
|
250 |
if (f.exists()) {
|
|
|
251 |
try {
|
|
|
252 |
String s = FileUtils.read(f);
|
|
|
253 |
List<String> sIds = StringUtils.fastSplit(s, ',');
|
|
|
254 |
for (String string : sIds) {
|
|
|
255 |
if (!string.isEmpty()) {
|
|
|
256 |
result.add(Integer.parseInt(string));
|
|
|
257 |
}
|
|
|
258 |
}
|
|
|
259 |
} catch (IOException e) {
|
|
|
260 |
e.printStackTrace();
|
|
|
261 |
}
|
|
|
262 |
}
|
|
|
263 |
return result;
|
|
|
264 |
}
|
|
|
265 |
|
|
|
266 |
public void saveFavoriteProductsIds(List<Article> products) {
|
|
|
267 |
final TemplateNXProps nxprops = (TemplateNXProps) TemplateNXProps.getInstance();
|
|
|
268 |
final File f = new File(nxprops.getDefaultStringValue(), "favorites.txt");
|
|
|
269 |
System.out.println("CaisseControler.saveFavoriteProductsIds() saving favorites to " + f.getAbsolutePath());
|
|
|
270 |
try (FileOutputStream fOut = new FileOutputStream(f);) {
|
|
|
271 |
for (Article product : products) {
|
|
|
272 |
fOut.write(String.valueOf(product.getId()).getBytes());
|
|
|
273 |
fOut.write(',');
|
|
|
274 |
}
|
|
|
275 |
fOut.flush();
|
|
|
276 |
} catch (IOException e) {
|
|
|
277 |
e.printStackTrace();
|
|
|
278 |
}
|
|
|
279 |
}
|
|
|
280 |
|
|
|
281 |
private List<Article> loadArticles(final SQLElementDirectory dir) {
|
|
|
282 |
long t1 = System.currentTimeMillis();
|
174 |
ilm |
283 |
final SQLSelect selUniteVente = new SQLSelect();
|
182 |
ilm |
284 |
final SQLTable tableUniteVente = dir.getElement("UNITE_VENTE").getTable();
|
|
|
285 |
selUniteVente.addSelect(tableUniteVente.getKey());
|
|
|
286 |
selUniteVente.addSelect(tableUniteVente.getField("CODE"));
|
174 |
ilm |
287 |
final Map<Integer, String> mapUniteVenteName = new HashMap<>();
|
|
|
288 |
for (SQLRow row : SQLRowListRSH.execute(selUniteVente)) {
|
|
|
289 |
mapUniteVenteName.put(row.getID(), row.getString("CODE"));
|
|
|
290 |
}
|
18 |
ilm |
291 |
|
182 |
ilm |
292 |
final Set<Integer> favoriteProductsIds = loadFavoriteProductsIds();
|
149 |
ilm |
293 |
final List<Article> favoriteProducts = new ArrayList<>();
|
|
|
294 |
|
174 |
ilm |
295 |
final Map<Integer, Categorie> categoriesMap = new HashMap<>();
|
18 |
ilm |
296 |
|
144 |
ilm |
297 |
SQLElement eltFam = dir.getElement("FAMILLE_ARTICLE");
|
|
|
298 |
SQLElement eltArticle = dir.getElement("ARTICLE");
|
18 |
ilm |
299 |
|
144 |
ilm |
300 |
final SQLSelect selFamille = new SQLSelect();
|
18 |
ilm |
301 |
selFamille.addSelectStar(eltFam.getTable());
|
144 |
ilm |
302 |
selFamille.addFieldOrder(eltFam.getTable().getField("CODE"));
|
149 |
ilm |
303 |
|
144 |
ilm |
304 |
for (SQLRow row : SQLRowListRSH.execute(selFamille)) {
|
83 |
ilm |
305 |
// Map id -> Category
|
|
|
306 |
final Categorie cP = categoriesMap.get(row.getInt("ID_FAMILLE_ARTICLE_PERE"));
|
18 |
ilm |
307 |
Categorie c;
|
|
|
308 |
if (cP != null) {
|
|
|
309 |
c = new Categorie(row.getString("NOM"));
|
|
|
310 |
cP.add(c);
|
|
|
311 |
} else {
|
|
|
312 |
c = new Categorie(row.getString("NOM"), true);
|
|
|
313 |
}
|
|
|
314 |
|
83 |
ilm |
315 |
categoriesMap.put(row.getID(), c);
|
18 |
ilm |
316 |
}
|
|
|
317 |
|
83 |
ilm |
318 |
final SQLSelect selArticle = new SQLSelect();
|
142 |
ilm |
319 |
final SQLTable tableArticle = eltArticle.getTable();
|
144 |
ilm |
320 |
selArticle.addAllSelect(tableArticle.getFields(VirtualFields.PRIMARY_KEY.union(VirtualFields.ARCHIVE)));
|
182 |
ilm |
321 |
selArticle.addAllSelect(tableArticle,
|
|
|
322 |
Arrays.asList("ID_FAMILLE_ARTICLE", "NOM", "CODE", "CODE_BARRE", "ID_TAXE", "PV_HT", "PV_TTC", "ADDITIONAL_TICKET_COPY", "ID_UNITE_VENTE", "ID_ECO_CONTRIBUTION"));
|
149 |
ilm |
323 |
selArticle.setWhere(new Where(tableArticle.getField("OBSOLETE"), "=", Boolean.FALSE).and(new Where(tableArticle.getField("MASQUE_CAISSE"), "=", Boolean.FALSE)));
|
182 |
ilm |
324 |
selArticle.andWhere(new Where(tableArticle.getField("VIRTUEL"), "=", Boolean.FALSE));
|
18 |
ilm |
325 |
|
182 |
ilm |
326 |
List<String> tablesDeclinaisons = new ArrayList<>();
|
|
|
327 |
List<String> declinaisonsFieldNames = new ArrayList<>();
|
|
|
328 |
for (SQLField f : tableArticle.getFields()) {
|
|
|
329 |
if (f.getName().startsWith("ID_ARTICLE_DECLINAISON_")) {
|
|
|
330 |
selArticle.addSelect(f);
|
|
|
331 |
declinaisonsFieldNames.add(f.getName());
|
|
|
332 |
tablesDeclinaisons.add(f.getName().substring("ID_".length()));
|
|
|
333 |
}
|
|
|
334 |
}
|
|
|
335 |
|
80 |
ilm |
336 |
final Categorie cUnclassified = new Categorie("Non classés", true);
|
149 |
ilm |
337 |
cUnclassified.setUnknown();
|
182 |
ilm |
338 |
|
|
|
339 |
// Fetch des declinaisons :
|
|
|
340 |
// "ID_ARTICLE_DECLINAISON_COULEUR" : { {3 , "noir"] } ,
|
|
|
341 |
// "ID_ARTICLE_DECLINAISON_TAILLE" : { {2 ,"XL"},{3,"XXL"}};
|
|
|
342 |
Map<String, Map<Integer, String>> mapDeclinaisons = new HashMap<>();
|
|
|
343 |
for (String table : tablesDeclinaisons) {
|
|
|
344 |
SQLTable t = eltArticle.getTable().getTable(table);
|
|
|
345 |
final SQLSelect selDecl = new SQLSelect();
|
|
|
346 |
selDecl.addSelect(t.getKey());
|
|
|
347 |
selDecl.addSelect(t.getField("NOM"));
|
|
|
348 |
Map<Integer, String> m = new HashMap<>();
|
|
|
349 |
mapDeclinaisons.put("ID_" + table, m);
|
|
|
350 |
for (SQLRow row : SQLRowListRSH.execute(selDecl)) {
|
|
|
351 |
m.put(row.getID(), row.getString("NOM"));
|
|
|
352 |
}
|
|
|
353 |
}
|
|
|
354 |
// Fetch des articles
|
|
|
355 |
final List<SQLRow> rArticles = SQLRowListRSH.execute(selArticle);
|
|
|
356 |
List<Integer> idsArticles = new ArrayList<>(rArticles.size());
|
|
|
357 |
for (SQLRow r : rArticles) {
|
|
|
358 |
idsArticles.add(r.getID());
|
|
|
359 |
}
|
|
|
360 |
|
|
|
361 |
// Recuperation des promos
|
|
|
362 |
final SQLTable tableArticleTairdPromotion = tableArticle.getTable("ARTICLE_TARIF_PROMOTION");
|
|
|
363 |
final SQLTable tableTarifPromotion = tableArticle.getTable("TARIF_PROMOTION");
|
|
|
364 |
SQLRowValues rTarifPromotion = new SQLRowValues(tableArticleTairdPromotion);
|
|
|
365 |
rTarifPromotion.putNulls(tableArticleTairdPromotion.getFieldsName());
|
|
|
366 |
rTarifPromotion.putRowValues("ID_TARIF_PROMOTION").putNulls("START", "END");
|
|
|
367 |
rTarifPromotion.putRowValues("ID_ARTICLE").putNulls("ID_TAXE");
|
|
|
368 |
Where where = new Where(tableArticleTairdPromotion.getField("ID_ARTICLE"), idsArticles);
|
|
|
369 |
Calendar today = Calendar.getInstance();
|
|
|
370 |
|
|
|
371 |
final SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rTarifPromotion);
|
|
|
372 |
fetcher.appendSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
|
|
|
373 |
|
|
|
374 |
@Override
|
|
|
375 |
public SQLSelect transformChecked(SQLSelect input) {
|
|
|
376 |
input.andWhere(new Where(input.getAlias(tableTarifPromotion.getField("START")), "<", today));
|
|
|
377 |
input.andWhere(new Where(input.getAlias(tableTarifPromotion.getField("END")), ">", today));
|
|
|
378 |
return input;
|
|
|
379 |
}
|
|
|
380 |
});
|
|
|
381 |
List<SQLRowValues> rPromotions = fetcher.fetch(where);
|
|
|
382 |
long t1p = System.currentTimeMillis();
|
|
|
383 |
// Tarifs : id article <-> liste des tarifs par quantité
|
|
|
384 |
Map<Integer, List<TarifQuantite>> mapTarif = new HashMap<>();
|
|
|
385 |
System.err.println("CaissePanel.loadArticles()" + rPromotions.size() + " promotions");
|
|
|
386 |
for (SQLRowValues r : rPromotions) {
|
|
|
387 |
final Integer foreignID = ((Integer) r.getObjectNoCheck("ID_ARTICLE"));
|
|
|
388 |
List<TarifQuantite> list = mapTarif.get(foreignID);
|
|
|
389 |
if (list == null) {
|
|
|
390 |
list = new ArrayList<>();
|
|
|
391 |
mapTarif.put(foreignID, list);
|
|
|
392 |
}
|
|
|
393 |
TarifQuantite t = new TarifQuantite(foreignID, r.getInt("QTE"), r.getBigDecimal("PV_HT"), r.getBigDecimal("PV_TTC"), r.getForeign("ID_ARTICLE").getInt("ID_TAXE"));
|
|
|
394 |
list.add(t);
|
|
|
395 |
}
|
|
|
396 |
final List<Article> res = new ArrayList<>(rArticles.size());
|
|
|
397 |
for (SQLRow row : rArticles) {
|
|
|
398 |
final Integer idFamilleArticle = ((Integer) row.getObjectNoCheck("ID_FAMILLE_ARTICLE"));
|
144 |
ilm |
399 |
Categorie s1 = categoriesMap.get(idFamilleArticle);
|
80 |
ilm |
400 |
if (s1 == null) {
|
|
|
401 |
s1 = cUnclassified;
|
144 |
ilm |
402 |
categoriesMap.put(idFamilleArticle, cUnclassified);
|
80 |
ilm |
403 |
}
|
182 |
ilm |
404 |
final String name = ((String) row.getObjectNoCheck("NOM")).trim();
|
80 |
ilm |
405 |
if (name.length() > 0) {
|
|
|
406 |
final Article a = new Article(s1, name, row.getID());
|
182 |
ilm |
407 |
final String barcode = (String) row.getObjectNoCheck("CODE_BARRE");
|
|
|
408 |
final String code = (String) row.getObjectNoCheck("CODE");
|
144 |
ilm |
409 |
a.setBarCode(StringUtils.isEmpty(barcode, true) ? code : barcode);
|
|
|
410 |
a.setCode(code);
|
182 |
ilm |
411 |
a.setIdTaxe(((Integer) row.getObjectNoCheck("ID_TAXE")));
|
|
|
412 |
a.setPriceWithoutTax((BigDecimal) row.getObjectNoCheck("PV_HT"));
|
|
|
413 |
a.setPriceWithTax((BigDecimal) row.getObjectNoCheck("PV_TTC"));
|
|
|
414 |
a.setAdditionalCopyRequested((Boolean) row.getObjectNoCheck("ADDITIONAL_TICKET_COPY"));
|
|
|
415 |
final Integer idEcoContribution = ((Integer) row.getObjectNoCheck("ID_ECO_CONTRIBUTION"));
|
|
|
416 |
if (idEcoContribution > 1)
|
|
|
417 |
a.setEcoTaxe((BigDecimal) row.getForeign("ID_ECO_CONTRIBUTION").getObjectNoCheck("TAUX"));
|
|
|
418 |
final Integer idUniteVente = ((Integer) row.getObjectNoCheck("ID_UNITE_VENTE"));
|
|
|
419 |
if (idUniteVente != 2) {
|
|
|
420 |
a.setSalesUnit(mapUniteVenteName.get(idUniteVente));
|
174 |
ilm |
421 |
}
|
182 |
ilm |
422 |
|
149 |
ilm |
423 |
final Integer idProduct = a.getId();
|
|
|
424 |
if (favoriteProductsIds.contains(idProduct)) {
|
|
|
425 |
favoriteProducts.add(a);
|
|
|
426 |
}
|
|
|
427 |
|
182 |
ilm |
428 |
final List<TarifQuantite> promotions = mapTarif.get(row.getID());
|
|
|
429 |
if (promotions != null) {
|
|
|
430 |
a.setTarifsPromotion(promotions);
|
|
|
431 |
for (TarifQuantite t : promotions) {
|
|
|
432 |
if (t.getQuantite() == 1) {
|
|
|
433 |
a.setIdTaxe(t.getIdTaxe());
|
|
|
434 |
a.setPriceWithoutTax(t.getPrixHT());
|
|
|
435 |
a.setPriceWithTax(t.getPrixTTC());
|
|
|
436 |
break;
|
|
|
437 |
}
|
|
|
438 |
}
|
18 |
ilm |
439 |
|
182 |
ilm |
440 |
}
|
174 |
ilm |
441 |
|
182 |
ilm |
442 |
for (String f : declinaisonsFieldNames) {
|
|
|
443 |
Integer idArtDeclinaison = (Integer) row.getObjectNoCheck(f);
|
|
|
444 |
if (idArtDeclinaison != null && idArtDeclinaison > 1) {
|
|
|
445 |
Map<Integer, String> mm = mapDeclinaisons.get(f);
|
|
|
446 |
if (mm != null) {
|
|
|
447 |
String v = mm.get(idArtDeclinaison);
|
|
|
448 |
a.addDeclinaison(f.substring("ID_ARTICLE_DECLINAISON_".length()), v);
|
|
|
449 |
}
|
|
|
450 |
}
|
|
|
451 |
}
|
174 |
ilm |
452 |
|
182 |
ilm |
453 |
res.add(a);
|
174 |
ilm |
454 |
|
182 |
ilm |
455 |
}
|
174 |
ilm |
456 |
}
|
182 |
ilm |
457 |
long t2p = System.currentTimeMillis();
|
174 |
ilm |
458 |
|
182 |
ilm |
459 |
Categorie.setFavoriteProducts(favoriteProducts);
|
|
|
460 |
ArticleCache.initCache(dir);
|
|
|
461 |
ArticleCache.getInstance().preloadCacheArticleMap(new ArrayList<>(favoriteProductsIds));
|
|
|
462 |
long t2 = System.currentTimeMillis();
|
|
|
463 |
System.err.println("CaissePanel.loadArticles() " + res.size() + " in " + (t2 - t1) + " ms : process: " + (t2p - t1p) + " ms");
|
|
|
464 |
return res;
|
174 |
ilm |
465 |
}
|
|
|
466 |
|
18 |
ilm |
467 |
@Override
|
|
|
468 |
public void paint(Graphics g) {
|
67 |
ilm |
469 |
System.err.println("CaissePanel.paint()" + this.getWidth() + " x " + this.getHeight());
|
18 |
ilm |
470 |
super.paint(g);
|
|
|
471 |
Graphics2D g2 = (Graphics2D) g;
|
|
|
472 |
g.setFont(new Font("Arial", Font.PLAIN, 32));
|
|
|
473 |
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
142 |
ilm |
474 |
|
|
|
475 |
if (this.controler.isClientDefined()) {
|
|
|
476 |
g.setColor(CaissePanel.DARK_BLUE);
|
|
|
477 |
g.setFont(new Font("Arial", Font.PLAIN, 28));
|
|
|
478 |
g.drawString(this.controler.getClient().getFullName(), 20, 75);
|
|
|
479 |
g.setColor(Color.GRAY);
|
|
|
480 |
g.setFont(g.getFont().deriveFont(18f));
|
|
|
481 |
g.drawString("Solde : " + new DecimalFormat("#0.00").format(this.controler.getClient().getSolde()), 20, 120);
|
|
|
482 |
|
|
|
483 |
}
|
174 |
ilm |
484 |
int xPos = 300;
|
|
|
485 |
if (this.controler.getPOSConf().getScreenWidth() < 1280) {
|
|
|
486 |
xPos = 270;
|
|
|
487 |
}
|
18 |
ilm |
488 |
// Prix
|
174 |
ilm |
489 |
int x = xPos;
|
18 |
ilm |
490 |
int y = 110;
|
|
|
491 |
String euros;
|
|
|
492 |
String cents;
|
|
|
493 |
Rectangle2D r;
|
142 |
ilm |
494 |
g.setColor(Color.BLACK);
|
|
|
495 |
if (this.controler.isClientDefined()) {
|
|
|
496 |
g.setFont(g.getFont().deriveFont(46f));
|
|
|
497 |
y += 10;
|
|
|
498 |
} else {
|
|
|
499 |
g.setFont(g.getFont().deriveFont(66f));
|
|
|
500 |
}
|
18 |
ilm |
501 |
final int total = this.controler.getTotal();
|
25 |
ilm |
502 |
euros = CaisseControler.getEuros(total) + ".";
|
|
|
503 |
cents = CaisseControler.getCents(total);
|
18 |
ilm |
504 |
r = g.getFontMetrics().getStringBounds(euros, g);
|
|
|
505 |
x = x - (int) r.getWidth();
|
|
|
506 |
g.drawString(euros, x, y);
|
|
|
507 |
g.setFont(g.getFont().deriveFont(40f));
|
|
|
508 |
g.drawString(cents, x + (int) r.getWidth(), y);
|
|
|
509 |
// Paiement
|
|
|
510 |
y += 40;
|
174 |
ilm |
511 |
x = xPos;
|
18 |
ilm |
512 |
final int paye = this.controler.getPaidTotal();
|
25 |
ilm |
513 |
euros = CaisseControler.getEuros(paye) + ".";
|
|
|
514 |
cents = CaisseControler.getCents(paye);
|
18 |
ilm |
515 |
|
|
|
516 |
g.setFont(g.getFont().deriveFont(18f));
|
|
|
517 |
Rectangle2D r2 = g.getFontMetrics().getStringBounds("Payé", g);
|
|
|
518 |
if (paye >= total) {
|
|
|
519 |
g.setColor(Color.DARK_GRAY);
|
|
|
520 |
} else {
|
|
|
521 |
g.setColor(Color.ORANGE);
|
|
|
522 |
}
|
|
|
523 |
g.setFont(g.getFont().deriveFont(32f));
|
|
|
524 |
r = g.getFontMetrics().getStringBounds(euros, g);
|
|
|
525 |
g.drawString(euros, x - (int) r.getWidth(), y);
|
|
|
526 |
g.setFont(g.getFont().deriveFont(24f));
|
|
|
527 |
g.drawString(cents, x, y);
|
|
|
528 |
g.setFont(g.getFont().deriveFont(18f));
|
|
|
529 |
g.setColor(Color.GRAY);
|
|
|
530 |
g.drawString("Payé", x - (int) r2.getWidth() - (int) r.getWidth() - 10, y);
|
|
|
531 |
// A rendre
|
67 |
ilm |
532 |
final boolean minimalHeight = this.getHeight() < 750;
|
|
|
533 |
if (!minimalHeight) {
|
|
|
534 |
y += 40;
|
174 |
ilm |
535 |
x = xPos;
|
67 |
ilm |
536 |
} else {
|
|
|
537 |
x = 140;
|
|
|
538 |
}
|
18 |
ilm |
539 |
int aRendre = paye - total;
|
|
|
540 |
if (aRendre != 0) {
|
|
|
541 |
String label;
|
|
|
542 |
if (aRendre > 0) {
|
|
|
543 |
label = "Rendu";
|
|
|
544 |
} else {
|
67 |
ilm |
545 |
if (!minimalHeight) {
|
|
|
546 |
label = "Reste à payer";
|
|
|
547 |
} else {
|
|
|
548 |
label = "Doit";
|
|
|
549 |
}
|
18 |
ilm |
550 |
aRendre = -aRendre;
|
|
|
551 |
}
|
|
|
552 |
|
25 |
ilm |
553 |
euros = CaisseControler.getEuros(aRendre) + ".";
|
|
|
554 |
cents = CaisseControler.getCents(aRendre);
|
18 |
ilm |
555 |
|
|
|
556 |
g.setFont(g.getFont().deriveFont(18f));
|
|
|
557 |
Rectangle2D r3 = g.getFontMetrics().getStringBounds(label, g);
|
|
|
558 |
|
|
|
559 |
g.setColor(Color.DARK_GRAY);
|
|
|
560 |
g.setFont(g.getFont().deriveFont(32f));
|
|
|
561 |
r = g.getFontMetrics().getStringBounds(euros, g);
|
|
|
562 |
g.drawString(euros, x - (int) r.getWidth(), y);
|
|
|
563 |
g.setFont(g.getFont().deriveFont(24f));
|
|
|
564 |
g.drawString(cents, x, y);
|
|
|
565 |
g.setFont(g.getFont().deriveFont(18f));
|
|
|
566 |
g.setColor(Color.GRAY);
|
|
|
567 |
g.drawString(label, x - (int) r3.getWidth() - (int) r.getWidth() - 10, y);
|
|
|
568 |
|
|
|
569 |
}
|
|
|
570 |
|
|
|
571 |
}
|
|
|
572 |
|
|
|
573 |
@Override
|
|
|
574 |
public void caisseStateChanged() {
|
|
|
575 |
repaint();
|
|
|
576 |
}
|
83 |
ilm |
577 |
|
|
|
578 |
public void switchListMode() {
|
|
|
579 |
|
174 |
ilm |
580 |
GridBagConstraints c = ((GridBagLayout) this.getLayout()).getConstraints(this.selector);
|
|
|
581 |
this.remove(this.selector);
|
83 |
ilm |
582 |
|
174 |
ilm |
583 |
if (this.selector == this.articleSearchPanel) {
|
|
|
584 |
this.selector = this.articleSelectorPanel;
|
83 |
ilm |
585 |
} else {
|
174 |
ilm |
586 |
this.selector = this.articleSearchPanel;
|
83 |
ilm |
587 |
}
|
174 |
ilm |
588 |
System.err.println("CaissePanel.switchListMode()" + this.selector.getMinimumSize() + " " + this.selector.getPreferredSize() + " " + this.selector.getMaximumSize());
|
|
|
589 |
this.add(this.selector, c);
|
83 |
ilm |
590 |
this.validate();
|
|
|
591 |
this.repaint();
|
|
|
592 |
|
|
|
593 |
}
|
132 |
ilm |
594 |
|
177 |
ilm |
595 |
public boolean isModeSearch() {
|
|
|
596 |
return this.selector == this.articleSearchPanel;
|
|
|
597 |
}
|
|
|
598 |
|
132 |
ilm |
599 |
public CaisseControler getControler() {
|
174 |
ilm |
600 |
return this.controler;
|
132 |
ilm |
601 |
}
|
174 |
ilm |
602 |
|
|
|
603 |
public void validateTicket(final CaisseFrame caisseFrame) {
|
|
|
604 |
final Ticket savedReceipt;
|
|
|
605 |
try {
|
|
|
606 |
savedReceipt = CaissePanel.this.controler.saveAndClearTicket(caisseFrame.getFiles(), caisseFrame.getConf().getDirectory());
|
|
|
607 |
} catch (DifferentDayException ex) {
|
|
|
608 |
JOptionPane.showMessageDialog(CaissePanel.this, "Impossible de laisser la caisse ouverte plusieurs jours. Veuillez la clôturer pour pouvoir faire de nouveaux tickets.", "Erreur",
|
|
|
609 |
JOptionPane.ERROR_MESSAGE);
|
|
|
610 |
return;
|
|
|
611 |
} catch (Throwable ex) {
|
|
|
612 |
ExceptionHandler.handle(CaissePanel.this, "Erreur de sauvegarde des informations du ticket", ex);
|
|
|
613 |
return;
|
|
|
614 |
}
|
|
|
615 |
if (savedReceipt != null) {
|
|
|
616 |
// Valider
|
|
|
617 |
CaissePanel.this.controler.setLCD("Impression de", "votre ticket...", 0);
|
|
|
618 |
try {
|
|
|
619 |
caisseFrame.getPOSConf().print(savedReceipt, (savedReceipt.isAdditionnalCopyRequested() ? 1 : 0));
|
|
|
620 |
} catch (UnsatisfiedLinkError ex) {
|
182 |
ilm |
621 |
JOptionPane.showMessageDialog(CaissePanel.this, "Erreur de configuration de la liaison à l'imprimante");
|
174 |
ilm |
622 |
} catch (Throwable ex) {
|
|
|
623 |
ex.printStackTrace();
|
|
|
624 |
JOptionPane.showMessageDialog(CaissePanel.this, "Erreur d'impression du ticket");
|
|
|
625 |
}
|
|
|
626 |
|
|
|
627 |
CaissePanel.this.controler.setLCDDefaultDisplay(2);
|
|
|
628 |
} else {
|
182 |
ilm |
629 |
System.err.println("CaissePanel.validateTicket() ticket non sauvé");
|
174 |
ilm |
630 |
}
|
|
|
631 |
}
|
18 |
ilm |
632 |
}
|