OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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