OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 93 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
80 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.model;
15
 
16
import org.openconcerto.erp.preferences.TemplateNXProps;
17
import org.openconcerto.utils.ExceptionHandler;
18
import org.openconcerto.utils.FileUtils;
19
 
20
import java.io.File;
21
import java.io.FileFilter;
22
import java.io.IOException;
23
import java.text.DecimalFormat;
24
import java.text.Format;
25
import java.text.ParseException;
26
import java.text.ParsePosition;
27
import java.text.SimpleDateFormat;
28
import java.util.ArrayList;
29
import java.util.Arrays;
30
import java.util.Calendar;
31
import java.util.Collections;
32
import java.util.Date;
33
import java.util.List;
34
 
35
public class ReceiptCode {
36
 
37
    // year/month/day
38
    static private final int DIR_DEPTH = 3;
39
    static private final int FILE_DEPTH = DIR_DEPTH + 1;
40
    static private final String EXT = ".xml";
41
    static private final String DELETED_SUFFIX = "_deleted";
42
    static private final String DELETED_EXT = EXT + DELETED_SUFFIX;
43
    static private final String IMPORTED_SUFFIX = "_imported";
44
    static private final String IMPORTED_EXT = EXT + IMPORTED_SUFFIX;
45
 
46
    static public final File getRootDir() {
47
        return getRootDir(false);
48
    }
49
 
50
    static public final File getRootDir(final boolean archived) {
51
        final TemplateNXProps nxprops = (TemplateNXProps) TemplateNXProps.getInstance();
52
        return new File(nxprops.getDefaultStringValue(), archived ? "Tickets archivés" : "Tickets");
53
    }
54
 
55
    static public final File getDayDir(final Calendar cal, final boolean create) {
56
        final int j = cal.get(Calendar.DAY_OF_MONTH);
57
        final int m = cal.get(Calendar.MONTH) + 1;
58
        final int a = cal.get(Calendar.YEAR);
59
        final List<String> dirs = Arrays.asList(DIGIT4_FORMAT.format(a), DIGIT2_FORMAT.format(m), DIGIT2_FORMAT.format(j));
60
        assert dirs.size() == DIR_DEPTH;
61
        File res = getRootDir();
62
        for (final String dir : dirs) {
63
            res = new File(res, dir);
64
        }
65
        if (create) {
66
            try {
67
                FileUtils.mkdir_p(res);
68
            } catch (IOException e) {
69
                ExceptionHandler.handle("Impossible de créer le dossier des tickets.\n\n" + res.getAbsolutePath());
70
            }
71
        }
72
        return res;
73
    }
74
 
75
    static public final List<File> getReceiptsToImport(final int caisseNb) {
76
        return FileUtils.list(getRootDir(), FILE_DEPTH, createFF(DIGIT2_FORMAT.format(caisseNb), false, false));
77
    }
78
 
79
    protected static FileFilter createFF(final String prefix, final boolean includeDeleted, final boolean includeImported) {
80
        return new FileFilter() {
81
            @Override
82
            public boolean accept(File f) {
83
                if (!f.isFile() || !f.getName().startsWith(prefix))
84
                    return false;
85
                return f.getName().endsWith(EXT) || (includeDeleted && f.getName().endsWith(DELETED_EXT)) || (includeImported && f.getName().endsWith(IMPORTED_EXT));
86
            }
87
        };
88
    }
89
 
90
    static private final String getEnd(final String s, final List<String> candidates) {
91
        for (final String candidate : candidates)
92
            if (s.endsWith(candidate))
93
                return candidate;
94
        return null;
95
    }
96
 
97
    static public final ReceiptCode fromFile(final File f) {
98
        final String name = f.getName();
99
        final String toRm = getEnd(name, Arrays.asList(EXT, DELETED_EXT, IMPORTED_EXT));
100
        if (toRm == null)
101
            return null;
102
        try {
103
            return new ReceiptCode(name.substring(0, name.length() - toRm.length()));
104
        } catch (ParseException e) {
105
            return null;
106
        }
107
    }
108
 
109
    static public void archiveCompletelyImported() throws IOException {
110
        final File archiveDir = getRootDir(true);
111
        FileUtils.mkdir_p(archiveDir);
112
        final File rootDir = getRootDir(false);
113
        final List<File> dirs = FileUtils.list(rootDir, DIR_DEPTH, FileUtils.DIR_FILTER);
114
        // don't archive today otherwise number will be wrong (see Ticket.initNumber())
115
        final File todayDir = getDayDir(Ticket.getCalendar(), false);
116
        for (final File dir : dirs) {
117
            // if all receipts are deleted or imported : archive
118
            if (!todayDir.equals(dir) && dir.listFiles(createFF("", false, false)).length == 0) {
119
                final File destDir = new File(archiveDir, FileUtils.relative(rootDir, dir));
120
                FileUtils.mkParentDirs(destDir);
121
                if (!destDir.exists()) {
122
                    // move
123
                    final String err = FileUtils.mv(dir, destDir);
124
                    if (err != null)
125
                        throw new IOException(err);
126
                } else {
127
                    // merge
128
                    for (final File f : dir.listFiles()) {
129
                        FileUtils.mv(f, destDir);
130
                    }
131
                    FileUtils.rm(dir);
132
                }
133
                assert !dir.exists();
134
            }
135
        }
136
    }
137
 
138
    static private final DecimalFormat DIGIT2_FORMAT = new DecimalFormat("00");
139
    static private final DecimalFormat DIGIT4_FORMAT = new DecimalFormat("0000");
140
    static private final DecimalFormat INDEX_FORMAT = new DecimalFormat("00000");
141
 
142
    static {
143
        DIGIT2_FORMAT.setMaximumIntegerDigits(DIGIT2_FORMAT.getMinimumIntegerDigits());
144
        DIGIT4_FORMAT.setMaximumIntegerDigits(DIGIT4_FORMAT.getMinimumIntegerDigits());
145
        INDEX_FORMAT.setMaximumIntegerDigits(INDEX_FORMAT.getMinimumIntegerDigits());
146
    }
147
 
148
    static private Number parse(final DecimalFormat f, final String s, final ParsePosition pos) throws ParseException {
149
        return (Number) parse(f, s, pos, f.getMaximumIntegerDigits());
150
    }
151
 
152
    static private Date parse(final SimpleDateFormat f, final String s, final ParsePosition pos) throws ParseException {
153
        // only works for fixed width pattern
154
        return (Date) parse(f, s, pos, f.toPattern().length());
155
    }
156
 
157
    // formats almost always try to parse to the end of the string, this method prevents that
158
    static private Object parse(final Format f, final String s, final ParsePosition pos, final int maxChar) throws ParseException {
159
        return f.parseObject(s.substring(0, pos.getIndex() + maxChar), pos);
160
    }
161
 
162
    private final int caisseNb;
163
    private final Calendar day;
164
    private final int dayIndex;
165
    private final String code;
166
 
167
    private SimpleDateFormat dateFormat;
168
 
169
    public ReceiptCode(String code) throws ParseException {
170
        super();
171
        // Code: 01_05042011_00002
172
        // filtre les chiffres
173
        final StringBuilder b = new StringBuilder();
174
        for (int i = 0; i < code.length(); i++) {
175
            final char c = code.charAt(i);
176
            if (Character.isDigit(c)) {
177
                b.append(c);
178
            }
179
        }
180
        code = b.toString();
181
        // Code: 010504201100002
182
        this.code = code;
183
        this.setCalendar(Ticket.getCalendar());
184
 
185
        // Code: 0105041300002
186
        // n°caisse sur 2 caracteres
187
        // date jour mois année JJMMAA
188
        // numero de ticket formaté sur 5 caractères
189
        final ParsePosition pos = new ParsePosition(0);
190
        this.caisseNb = parse(DIGIT2_FORMAT, code, pos).intValue();
191
        this.day = getCalendar();
192
        this.day.setTime(parse(this.dateFormat, code, pos));
193
        this.dayIndex = parse(INDEX_FORMAT, code, pos).intValue();
194
    }
195
 
196
    public ReceiptCode(final int caisseNb, final Calendar cal, final int dayIndex) {
197
        super();
198
        this.setCalendar(cal);
199
        this.caisseNb = caisseNb;
200
        this.day = (Calendar) cal.clone();
201
        this.dayIndex = dayIndex;
202
        this.code = DIGIT2_FORMAT.format(this.caisseNb) + this.dateFormat.format(this.day.getTime()) + INDEX_FORMAT.format(this.dayIndex);
203
    }
204
 
205
    public final void setCalendar(final Calendar newCal) {
206
        final Calendar cal = (Calendar) newCal.clone();
207
        this.dateFormat = new SimpleDateFormat("ddMMyy");
208
        this.dateFormat.setCalendar(cal);
209
        cal.clear();
210
        cal.set(2000, 0, 1);
211
        this.dateFormat.set2DigitYearStart(cal.getTime());
212
    }
213
 
214
    public final Calendar getCalendar() {
215
        return (Calendar) this.dateFormat.getCalendar().clone();
216
    }
217
 
218
    public final int getCaisseNb() {
219
        return this.caisseNb;
220
    }
221
 
222
    public final Calendar getDay() {
223
        return this.day;
224
    }
225
 
226
    public final int getDayIndex() {
227
        return this.dayIndex;
228
    }
229
 
230
    public final String getCodePrefix() {
231
        return this.code.substring(0, this.code.length() - INDEX_FORMAT.getMinimumIntegerDigits());
232
    }
233
 
234
    public final String getCode() {
235
        return this.code;
236
    }
237
 
238
    public final File getDir(final boolean create) {
239
        return getDayDir(getDay(), create);
240
    }
241
 
242
    public final File getFile() {
243
        return new File(getDir(true), getFileName());
244
    }
245
 
246
    public final String getFileName() {
247
        return getCode().replace(' ', '_') + EXT;
248
    }
249
 
250
    public void markDeleted() throws IOException {
251
        mark(DELETED_SUFFIX);
252
    }
253
 
254
    public void markImported() throws IOException {
255
        mark(IMPORTED_SUFFIX);
256
    }
257
 
258
    private final void mark(final String suffix) throws IOException {
259
        final File f = getFile();
260
        if (!f.renameTo(new File(f.getParentFile(), f.getName() + suffix)))
261
            throw new IOException("Couldn't rename " + f);
262
    }
263
 
264
    public final List<ReceiptCode> getSameDayCodes(final boolean includeAll) {
265
        final File dir = getDir(false);
266
        final File[] listFiles = dir.listFiles(createFF(getCodePrefix(), includeAll, includeAll));
267
        if (listFiles == null)
268
            return Collections.emptyList();
269
 
270
        final List<ReceiptCode> res = new ArrayList<ReceiptCode>(listFiles.length);
271
        for (final File f : listFiles) {
272
            res.add(fromFile(f));
273
        }
274
        return res;
275
    }
276
}