OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 177 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
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
}