OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 144 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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