OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 151 | 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
 *
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.sales.pos.ui;
15
 
16
import org.openconcerto.erp.core.sales.pos.model.Article;
17
import org.openconcerto.erp.core.sales.pos.model.Categorie;
149 ilm 18
import org.openconcerto.erp.core.sales.pos.model.RegisterFiles.DifferentDayException;
19
import org.openconcerto.erp.core.sales.pos.model.Ticket;
18 ilm 20
import org.openconcerto.sql.element.SQLElement;
144 ilm 21
import org.openconcerto.sql.element.SQLElementDirectory;
18 ilm 22
import org.openconcerto.sql.model.SQLRow;
23
import org.openconcerto.sql.model.SQLRowListRSH;
24
import org.openconcerto.sql.model.SQLSelect;
142 ilm 25
import org.openconcerto.sql.model.SQLTable;
144 ilm 26
import org.openconcerto.sql.model.SQLTable.VirtualFields;
142 ilm 27
import org.openconcerto.sql.model.Where;
19 ilm 28
import org.openconcerto.utils.ExceptionHandler;
144 ilm 29
import org.openconcerto.utils.StringUtils;
18 ilm 30
 
31
import java.awt.Color;
32
import java.awt.Font;
33
import java.awt.Graphics;
34
import java.awt.Graphics2D;
35
import java.awt.GridBagConstraints;
36
import java.awt.GridBagLayout;
142 ilm 37
import java.awt.Insets;
18 ilm 38
import java.awt.RenderingHints;
142 ilm 39
import java.awt.event.ActionEvent;
40
import java.awt.event.ActionListener;
18 ilm 41
import java.awt.geom.Rectangle2D;
142 ilm 42
import java.text.DecimalFormat;
149 ilm 43
import java.util.ArrayList;
144 ilm 44
import java.util.Arrays;
18 ilm 45
import java.util.HashMap;
149 ilm 46
import java.util.List;
18 ilm 47
import java.util.Map;
149 ilm 48
import java.util.Set;
18 ilm 49
 
83 ilm 50
import javax.swing.JOptionPane;
18 ilm 51
import javax.swing.JPanel;
52
 
53
public class CaissePanel extends JPanel implements CaisseListener {
142 ilm 54
 
55
    public static final Color LIGHT_BLUE = new Color(83, 129, 172);
56
    public static final Color DARK_BLUE = new Color(0, 98, 159);
57
 
18 ilm 58
    private CaisseControler controler;
25 ilm 59
 
18 ilm 60
    private StatusBar st;
83 ilm 61
    private ArticleSelectorPanel articleSelectorPanel;
62
    private ArticleSearchPanel articleSearchPanel;
18 ilm 63
 
83 ilm 64
    private JPanel articleSelector;
65
 
144 ilm 66
    public CaissePanel(final CaisseFrame caisseFrame) throws Exception {
67
        final SQLElementDirectory dir = caisseFrame.getConf().getDirectory();
68
 
18 ilm 69
        this.setLayout(new GridBagLayout());
70
        this.setBackground(Color.WHITE);
71
        this.setOpaque(isOpaque());
72
        GridBagConstraints c = new GridBagConstraints();
73
        c.gridx = 0;
74
        c.gridy = 0;
83 ilm 75
        c.weightx = 0;
18 ilm 76
        c.weighty = 0;
77
 
78
        this.controler = new CaisseControler(caisseFrame);
79
 
80
        c.fill = GridBagConstraints.HORIZONTAL;
142 ilm 81
        this.st = createStatusBar(caisseFrame);
18 ilm 82
 
83
        this.add(this.st, c);
84
 
85
        TicketPanel t = new TicketPanel(this.controler);
86
        // fillExampleArticle();
144 ilm 87
        loadArticles(dir);
18 ilm 88
        c.gridx = 0;
89
        c.gridy++;
90
        c.weightx = 0;
91
        c.weighty = 1;
92
        c.gridwidth = 1;
93
        c.anchor = GridBagConstraints.SOUTHWEST;
94
        c.fill = GridBagConstraints.NONE;
95
        this.add(t, c);
96
 
97
        c.fill = GridBagConstraints.BOTH;
98
        c.gridx++;
99
        c.weightx = 1;
100
        c.gridy--;
101
        c.gridheight = 2;
83 ilm 102
        articleSelectorPanel = new ArticleSelectorPanel(this.controler);
103
        articleSearchPanel = new ArticleSearchPanel(this.controler);
104
        articleSelector = articleSelectorPanel;
105
        this.add(articleSelector, c);
18 ilm 106
 
107
        c.gridx++;
108
        c.weightx = 0;
109
        this.add(new PaiementPanel(this.controler), c);
110
        this.controler.addCaisseListener(this);
111
    }
112
 
142 ilm 113
    private StatusBar createStatusBar(final CaisseFrame caisseFrame) {
114
        final StatusBar s = new StatusBar();
115
        s.setLayout(new GridBagLayout());
116
        final GridBagConstraints c = new GridBagConstraints();
117
        c.insets = new Insets(0, 10, 0, 10);
118
        c.gridx = 0;
119
        c.gridy = 0;
120
        c.fill = GridBagConstraints.NONE;
121
        c.anchor = GridBagConstraints.CENTER;
122
        c.weightx = 0;
123
        final POSButton bValidate = new POSButton("Valider");
124
        bValidate.setForeground(Color.WHITE);
125
        bValidate.setBackground(DARK_BLUE);
126
        s.add(bValidate, c);
127
        c.weightx = 1;
128
        c.gridx++;
129
        final POSButton bClients = new POSButton("Clients");
130
        bClients.setForeground(Color.WHITE);
131
        bClients.setBackground(DARK_BLUE);
132
        s.add(bClients, c);
133
        c.gridx++;
134
        final POSButton bMenu = new POSButton("Menu");
135
        bMenu.setForeground(Color.WHITE);
136
        bMenu.setBackground(DARK_BLUE);
137
        s.add(bMenu, c);
138
        bValidate.addActionListener(new ActionListener() {
139
 
140
            @Override
141
            public void actionPerformed(ActionEvent e) {
149 ilm 142
                final Ticket savedReceipt;
143
                try {
144
                    savedReceipt = CaissePanel.this.controler.saveAndClearTicket(caisseFrame.getFiles(), caisseFrame.getConf().getDirectory());
145
                } catch (DifferentDayException ex) {
146
                    JOptionPane.showMessageDialog(CaissePanel.this, "Impossible de laisser la caisse ouverte plusieurs jours. Veuillez la clôturer pour pouvoir faire de nouveaux tickets.", "Erreur",
147
                            JOptionPane.ERROR_MESSAGE);
148
                    return;
149
                } catch (Throwable ex) {
150
                    ExceptionHandler.handle(CaissePanel.this, "Erreur de sauvegarde des informations du ticket", ex);
151
                    return;
152
                }
153
                if (savedReceipt != null) {
144 ilm 154
                    // Valider
155
                    CaissePanel.this.controler.setLCD("Impression de", "votre ticket...", 0);
156
                    try {
156 ilm 157
                        caisseFrame.getPOSConf().print(savedReceipt, (savedReceipt.isAdditionnalCopyRequested() ? 1 : 0));
144 ilm 158
                    } catch (UnsatisfiedLinkError ex) {
159
                        JOptionPane.showMessageDialog(CaissePanel.this, "Erreur de configuration de la liaison à l'imprimante");
160
                    } catch (Throwable ex) {
149 ilm 161
                        ex.printStackTrace();
144 ilm 162
                        JOptionPane.showMessageDialog(CaissePanel.this, "Erreur d'impression du ticket");
163
                    }
149 ilm 164
 
144 ilm 165
                    CaissePanel.this.controler.setLCDDefaultDisplay(2);
142 ilm 166
                }
149 ilm 167
 
142 ilm 168
            }
169
        });
170
        bClients.addActionListener(new ActionListener() {
171
 
172
            @Override
173
            public void actionPerformed(ActionEvent e) {
174
                // Clients
175
                try {
176
                    caisseFrame.showClients();
177
                } catch (Throwable ex) {
178
                    ExceptionHandler.handle("Erreur d'affichage du menu", ex);
179
                }
180
 
181
            }
182
        });
183
 
184
        bMenu.addActionListener(new ActionListener() {
185
 
186
            @Override
187
            public void actionPerformed(ActionEvent e) {
188
                // Menu
189
                try {
190
                    caisseFrame.showMenu();
191
                } catch (Throwable ex) {
192
                    ExceptionHandler.handle("Erreur d'affichage du menu", ex);
193
                }
194
 
195
            }
196
        });
197
 
198
        return s;
199
    }
200
 
144 ilm 201
    private void loadArticles(final SQLElementDirectory dir) {
18 ilm 202
 
149 ilm 203
        final Set<Integer> favoriteProductsIds = controler.loadFavoriteProductsIds();
204
        final List<Article> favoriteProducts = new ArrayList<>();
205
 
83 ilm 206
        final Map<Integer, Categorie> categoriesMap = new HashMap<Integer, Categorie>();
18 ilm 207
 
144 ilm 208
        SQLElement eltFam = dir.getElement("FAMILLE_ARTICLE");
209
        SQLElement eltArticle = dir.getElement("ARTICLE");
18 ilm 210
 
144 ilm 211
        final SQLSelect selFamille = new SQLSelect();
18 ilm 212
        selFamille.addSelectStar(eltFam.getTable());
144 ilm 213
        selFamille.addFieldOrder(eltFam.getTable().getField("CODE"));
149 ilm 214
 
144 ilm 215
        for (SQLRow row : SQLRowListRSH.execute(selFamille)) {
83 ilm 216
            // Map id -> Category
217
            final Categorie cP = categoriesMap.get(row.getInt("ID_FAMILLE_ARTICLE_PERE"));
18 ilm 218
            Categorie c;
219
            if (cP != null) {
220
                c = new Categorie(row.getString("NOM"));
221
                cP.add(c);
222
            } else {
223
                c = new Categorie(row.getString("NOM"), true);
224
            }
225
 
83 ilm 226
            categoriesMap.put(row.getID(), c);
18 ilm 227
        }
228
 
83 ilm 229
        final SQLSelect selArticle = new SQLSelect();
142 ilm 230
        final SQLTable tableArticle = eltArticle.getTable();
144 ilm 231
        selArticle.addAllSelect(tableArticle.getFields(VirtualFields.PRIMARY_KEY.union(VirtualFields.ARCHIVE)));
151 ilm 232
        selArticle.addAllSelect(tableArticle, Arrays.asList("ID_FAMILLE_ARTICLE", "NOM", "CODE", "CODE_BARRE", "ID_TAXE", "PV_HT", "PV_TTC", "ADDITIONAL_TICKET_COPY"));
149 ilm 233
        selArticle.setWhere(new Where(tableArticle.getField("OBSOLETE"), "=", Boolean.FALSE).and(new Where(tableArticle.getField("MASQUE_CAISSE"), "=", Boolean.FALSE)));
18 ilm 234
 
80 ilm 235
        final Categorie cUnclassified = new Categorie("Non classés", true);
149 ilm 236
        cUnclassified.setUnknown();
144 ilm 237
        for (SQLRow row : SQLRowListRSH.execute(selArticle)) {
238
            final int idFamilleArticle = row.getInt("ID_FAMILLE_ARTICLE");
239
            Categorie s1 = categoriesMap.get(idFamilleArticle);
80 ilm 240
            if (s1 == null) {
241
                s1 = cUnclassified;
144 ilm 242
                categoriesMap.put(idFamilleArticle, cUnclassified);
80 ilm 243
            }
244
            final String name = row.getString("NOM").trim();
245
            if (name.length() > 0) {
246
                final Article a = new Article(s1, name, row.getID());
83 ilm 247
                final String barcode = row.getString("CODE_BARRE");
144 ilm 248
                final String code = row.getString("CODE");
249
                a.setBarCode(StringUtils.isEmpty(barcode, true) ? code : barcode);
250
                a.setCode(code);
18 ilm 251
                a.setIdTaxe(row.getInt("ID_TAXE"));
144 ilm 252
                a.setPriceWithoutTax(row.getBigDecimal("PV_HT"));
253
                a.setPriceWithTax(row.getBigDecimal("PV_TTC"));
151 ilm 254
                a.setAdditionalCopyRequested(row.getBoolean("ADDITIONAL_TICKET_COPY"));
149 ilm 255
                final Integer idProduct = a.getId();
256
                if (favoriteProductsIds.contains(idProduct)) {
257
                    favoriteProducts.add(a);
258
                }
259
 
18 ilm 260
            }
261
        }
149 ilm 262
        Categorie.setFavoriteProducts(favoriteProducts);
18 ilm 263
    }
264
 
265
    @Override
266
    public void paint(Graphics g) {
67 ilm 267
        System.err.println("CaissePanel.paint()" + this.getWidth() + " x " + this.getHeight());
18 ilm 268
        super.paint(g);
269
        Graphics2D g2 = (Graphics2D) g;
270
        g.setFont(new Font("Arial", Font.PLAIN, 32));
271
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
142 ilm 272
 
273
        if (this.controler.isClientDefined()) {
274
            g.setColor(CaissePanel.DARK_BLUE);
275
            g.setFont(new Font("Arial", Font.PLAIN, 28));
276
            g.drawString(this.controler.getClient().getFullName(), 20, 75);
277
            g.setColor(Color.GRAY);
278
            g.setFont(g.getFont().deriveFont(18f));
279
            g.drawString("Solde : " + new DecimalFormat("#0.00").format(this.controler.getClient().getSolde()), 20, 120);
280
 
281
        }
282
 
18 ilm 283
        // Prix
284
        int x = 300;
285
        int y = 110;
286
        String euros;
287
        String cents;
288
        Rectangle2D r;
142 ilm 289
        g.setColor(Color.BLACK);
290
        if (this.controler.isClientDefined()) {
291
            g.setFont(g.getFont().deriveFont(46f));
292
            y += 10;
293
        } else {
294
            g.setFont(g.getFont().deriveFont(66f));
295
        }
18 ilm 296
        final int total = this.controler.getTotal();
25 ilm 297
        euros = CaisseControler.getEuros(total) + ".";
298
        cents = CaisseControler.getCents(total);
18 ilm 299
        r = g.getFontMetrics().getStringBounds(euros, g);
300
        x = x - (int) r.getWidth();
301
        g.drawString(euros, x, y);
302
        g.setFont(g.getFont().deriveFont(40f));
303
        g.drawString(cents, x + (int) r.getWidth(), y);
304
        // Paiement
305
        y += 40;
306
        x = 300;
307
        final int paye = this.controler.getPaidTotal();
25 ilm 308
        euros = CaisseControler.getEuros(paye) + ".";
309
        cents = CaisseControler.getCents(paye);
18 ilm 310
 
311
        g.setFont(g.getFont().deriveFont(18f));
312
        Rectangle2D r2 = g.getFontMetrics().getStringBounds("Payé", g);
313
        if (paye >= total) {
314
            g.setColor(Color.DARK_GRAY);
315
        } else {
316
            g.setColor(Color.ORANGE);
317
        }
318
        g.setFont(g.getFont().deriveFont(32f));
319
        r = g.getFontMetrics().getStringBounds(euros, g);
320
        g.drawString(euros, x - (int) r.getWidth(), y);
321
        g.setFont(g.getFont().deriveFont(24f));
322
        g.drawString(cents, x, y);
323
        g.setFont(g.getFont().deriveFont(18f));
324
        g.setColor(Color.GRAY);
325
        g.drawString("Payé", x - (int) r2.getWidth() - (int) r.getWidth() - 10, y);
326
        // A rendre
67 ilm 327
        final boolean minimalHeight = this.getHeight() < 750;
328
        if (!minimalHeight) {
329
            y += 40;
330
            x = 300;
331
        } else {
332
            x = 140;
333
        }
18 ilm 334
        int aRendre = paye - total;
335
        if (aRendre != 0) {
336
            String label;
337
            if (aRendre > 0) {
338
                label = "Rendu";
339
            } else {
67 ilm 340
                if (!minimalHeight) {
341
                    label = "Reste à payer";
342
                } else {
343
                    label = "Doit";
344
                }
18 ilm 345
                aRendre = -aRendre;
346
            }
347
 
25 ilm 348
            euros = CaisseControler.getEuros(aRendre) + ".";
349
            cents = CaisseControler.getCents(aRendre);
18 ilm 350
 
351
            g.setFont(g.getFont().deriveFont(18f));
352
            Rectangle2D r3 = g.getFontMetrics().getStringBounds(label, g);
353
 
354
            g.setColor(Color.DARK_GRAY);
355
            g.setFont(g.getFont().deriveFont(32f));
356
            r = g.getFontMetrics().getStringBounds(euros, g);
357
            g.drawString(euros, x - (int) r.getWidth(), y);
358
            g.setFont(g.getFont().deriveFont(24f));
359
            g.drawString(cents, x, y);
360
            g.setFont(g.getFont().deriveFont(18f));
361
            g.setColor(Color.GRAY);
362
            g.drawString(label, x - (int) r3.getWidth() - (int) r.getWidth() - 10, y);
363
 
364
        }
365
 
366
    }
367
 
368
    @Override
369
    public void caisseStateChanged() {
370
        repaint();
371
    }
83 ilm 372
 
373
    public void switchListMode() {
374
 
375
        GridBagConstraints c = ((GridBagLayout) this.getLayout()).getConstraints(articleSelector);
376
        this.remove(articleSelector);
377
 
378
        if (articleSelector == this.articleSearchPanel) {
379
            articleSelector = this.articleSelectorPanel;
380
        } else {
381
            articleSelector = this.articleSearchPanel;
382
        }
383
        this.add(articleSelector, c);
384
        this.validate();
385
        this.repaint();
386
 
387
    }
132 ilm 388
 
389
    public CaisseControler getControler() {
390
        return controler;
391
    }
18 ilm 392
}