OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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