]> git.ktnx.net Git - mobile-ledger.git/blob - app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java
more pronounced day/month delimiters in the transaction list
[mobile-ledger.git] / app / src / main / java / net / ktnx / mobileledger / model / LedgerTransaction.java
1 /*
2  * Copyright © 2021 Damyan Ivanov.
3  * This file is part of MoLe.
4  * MoLe is free software: you can distribute it and/or modify it
5  * under the term of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your opinion), any later version.
8  *
9  * MoLe is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License terms for details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with MoLe. If not, see <https://www.gnu.org/licenses/>.
16  */
17
18 package net.ktnx.mobileledger.model;
19
20 import androidx.annotation.NonNull;
21 import androidx.annotation.Nullable;
22
23 import net.ktnx.mobileledger.db.Profile;
24 import net.ktnx.mobileledger.db.Transaction;
25 import net.ktnx.mobileledger.db.TransactionAccount;
26 import net.ktnx.mobileledger.db.TransactionWithAccounts;
27 import net.ktnx.mobileledger.utils.Digest;
28 import net.ktnx.mobileledger.utils.Globals;
29 import net.ktnx.mobileledger.utils.SimpleDate;
30
31 import java.nio.charset.StandardCharsets;
32 import java.security.NoSuchAlgorithmException;
33 import java.text.ParseException;
34 import java.util.ArrayList;
35 import java.util.Comparator;
36 import java.util.List;
37
38 public class LedgerTransaction {
39     private static final String DIGEST_TYPE = "SHA-256";
40     public final Comparator<LedgerTransactionAccount> comparator = (o1, o2) -> {
41         int res = o1.getAccountName()
42                     .compareTo(o2.getAccountName());
43         if (res != 0)
44             return res;
45         res = o1.getCurrency()
46                 .compareTo(o2.getCurrency());
47         if (res != 0)
48             return res;
49         res = o1.getComment()
50                 .compareTo(o2.getComment());
51         if (res != 0)
52             return res;
53         return Float.compare(o1.getAmount(), o2.getAmount());
54     };
55     private final long profile;
56     private final long ledgerId;
57     private final List<LedgerTransactionAccount> accounts;
58     private long dbId;
59     private SimpleDate date;
60     private String description;
61     private String comment;
62     private String dataHash;
63     private boolean dataLoaded;
64     public LedgerTransaction(long ledgerId, String dateString, String description)
65             throws ParseException {
66         this(ledgerId, Globals.parseLedgerDate(dateString), description);
67     }
68     public LedgerTransaction(TransactionWithAccounts dbo) {
69         this(dbo.transaction.getLedgerId(), dbo.transaction.getProfileId());
70         dbId = dbo.transaction.getId();
71         date = new SimpleDate(dbo.transaction.getYear(), dbo.transaction.getMonth(),
72                 dbo.transaction.getDay());
73         description = dbo.transaction.getDescription();
74         comment = dbo.transaction.getComment();
75         dataHash = dbo.transaction.getDataHash();
76         if (dbo.accounts != null)
77             for (TransactionAccount acc : dbo.accounts) {
78                 accounts.add(new LedgerTransactionAccount(acc));
79             }
80         dataLoaded = true;
81     }
82     public TransactionWithAccounts toDBO() {
83         TransactionWithAccounts o = new TransactionWithAccounts();
84         o.transaction = new Transaction();
85         o.transaction.setId(dbId);
86         o.transaction.setProfileId(profile);
87         o.transaction.setLedgerId(ledgerId);
88         o.transaction.setYear(date.year);
89         o.transaction.setMonth(date.month);
90         o.transaction.setDay(date.day);
91         o.transaction.setDescription(description);
92         o.transaction.setComment(comment);
93         fillDataHash();
94         o.transaction.setDataHash(dataHash);
95
96         o.accounts = new ArrayList<>();
97         int orderNo = 1;
98         for (LedgerTransactionAccount acc : accounts) {
99             TransactionAccount a = acc.toDBO();
100             a.setOrderNo(orderNo++);
101             a.setTransactionId(dbId);
102             o.accounts.add(a);
103         }
104         return o;
105     }
106     public LedgerTransaction(long ledgerId, SimpleDate date, String description, Profile profile) {
107         this.profile = profile.getId();
108         this.ledgerId = ledgerId;
109         this.date = date;
110         this.description = description;
111         this.accounts = new ArrayList<>();
112         this.dataHash = null;
113         dataLoaded = false;
114     }
115     public LedgerTransaction(long ledgerId, SimpleDate date, String description) {
116         this(ledgerId, date, description, Data.getProfile());
117     }
118     public LedgerTransaction(SimpleDate date, String description) {
119         this(0, date, description);
120     }
121     public LedgerTransaction(int ledgerId) {
122         this(ledgerId, (SimpleDate) null, null);
123     }
124     public LedgerTransaction(long ledgerId, long profileId) {
125         this.profile = profileId;
126         this.ledgerId = ledgerId;
127         this.date = null;
128         this.description = null;
129         this.accounts = new ArrayList<>();
130         this.dataHash = null;
131         this.dataLoaded = false;
132     }
133     public List<LedgerTransactionAccount> getAccounts() {
134         return accounts;
135     }
136     public void addAccount(LedgerTransactionAccount item) {
137         accounts.add(item);
138         dataHash = null;
139     }
140     @Nullable
141     public SimpleDate getDateIfAny() {
142         return date;
143     }
144     @NonNull
145     public SimpleDate getDate() {
146         if (date == null)
147             throw new IllegalStateException("Transaction has no date");
148         return date;
149     }
150     public void setDate(SimpleDate date) {
151         this.date = date;
152         dataHash = null;
153     }
154     public String getDescription() {
155         return description;
156     }
157     public void setDescription(String description) {
158         this.description = description;
159         dataHash = null;
160     }
161     public String getComment() {
162         return comment;
163     }
164     public void setComment(String comment) {
165         this.comment = comment;
166     }
167     public long getLedgerId() {
168         return ledgerId;
169     }
170     protected void fillDataHash() {
171         if (dataHash != null)
172             return;
173         try {
174             Digest sha = new Digest(DIGEST_TYPE);
175             StringBuilder data = new StringBuilder();
176             data.append("ver1");
177             data.append(profile);
178             data.append(getLedgerId());
179             data.append('\0');
180             data.append(getDescription());
181             data.append('\0');
182             data.append(getComment());
183             data.append('\0');
184             data.append(Globals.formatLedgerDate(getDate()));
185             data.append('\0');
186             for (LedgerTransactionAccount item : accounts) {
187                 data.append(item.getAccountName());
188                 data.append('\0');
189                 data.append(item.getCurrency());
190                 data.append('\0');
191                 data.append(item.getAmount());
192                 data.append('\0');
193                 data.append(item.getComment());
194             }
195             sha.update(data.toString()
196                            .getBytes(StandardCharsets.UTF_8));
197             dataHash = sha.digestToHexString();
198         }
199         catch (NoSuchAlgorithmException e) {
200             throw new RuntimeException(
201                     String.format("Unable to get instance of %s digest", DIGEST_TYPE), e);
202         }
203     }
204     public String getDataHash() {
205         fillDataHash();
206         return dataHash;
207     }
208     public void finishLoading() {
209         dataLoaded = true;
210     }
211     @Override
212     public boolean equals(@Nullable Object obj) {
213         if (obj == null)
214             return false;
215         if (!obj.getClass()
216                 .equals(this.getClass()))
217             return false;
218
219         return ((LedgerTransaction) obj).getDataHash()
220                                         .equals(getDataHash());
221     }
222
223     public boolean hasAccountNamedLike(String name) {
224         name = name.toUpperCase();
225         for (LedgerTransactionAccount acc : accounts) {
226             if (acc.getAccountName()
227                    .toUpperCase()
228                    .contains(name))
229                 return true;
230         }
231
232         return false;
233     }
234     public void markDataAsLoaded() {
235         dataLoaded = true;
236     }
237 }