OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 150 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
112 ilm 1
package org.openconcerto.modules.operation;
2
 
3
import java.awt.FileDialog;
4
import java.awt.FlowLayout;
5
import java.awt.Frame;
6
import java.awt.GridBagConstraints;
7
import java.awt.GridBagLayout;
8
import java.awt.event.ActionEvent;
9
import java.awt.event.ActionListener;
10
import java.io.File;
11
import java.io.InputStream;
153 ilm 12
import java.math.BigDecimal;
150 ilm 13
import java.text.DateFormat;
14
import java.text.SimpleDateFormat;
112 ilm 15
import java.util.ArrayList;
16
import java.util.Calendar;
17
import java.util.Collections;
18
import java.util.Comparator;
19
import java.util.Date;
20
import java.util.HashSet;
21
import java.util.List;
150 ilm 22
import java.util.ListIterator;
23
import java.util.Map.Entry;
112 ilm 24
import java.util.Set;
150 ilm 25
import java.util.TreeMap;
112 ilm 26
 
27
import javax.swing.ButtonGroup;
28
import javax.swing.JButton;
29
import javax.swing.JCheckBox;
30
import javax.swing.JLabel;
31
import javax.swing.JOptionPane;
32
import javax.swing.JPanel;
33
import javax.swing.JRadioButton;
34
import javax.swing.SwingConstants;
35
import javax.swing.SwingUtilities;
36
import javax.swing.table.AbstractTableModel;
37
import javax.swing.table.TableModel;
153 ilm 38
import javax.xml.datatype.DatatypeConfigurationException;
39
import javax.xml.datatype.DatatypeFactory;
112 ilm 40
 
150 ilm 41
import org.jdom2.Document;
153 ilm 42
import org.jdom2.Element;
112 ilm 43
import org.jopencalendar.model.JCalendarItem;
44
import org.openconcerto.erp.config.ComptaPropsConfiguration;
45
import org.openconcerto.erp.generationDoc.TemplateManager;
46
import org.openconcerto.openoffice.OOUtils;
47
import org.openconcerto.openoffice.spreadsheet.Sheet;
48
import org.openconcerto.openoffice.spreadsheet.SpreadSheet;
150 ilm 49
import org.openconcerto.sql.PropsConfiguration;
112 ilm 50
import org.openconcerto.sql.model.DBRoot;
150 ilm 51
import org.openconcerto.sql.model.FieldMapper;
153 ilm 52
import org.openconcerto.sql.model.SQLRowAccessor;
112 ilm 53
import org.openconcerto.sql.model.SQLRowValues;
54
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
55
import org.openconcerto.sql.model.SQLTable;
56
import org.openconcerto.sql.model.Where;
150 ilm 57
import org.openconcerto.sql.sqlobject.SQLTextCombo;
58
import org.openconcerto.sql.sqlobject.SQLTextCombo.ITextComboCacheSQL;
112 ilm 59
import org.openconcerto.ui.DefaultGridBagConstraints;
60
import org.openconcerto.ui.JDate;
61
import org.openconcerto.ui.date.DateRangePlannerPanel;
150 ilm 62
import org.openconcerto.utils.CollectionMap2.Mode;
63
import org.openconcerto.utils.CompareUtils;
153 ilm 64
import org.openconcerto.utils.DecimalUtils;
112 ilm 65
import org.openconcerto.utils.ExceptionHandler;
150 ilm 66
import org.openconcerto.utils.ListMap;
112 ilm 67
import org.openconcerto.utils.StreamUtils;
150 ilm 68
import org.openconcerto.utils.StringUtils;
69
import org.openconcerto.utils.TimeUtils;
70
import org.openconcerto.xml.JDOM2Utils;
112 ilm 71
 
150 ilm 72
import net.jcip.annotations.GuardedBy;
73
 
112 ilm 74
public class OperationExportPanel extends JPanel {
150 ilm 75
 
76
    @GuardedBy("EDT")
77
    static private final DateFormat DF = new SimpleDateFormat("yyyyMMdd");
78
 
112 ilm 79
    final JCheckBox lockedCheckBox = new JCheckBox("verrouillées uniquement");
80
    final JButton bPrint = new JButton("Exporter");
81
 
82
    public OperationExportPanel(final OperationCalendarManager manager, final List<SQLRowValues> rowsSite) {
83
        lockedCheckBox.setSelected(true);
84
        //
85
        this.setLayout(new GridBagLayout());
86
        final GridBagConstraints c = new DefaultGridBagConstraints();
87
        final JLabel l = new JLabel("Date de début", SwingConstants.RIGHT);
88
        this.add(l, c);
89
        c.gridx++;
90
        final JDate d1 = new JDate(false, true);
91
        Calendar cal = Calendar.getInstance();
92
        cal.set(Calendar.DAY_OF_MONTH, 1);
93
        cal.set(Calendar.HOUR_OF_DAY, 0);
94
        cal.set(Calendar.MINUTE, 0);
95
        cal.set(Calendar.SECOND, 0);
96
        cal.set(Calendar.MILLISECOND, 0);
97
        d1.setDate(cal.getTime());
98
        c.weightx = 1;
99
        this.add(d1, c);
100
        c.gridx = 0;
101
        c.gridy++;
102
        c.weightx = 0;
103
        final JLabel l2 = new JLabel("Date de fin", SwingConstants.RIGHT);
104
 
105
        this.add(l2, c);
106
        c.gridx++;
107
        final JDate d2 = new JDate(false, true);
108
        cal.add(Calendar.MONTH, 1);
109
        cal.add(Calendar.SECOND, -1);
110
        d2.setDate(cal.getTime());
111
        c.weightx = 1;
112
        this.add(d2, c);
113
 
150 ilm 114
        final OperationSQLElement operationElem = manager.getDirectory().getElement(OperationSQLElement.class);
115
        final OperationSQLComponent operationSQLComp = new OperationSQLComponent(operationElem);
116
        final String statusID = "operation.status";
117
        c.gridy++;
118
        c.gridx = 0;
119
        c.gridwidth = 1;
120
        this.add(operationSQLComp.getLabel(statusID), c);
121
        c.gridx++;
122
        final SQLTextCombo statusCombo = (SQLTextCombo) operationSQLComp.createEditor(statusID);
123
        final FieldMapper fieldMapper = PropsConfiguration.getInstance().getFieldMapper();
124
        statusCombo.initCache(new ITextComboCacheSQL(fieldMapper.getSQLFieldForItem(statusID)));
125
        this.add(statusCombo, c);
126
 
112 ilm 127
        //
128
        c.gridwidth = 2;
129
        c.gridx = 0;
130
        c.gridy++;
131
        final JRadioButton radio1 = new JRadioButton("interventions");
132
        radio1.setSelected(true);
133
        this.add(radio1, c);
150 ilm 134
        final JRadioButton radio2 = new JRadioButton("planifications");
112 ilm 135
        c.gridy++;
136
        this.add(radio2, c);
137
        final ButtonGroup g = new ButtonGroup();
138
        g.add(radio1);
139
        g.add(radio2);
140
 
141
        //
142
        final JPanel p = new JPanel();
143
        p.setLayout(new FlowLayout(FlowLayout.RIGHT));
144
        p.add(lockedCheckBox);
145
        p.add(bPrint);
146
        c.gridwidth = 2;
147
        c.gridx = 0;
148
        c.gridy++;
149
        c.fill = GridBagConstraints.NONE;
150
        c.anchor = GridBagConstraints.SOUTHEAST;
151
        this.add(p, c);
152
        //
153
 
154
        bPrint.addActionListener(new ActionListener() {
155
 
156
            @Override
157
            public void actionPerformed(ActionEvent e) {
158
                if (d1.getDate().after(d2.getDate())) {
159
                    return;
160
                }
150 ilm 161
                final String statusVal = statusCombo.getValue();
162
                final List<String> states = StringUtils.isEmpty(statusVal, true) ? null : Collections.singletonList(statusVal);
163
                final List<JCalendarItem> items = manager.getItemIn(d1.getDate(), d2.getDate(), null, states);
112 ilm 164
                final List<JCalendarItemDB> itemsToExport = new ArrayList<JCalendarItemDB>(items.size());
165
                if (lockedCheckBox.isSelected()) {
166
                    for (JCalendarItem jCalendarItem : items) {
167
                        JCalendarItemDB i = (JCalendarItemDB) jCalendarItem;
168
                        if (i.getFlagsString().contains("locked")) {
169
                            itemsToExport.add(i);
170
                        }
171
                    }
172
                } else {
173
                    for (JCalendarItem jCalendarItem : items) {
174
                        JCalendarItemDB i = (JCalendarItemDB) jCalendarItem;
175
                        itemsToExport.add(i);
176
                    }
177
                }
178
                if (rowsSite != null && !rowsSite.isEmpty()) {
179
                    final Set<String> allowedSites = new HashSet<String>();
180
                    for (SQLRowValues r : rowsSite) {
181
                        String siteName = r.getString("NAME");
182
                        allowedSites.add(siteName);
183
                    }
184
                    final List<JCalendarItemDB> filtered = new ArrayList<JCalendarItemDB>(itemsToExport.size());
185
                    for (JCalendarItemDB i : itemsToExport) {
186
                        if (allowedSites.contains(i.getSiteName())) {
187
                            filtered.add(i);
188
                        }
189
                    }
190
                    itemsToExport.clear();
191
                    itemsToExport.addAll(filtered);
192
                }
193
 
194
                if (itemsToExport.isEmpty()) {
195
                    JOptionPane.showMessageDialog(OperationExportPanel.this, "Aucune intervention trouvée.\nMerci de vérifier la période et le verrouillage des interventions.");
196
                    return;
197
                }
198
 
199
                Collections.sort(itemsToExport, new Comparator<JCalendarItem>() {
200
 
201
                    @Override
202
                    public int compare(JCalendarItem o1, JCalendarItem o2) {
203
                        if (o1.getUserId().equals(o2.getUserId())) {
204
                            return o1.getDtStart().getTime().compareTo(o2.getDtStart().getTime());
205
                        }
206
                        return (int) (((Number) o1.getUserId()).longValue() - ((Number) o2.getUserId()).longValue());
207
                    }
208
                });
150 ilm 209
                final String dates = " " + DF.format(d1.getDate()) + '-' + DF.format(d2.getDate());
112 ilm 210
                if (radio1.isSelected()) {
150 ilm 211
                    export(itemsToExport, "export " + radio1.getText() + dates);
112 ilm 212
                } else {
150 ilm 213
                    exportPlan(itemsToExport, "export " + radio2.getText() + dates);
112 ilm 214
                }
215
                closeFrame();
216
 
217
            }
218
        });
219
    }
220
 
150 ilm 221
    static private final class Planner implements Comparable<Planner> {
153 ilm 222
 
223
        static private final BigDecimal MS_PER_HOUR = BigDecimal.valueOf(1000 * 3600);
224
 
150 ilm 225
        private final String uid;
226
        private final String xml;
227
        private Date rangeStart;
153 ilm 228
        private Date startTime;
229
        private BigDecimal hours;
112 ilm 230
 
150 ilm 231
        protected Planner(String uid, String xml) {
232
            super();
233
            this.uid = uid;
234
            this.xml = xml;
235
        }
236
 
237
        public final String getUID() {
238
            return this.uid;
239
        }
240
 
241
        public final String getDescription() {
153 ilm 242
            return DateRangePlannerPanel.getDescriptionFromXML(this.xml, false);
150 ilm 243
        }
244
 
245
        public final Date getRangeStart() {
246
            if (this.rangeStart == null) {
153 ilm 247
                parse();
150 ilm 248
            }
249
            return this.rangeStart;
250
        }
251
 
153 ilm 252
        protected void parse() {
253
            try {
254
                final Document doc = JDOM2Utils.parseStringDocument(this.xml);
255
                this.rangeStart = new Date(Long.valueOf(doc.getRootElement().getChild("range").getAttributeValue("start")));
256
 
257
                final Element scheduleElem = doc.getRootElement().getChild("schedule");
258
                this.startTime = new Date(Long.valueOf(scheduleElem.getAttributeValue("start")));
259
                final long endTime = Long.valueOf(scheduleElem.getAttributeValue("end"));
260
                this.hours = DecimalUtils.round(BigDecimal.valueOf(endTime - this.startTime.getTime()).divide(MS_PER_HOUR, DecimalUtils.HIGH_PRECISION), 5);
261
            } catch (Exception e) {
262
                throw new IllegalStateException("couldn't get start for " + this.xml, e);
263
            }
264
        }
265
 
266
        public final Date getStartTime() {
267
            if (this.startTime == null) {
268
                parse();
269
            }
270
            return this.startTime;
271
        }
272
 
273
        public final BigDecimal getHours() {
274
            if (this.hours == null) {
275
                parse();
276
            }
277
            return this.hours;
278
        }
279
 
150 ilm 280
        @Override
281
        public int hashCode() {
282
            final int prime = 31;
283
            int result = 1;
284
            result = prime * result + this.uid.hashCode();
285
            return result;
286
        }
287
 
288
        @Override
289
        public boolean equals(Object obj) {
290
            if (this == obj)
291
                return true;
292
            if (obj == null)
293
                return false;
294
            if (getClass() != obj.getClass())
295
                return false;
296
            Planner other = (Planner) obj;
297
            return this.uid.equals(other.uid);
298
        }
299
 
300
        @Override
301
        public int compareTo(Planner o) {
302
            if (this.equals(o))
303
                return 0;
304
            final int startComparison = this.getRangeStart().compareTo(o.getRangeStart());
305
            if (startComparison != 0)
306
                return startComparison;
307
            return this.getUID().compareTo(o.getUID());
308
 
309
        }
310
    }
311
 
312
    protected void exportPlan(List<JCalendarItemDB> itemsToExport, final String name) {
313
 
112 ilm 314
        final List<Long> ids = ModuleOperation.getOperationIdsFrom(new HashSet<JCalendarItemDB>(itemsToExport));
315
 
316
        final DBRoot root = ComptaPropsConfiguration.getInstanceCompta().getRootSociete();
317
        final SQLTable table = root.getTable(ModuleOperation.TABLE_OPERATION);
318
        final SQLRowValues valOperation = new SQLRowValues(table);
319
 
320
        final SQLRowValues valSite = new SQLRowValues(root.getTable(ModuleOperation.TABLE_SITE));
321
        valSite.putNulls("NAME", "COMMENT");
322
 
153 ilm 323
        valOperation.putRowValues("ID_USER_COMMON").putNulls("NOM", "PRENOM");
112 ilm 324
        // valOperation.put("ID_CALENDAR_ITEM_GROUP", valsCalendarItemsGroup);
325
        valOperation.put("ID_SITE", valSite);
326
        valOperation.putNulls("STATUS", "DESCRIPTION", "TYPE", "PLANNER_XML", "PLANNER_UID");
327
 
328
        final SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(valOperation);
329
        fetcher.setFullOnly(true);
330
 
150 ilm 331
        final List<SQLRowValues> itemsFetched = fetcher.fetch(new Where(table.getKey(), ids).and(Where.createRaw("length(" + table.getField("PLANNER_UID").getFieldRef() + ")>2")));
332
        final ListMap<Planner, SQLRowValues> operationsByPlanner = new ListMap<>(new TreeMap<Planner, List<SQLRowValues>>(), Mode.NULL_FORBIDDEN);
112 ilm 333
        for (SQLRowValues d : itemsFetched) {
150 ilm 334
            operationsByPlanner.add(new Planner(d.getString("PLANNER_UID"), d.getString("PLANNER_XML")), d);
112 ilm 335
        }
150 ilm 336
        final List<Entry<Planner, List<SQLRowValues>>> items = new ArrayList<>(operationsByPlanner.entrySet());
153 ilm 337
        final DatatypeFactory dataTypeFactory;
338
        try {
339
            dataTypeFactory = DatatypeFactory.newInstance();
340
        } catch (DatatypeConfigurationException e) {
341
            throw new IllegalStateException(e);
342
        }
112 ilm 343
 
344
        TableModel model = new AbstractTableModel() {
345
 
346
            @Override
347
            public int getRowCount() {
348
                return items.size();
349
            }
350
 
351
            @Override
352
            public int getColumnCount() {
153 ilm 353
                return 7;
112 ilm 354
            }
355
 
356
            @Override
357
            public Object getValueAt(int rowIndex, int columnIndex) {
150 ilm 358
                final Entry<Planner, List<SQLRowValues>> rows = items.get(rowIndex);
359
                final Planner planner = rows.getKey();
360
                // for now, only the "Employé" column check all operations for a planner, the other
361
                // columns just take the first one.
362
                final SQLRowValues i = rows.getValue().get(0);
112 ilm 363
                switch (columnIndex) {
364
                case 0:
153 ilm 365
                    return dataTypeFactory.newDurationDayTime(planner.getStartTime().getTime());
366
 
367
                case 1:
368
                    return planner.getHours();
369
 
370
                case 2:
112 ilm 371
                    // Plannif
150 ilm 372
                    return planner.getDescription();
112 ilm 373
 
153 ilm 374
                case 3:
112 ilm 375
                    // Employé
150 ilm 376
                    final ListMap<Integer, SQLRowValues> operationsByUserID = new ListMap<>();
377
                    for (final SQLRowValues r : rows.getValue()) {
378
                        operationsByUserID.add(r.getForeignID("ID_USER_COMMON"), r);
379
                    }
380
                    final List<Entry<Integer, List<SQLRowValues>>> entries = new ArrayList<>(operationsByUserID.entrySet());
381
                    // the users with the most operations first
382
                    Collections.sort(entries, new Comparator<Entry<Integer, List<SQLRowValues>>>() {
383
                        @Override
384
                        public int compare(Entry<Integer, List<SQLRowValues>> o1, Entry<Integer, List<SQLRowValues>> o2) {
385
                            final int sizeComparison = CompareUtils.compareInt(o1.getValue().size(), o2.getValue().size());
386
                            if (sizeComparison != 0)
387
                                return -sizeComparison;
388
                            return o1.getKey().compareTo(o2.getKey());
389
                        }
390
                    });
391
                    final ListIterator<Entry<Integer, List<SQLRowValues>>> listIter = entries.listIterator();
392
                    final StringBuilder sb = new StringBuilder(128);
393
                    while (listIter.hasNext()) {
394
                        final Entry<Integer, List<SQLRowValues>> element = listIter.next();
395
                        final SQLRowValues operationR = element.getValue().get(0);
153 ilm 396
                        final SQLRowAccessor userR = operationR.getForeign("ID_USER_COMMON");
397
                        sb.append(userR.getString("PRENOM") + " " + userR.getString("NOM"));
150 ilm 398
                        if (listIter.previousIndex() > 0) {
399
                            sb.append(" (");
400
                            sb.append(element.getValue().size());
401
                            sb.append(")");
402
                        }
403
                        if (listIter.hasNext()) {
404
                            sb.append(", ");
405
                        }
406
                    }
407
                    return sb.toString();
153 ilm 408
                case 4:
112 ilm 409
                    // Nature
410
                    final String type = i.getString("TYPE");
411
                    return type;
153 ilm 412
                case 5:
112 ilm 413
                    // Chantier
414
                    final String siteName = i.getForeign("ID_SITE").getString("NAME");
415
                    return siteName;
153 ilm 416
                case 6:
112 ilm 417
                    // Description
418
                    final String desc = i.getString("DESCRIPTION");
419
                    return desc;
420
                default:
421
                    break;
422
                }
423
                return "?";
424
            }
425
 
426
        };
427
 
428
        // Save the data to an ODS file and open it.
429
        final String templateId = ModuleOperation.OPERATIONS_REPORT_TEMPLATE2_ID;
150 ilm 430
        saveAsODS(model, templateId, name);
112 ilm 431
    }
432
 
150 ilm 433
    protected void export(final List<JCalendarItemDB> items, final String name) {
112 ilm 434
 
435
        TableModel model = new AbstractTableModel() {
436
 
437
            @Override
438
            public int getRowCount() {
439
                return items.size();
440
            }
441
 
442
            @Override
443
            public int getColumnCount() {
444
                return 7;
445
            }
446
 
447
            @Override
448
            public Object getValueAt(int rowIndex, int columnIndex) {
449
                JCalendarItemDB i = items.get(rowIndex);
450
                switch (columnIndex) {
451
                case 0:
452
                    // Date
150 ilm 453
                    Date start = TimeUtils.clearTime((Calendar) i.getDtStart().clone()).getTime();
112 ilm 454
                    return start;
455
                case 1:
456
                    // Heure
457
                    Calendar h = i.getDtStart();
458
                    return h;
459
                case 2:
460
                    // Durée
461
                    long m = (i.getDtEnd().getTimeInMillis() - i.getDtStart().getTimeInMillis()) / (1000 * 60);
462
                    return m;
463
                case 3:
464
                    // Employé
150 ilm 465
                    final SQLRowValues user = i.getUserRow();
466
                    return user.getString("PRENOM") + " " + user.getString("NOM");
112 ilm 467
                case 4:
468
                    // Nature
469
                    final String type = i.getType();
470
                    return type;
471
                case 5:
472
                    // Chantier
473
                    final String siteName = i.getSiteName();
474
                    return siteName;
475
                case 6:
476
                    // Description
477
                    final String desc = i.getDescription();
478
                    return desc;
479
                default:
480
                    break;
481
                }
482
                return "?";
483
            }
484
 
485
        };
486
 
487
        // Save the data to an ODS file and open it.
488
        final String templateId = ModuleOperation.OPERATIONS_REPORT_TEMPLATE_ID;
150 ilm 489
        saveAsODS(model, templateId, name);
112 ilm 490
 
491
    }
492
 
150 ilm 493
    public void saveAsODS(TableModel model, final String templateId, final String name) {
112 ilm 494
        try {
495
            final InputStream inStream = TemplateManager.getInstance().getTemplate(templateId);
496
            final File templateFile = File.createTempFile(templateId, ".ods");
497
            if (inStream == null) {
498
                JOptionPane.showMessageDialog(this, "Modèle introuvable");
499
                return;
500
            }
501
            StreamUtils.copy(inStream, templateFile);
502
            inStream.close();
503
            final Sheet sheet = SpreadSheet.createFromFile(templateFile).getSheet(0);
504
            final int rowCount = model.getRowCount();
505
            sheet.ensureRowCount(rowCount + 1);
506
            final int columnCount = model.getColumnCount();
507
            for (int x = 0; x < columnCount; x++) {
508
                for (int y = 0; y < rowCount; y++) {
509
                    sheet.setValueAt(model.getValueAt(y, x), x, y + 1);
510
                }
511
            }
512
 
513
            final FileDialog d = new FileDialog((Frame) SwingUtilities.getWindowAncestor(this), "Exporter sous...", FileDialog.SAVE);
150 ilm 514
            d.setFile(name + ".ods");
112 ilm 515
            d.setVisible(true);
516
            String fileName = d.getFile();
517
            if (fileName != null) {
518
                fileName = fileName.trim();
519
                if (!fileName.toLowerCase().endsWith(".ods")) {
520
                    fileName += ".ods";
521
                }
522
                File outputFile = new File(d.getDirectory(), fileName);
523
                final File saveAs = sheet.getSpreadSheet().saveAs(outputFile);
524
                OOUtils.open(saveAs);
525
            } else {
526
                JOptionPane.showMessageDialog(this, "Fichier non spécifié");
527
            }
528
        } catch (Exception e) {
529
            ExceptionHandler.handle("Export error", e);
530
        }
531
    }
532
 
533
    protected void closeFrame() {
534
        SwingUtilities.getWindowAncestor(this).dispose();
535
    }
536
 
537
}