OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 142 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 142 Rev 156
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.finance.accounting.model;
14
 package org.openconcerto.erp.core.finance.accounting.model;
15
 
15
 
16
import org.openconcerto.erp.config.ComptaPropsConfiguration;
16
import org.openconcerto.erp.config.ComptaPropsConfiguration;
17
import org.openconcerto.sql.model.DBRoot;
17
import org.openconcerto.sql.model.DBRoot;
18
import org.openconcerto.sql.model.Order;
18
import org.openconcerto.sql.model.Order;
19
import org.openconcerto.sql.model.SQLRow;
19
import org.openconcerto.sql.model.SQLRow;
20
import org.openconcerto.sql.model.SQLRowListRSH;
20
import org.openconcerto.sql.model.SQLRowListRSH;
21
import org.openconcerto.sql.model.SQLSelect;
21
import org.openconcerto.sql.model.SQLSelect;
22
import org.openconcerto.sql.model.SQLTable;
22
import org.openconcerto.sql.model.SQLTable;
23
import org.openconcerto.sql.model.Where;
23
import org.openconcerto.sql.model.Where;
24
import org.openconcerto.utils.DecimalUtils;
24
import org.openconcerto.utils.DecimalUtils;
-
 
25
import org.openconcerto.utils.Tuple2;
-
 
26
import org.openconcerto.utils.Tuple3;
25
 
27
 
26
import java.math.BigDecimal;
28
import java.math.BigDecimal;
27
import java.util.ArrayList;
29
import java.util.ArrayList;
28
import java.util.Arrays;
30
import java.util.Arrays;
29
import java.util.Calendar;
31
import java.util.Calendar;
30
import java.util.Date;
32
import java.util.Date;
-
 
33
import java.util.HashMap;
31
import java.util.List;
34
import java.util.List;
-
 
35
import java.util.Map;
32
import java.util.TimeZone;
36
import java.util.TimeZone;
33
 
37
 
34
public class CurrencyConverter {
38
public class CurrencyConverter {
35
    private String companyCurrencyCode;
39
    private String companyCurrencyCode;
36
    private final DBRoot root;
40
    private final DBRoot root;
37
 
-
 
-
 
41
    private boolean useCache = false;
38
    private String baseCurrencyCode;
42
    private String baseCurrencyCode;
39
 
43
 
40
    public CurrencyConverter(DBRoot rootSociete, String companyCurrencyCode, String baseCurrencyCode) {
44
    public CurrencyConverter(DBRoot rootSociete, String companyCurrencyCode, String baseCurrencyCode) {
41
        if (companyCurrencyCode == null || companyCurrencyCode.isEmpty()) {
45
        if (companyCurrencyCode == null || companyCurrencyCode.isEmpty()) {
42
            this.companyCurrencyCode = "EUR";
46
            this.companyCurrencyCode = "EUR";
43
        } else {
47
        } else {
44
            this.companyCurrencyCode = companyCurrencyCode.trim().toUpperCase();
48
            this.companyCurrencyCode = companyCurrencyCode.trim().toUpperCase();
45
        }
49
        }
46
        this.baseCurrencyCode = baseCurrencyCode;
50
        this.baseCurrencyCode = baseCurrencyCode;
47
        this.root = rootSociete;
51
        this.root = rootSociete;
48
    }
52
    }
49
 
53
 
50
    public CurrencyConverter() {
54
    public CurrencyConverter() {
51
        this(ComptaPropsConfiguration.getInstanceCompta().getRootSociete(), ComptaPropsConfiguration.getInstanceCompta().getCurrency().getCode(), "EUR");
55
        this(ComptaPropsConfiguration.getInstanceCompta().getRootSociete(), ComptaPropsConfiguration.getInstanceCompta().getCurrency().getCode(), "EUR");
52
    }
56
    }
53
 
57
 
54
    public String getCompanyCurrencyCode() {
58
    public String getCompanyCurrencyCode() {
55
        return companyCurrencyCode;
59
        return companyCurrencyCode;
56
    }
60
    }
57
 
61
 
58
    public String getBaseCurrencyCode() {
62
    public String getBaseCurrencyCode() {
59
        return baseCurrencyCode;
63
        return baseCurrencyCode;
60
    }
64
    }
61
 
65
 
-
 
66
    public void setUseCache(boolean useCache) {
-
 
67
        this.useCache = useCache;
-
 
68
    }
-
 
69
 
62
    /**
70
    /**
63
     * Converter an amount to an other currency
71
     * Converter an amount to an other currency
64
     */
72
     */
65
    public BigDecimal convert(BigDecimal amount, String from, String to) {
73
    public BigDecimal convert(BigDecimal amount, String from, String to) {
66
        return convert(amount, from, to, Calendar.getInstance().getTime());
74
        return convert(amount, from, to, Calendar.getInstance().getTime());
67
    }
75
    }
68
 
76
 
69
    /**
77
    /**
70
     * Converter an amount to an other currency at a precise date
78
     * Converter an amount to an other currency at a precise date
71
     */
79
     */
72
    public BigDecimal convert(BigDecimal amount, String from, String to, Date date) {
80
    public BigDecimal convert(BigDecimal amount, String from, String to, Date date) {
73
        return convert(amount, from, to, date, false);
81
        return convert(amount, from, to, date, false);
74
    }
82
    }
75
 
83
 
-
 
84
    Map<Tuple3<String, String, Date>, Tuple2<BigDecimal, BigDecimal>> cacheBiased = new HashMap<Tuple3<String, String, Date>, Tuple2<BigDecimal, BigDecimal>>();
-
 
85
    Map<Tuple3<String, String, Date>, Tuple2<BigDecimal, BigDecimal>> cacheNotBiased = new HashMap<Tuple3<String, String, Date>, Tuple2<BigDecimal, BigDecimal>>();
-
 
86
 
-
 
87
    public void clearCache() {
-
 
88
        cacheBiased.clear();
-
 
89
        cacheNotBiased.clear();
-
 
90
    }
-
 
91
 
76
    /**
92
    /**
77
     * Converter an amount to an other currency at a precise date
93
     * Converter an amount to an other currency at a precise date
78
     */
94
     */
79
    public BigDecimal convert(BigDecimal amount, String from, String to, Date date, boolean useBiased) {
95
    public BigDecimal convert(BigDecimal amount, String from, String to, Date date, boolean useBiased) {
80
 
96
 
81
        if (from.equalsIgnoreCase(to)) {
97
        if (from.equalsIgnoreCase(to)) {
82
            return amount;
98
            return amount;
83
        }
99
        }
84
 
100
 
-
 
101
        if (amount.signum() == 0) {
-
 
102
            return BigDecimal.ZERO;
-
 
103
        }
-
 
104
 
-
 
105
        BigDecimal r1 = null;
-
 
106
        BigDecimal r2 = null;
-
 
107
 
-
 
108
        if (useCache) {
-
 
109
            Tuple3<String, String, Date> key = Tuple3.create(from, to, date);
-
 
110
            if (useBiased && cacheBiased.containsKey(key)) {
-
 
111
                Tuple2<BigDecimal, BigDecimal> value = cacheBiased.get(key);
-
 
112
                r1 = value.get0();
-
 
113
                r2 = value.get1();
-
 
114
            } else if (!useBiased && cacheNotBiased.containsKey(key)) {
-
 
115
                Tuple2<BigDecimal, BigDecimal> value = cacheNotBiased.get(key);
-
 
116
                r1 = value.get0();
-
 
117
                r2 = value.get1();
-
 
118
            }
-
 
119
        }
-
 
120
 
-
 
121
        if (r1 == null || r2 == null) {
85
        // Clean date
122
            // Clean date
86
        final Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
123
            final Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
87
        c.setTimeInMillis(date.getTime());
124
            c.setTimeInMillis(date.getTime());
88
        c.set(Calendar.HOUR_OF_DAY, 0);
125
            c.set(Calendar.HOUR_OF_DAY, 0);
89
        c.set(Calendar.MINUTE, 0);
126
            c.set(Calendar.MINUTE, 0);
90
        c.set(Calendar.SECOND, 0);
127
            c.set(Calendar.SECOND, 0);
91
        c.set(Calendar.MILLISECOND, 0);
128
            c.set(Calendar.MILLISECOND, 0);
92
        final Date d = c.getTime();
129
            final Date d = c.getTime();
93
 
130
 
94
        // Get conversion info
131
            // Get conversion info
95
        final List<SQLRow> rowsFrom = getRates(from, d);
132
            final List<SQLRow> rowsFrom = getRates(from, d);
96
        final List<SQLRow> rowsTo = getRates(to, d);
133
            final List<SQLRow> rowsTo = getRates(to, d);
97
        BigDecimal r1 = null;
-
 
98
        BigDecimal r2 = null;
-
 
99
 
-
 
100
        // Récupération des taux par défaut dans DEVISE si aucun taux dans l'historique
-
 
101
        List<SQLRow> rowsDevise = new ArrayList<SQLRow>();
-
 
102
        if (rowsTo.isEmpty() || rowsFrom.isEmpty()) {
-
 
103
            SQLSelect sel = new SQLSelect();
-
 
104
            sel.addSelectStar(root.findTable("DEVISE"));
-
 
105
            rowsDevise.addAll(SQLRowListRSH.execute(sel));
-
 
106
        }
-
 
107
 
-
 
108
        if (rowsTo.isEmpty()) {
-
 
109
            for (SQLRow sqlRow : rowsDevise) {
-
 
110
                if (sqlRow.getString("CODE").equalsIgnoreCase(to)) {
-
 
111
                    r2 = (useBiased ? sqlRow.getBigDecimal("TAUX_COMMERCIAL") : sqlRow.getBigDecimal("TAUX"));
-
 
112
                }
-
 
113
            }
-
 
114
        }
-
 
115
        if (rowsFrom.isEmpty()) {
-
 
116
            for (SQLRow sqlRow : rowsDevise) {
-
 
117
                if (sqlRow.getString("CODE").equalsIgnoreCase(from)) {
-
 
118
                    r1 = (useBiased ? sqlRow.getBigDecimal("TAUX_COMMERCIAL") : sqlRow.getBigDecimal("TAUX"));
-
 
119
                }
-
 
120
            }
-
 
121
        }
-
 
122
 
134
 
123
        List<SQLRow> rows = new ArrayList<SQLRow>();
135
            List<SQLRow> rows = new ArrayList<SQLRow>();
124
        rows.addAll(rowsTo);
136
            rows.addAll(rowsTo);
125
        rows.addAll(rowsFrom);
137
            rows.addAll(rowsFrom);
-
 
138
            // Pour le taux réel, on récupére celui de la veille
126
        for (SQLRow sqlRow : rows) {
139
            for (SQLRow sqlRow : rows) {
127
            if (sqlRow.getString("DST").equals(from)) {
140
                if (sqlRow.getString("DST").equals(from)) {
128
                if (useBiased) {
141
                    if (useBiased) {
-
 
142
                        if (r1 == null) {
129
                    r1 = sqlRow.getBigDecimal("TAUX_COMMERCIAL");
143
                            r1 = sqlRow.getBigDecimal("TAUX_COMMERCIAL");
-
 
144
                        }
130
                } else {
145
                    } else {
131
                    r1 = sqlRow.getBigDecimal("TAUX");
146
                        r1 = sqlRow.getBigDecimal("TAUX");
132
                }
147
                    }
133
            }
148
                }
134
            if (sqlRow.getString("DST").equals(to)) {
149
                if (sqlRow.getString("DST").equals(to)) {
135
                if (useBiased) {
150
                    if (useBiased) {
-
 
151
                        if (r2 == null) {
136
                    r2 = sqlRow.getBigDecimal("TAUX_COMMERCIAL");
152
                            r2 = sqlRow.getBigDecimal("TAUX_COMMERCIAL");
-
 
153
                        }
137
                } else {
154
                    } else {
138
                    r2 = sqlRow.getBigDecimal("TAUX");
155
                        r2 = sqlRow.getBigDecimal("TAUX");
139
                }
156
                    }
140
            }
157
                }
141
        }
158
            }
142
        if (from.equals(this.baseCurrencyCode)) {
159
            if (from.equals(this.baseCurrencyCode)) {
143
            r1 = BigDecimal.ONE;
160
                r1 = BigDecimal.ONE;
144
        }
161
            }
145
        if (to.equals(this.baseCurrencyCode)) {
162
            if (to.equals(this.baseCurrencyCode)) {
146
            r2 = BigDecimal.ONE;
163
                r2 = BigDecimal.ONE;
147
        }
164
            }
-
 
165
 
-
 
166
            if (r1 == null || r2 == null) {
-
 
167
                // Récupération des taux par défaut dans DEVISE si aucun taux dans l'historique
-
 
168
                List<SQLRow> rowsDevise = new ArrayList<SQLRow>();
-
 
169
                if (rowsTo.isEmpty() || rowsFrom.isEmpty()) {
-
 
170
                    SQLSelect sel = new SQLSelect();
-
 
171
                    sel.addSelectStar(root.findTable("DEVISE"));
-
 
172
                    rowsDevise.addAll(SQLRowListRSH.execute(sel));
-
 
173
                }
-
 
174
                if (r2 == null) {
-
 
175
                    for (SQLRow sqlRow : rowsDevise) {
-
 
176
                        if (sqlRow.getString("CODE").equalsIgnoreCase(to)) {
-
 
177
                            r2 = (useBiased ? sqlRow.getBigDecimal("TAUX_COMMERCIAL") : sqlRow.getBigDecimal("TAUX"));
-
 
178
                        }
-
 
179
                    }
-
 
180
                }
-
 
181
                if (r1 == null) {
-
 
182
                    for (SQLRow sqlRow : rowsDevise) {
-
 
183
                        if (sqlRow.getString("CODE").equalsIgnoreCase(from)) {
-
 
184
                            r1 = (useBiased ? sqlRow.getBigDecimal("TAUX_COMMERCIAL") : sqlRow.getBigDecimal("TAUX"));
-
 
185
                        }
-
 
186
                    }
-
 
187
                }
-
 
188
            }
-
 
189
 
-
 
190
        }
148
        if (r1 == null) {
191
        if (r1 == null) {
149
            throw new IllegalStateException("No conversion rate for " + from);
192
            throw new IllegalStateException("No conversion rate for " + from);
150
        }
193
        }
151
        if (r2 == null) {
194
        if (r2 == null) {
152
            throw new IllegalStateException("No conversion rate for " + to);
195
            throw new IllegalStateException("No conversion rate for " + to);
153
        }
196
        }
-
 
197
        if (useCache) {
-
 
198
            Tuple3<String, String, Date> key = Tuple3.create(from, to, date);
-
 
199
 
-
 
200
            if (useBiased) {
-
 
201
                cacheBiased.put(key, Tuple2.create(r1, r2));
-
 
202
            } else {
-
 
203
                cacheNotBiased.put(key, Tuple2.create(r1, r2));
-
 
204
            }
-
 
205
        }
154
        final BigDecimal result = amount.multiply(r2, DecimalUtils.HIGH_PRECISION).divide(r1, DecimalUtils.HIGH_PRECISION);
206
        final BigDecimal result = amount.multiply(r2, DecimalUtils.HIGH_PRECISION).divide(r1, DecimalUtils.HIGH_PRECISION);
155
        return result;
207
        return result;
156
    }
208
    }
157
 
209
 
158
    public List<SQLRow> getRates(String currencyCode, final Date d) {
210
    public List<SQLRow> getRates(String currencyCode, final Date d) {
159
        final SQLSelect select = new SQLSelect();
211
        final SQLSelect select = new SQLSelect();
160
        final SQLTable t = this.root.getTable("DEVISE_HISTORIQUE");
212
        final SQLTable t = this.root.getTable("DEVISE_HISTORIQUE");
161
        select.addAllSelect(t, Arrays.asList("ID", "DATE", "SRC", "DST", "TAUX", "TAUX_COMMERCIAL"));
213
        select.addAllSelect(t, Arrays.asList("ID", "DATE", "SRC", "DST", "TAUX", "TAUX_COMMERCIAL"));
162
        Where w = new Where(t.getField("SRC"), "=", baseCurrencyCode);
214
        Where w = new Where(t.getField("SRC"), "=", baseCurrencyCode);
163
        w = w.and(new Where(t.getField("DST"), "=", currencyCode));
215
        w = w.and(new Where(t.getField("DST"), "=", currencyCode));
164
        w = w.and(new Where(t.getField("DATE"), "<=", d));
216
        w = w.and(new Where(t.getField("DATE"), "<=", d));
165
        select.setWhere(w);
217
        select.setWhere(w);
166
        select.addFieldOrder(t.getField("DATE"), Order.desc());
218
        select.addFieldOrder(t.getField("DATE"), Order.desc());
-
 
219
        // Limit pour récupérer le taux de la veille
167
        select.setLimit(2);
220
        select.setLimit(2);
168
        final List<SQLRow> rows = SQLRowListRSH.execute(select);
221
        final List<SQLRow> rows = SQLRowListRSH.execute(select);
169
        return rows;
222
        return rows;
170
    }
223
    }
171
}
224
}