1 /********************************************************************\
2 * split-register-copy-ops.c -- copy/paste semantics for *
3 * transactions and splits *
4 * Port to C of engine-interface *
5 * originally written by Dave Peticolas <dave@krondo.com> *
6 * © 2019 Geert Janssens
7 * *
8 * This program is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU General Public License as *
10 * published by the Free Software Foundation; either version 2 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License*
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21 \********************************************************************/
22
23 #include <glib.h>
24
25 #include "config.h"
26 #include "split-register-copy-ops.h"
27
28 /* accessors */
gnc_float_split_get_split(const FloatingSplit * fs)29 Split *gnc_float_split_get_split (const FloatingSplit *fs)
30 {
31 g_return_val_if_fail (fs, NULL);
32 return fs->m_split;
33 }
34
gnc_float_split_get_account(const FloatingSplit * fs)35 Account *gnc_float_split_get_account (const FloatingSplit *fs) /* direct account pointer rather than account guid */
36 {
37 g_return_val_if_fail (fs, NULL);
38 return fs->m_account;
39 }
40
gnc_float_split_get_transaction(const FloatingSplit * fs)41 Transaction *gnc_float_split_get_transaction (const FloatingSplit *fs) /* direct transaction pointer rather than transaction guid */
42 {
43 g_return_val_if_fail (fs, NULL);
44 return fs->m_transaction;
45 }
46
gnc_float_split_get_memo(const FloatingSplit * fs)47 const char *gnc_float_split_get_memo (const FloatingSplit *fs)
48 {
49 g_return_val_if_fail (fs, NULL);
50 return fs->m_memo;
51 }
52
gnc_float_split_get_action(const FloatingSplit * fs)53 const char *gnc_float_split_get_action (const FloatingSplit *fs)
54 {
55 g_return_val_if_fail (fs, NULL);
56 return fs->m_action;
57 }
58
gnc_float_split_get_reconcile_state(const FloatingSplit * fs)59 char gnc_float_split_get_reconcile_state (const FloatingSplit *fs)
60 {
61 g_return_val_if_fail (fs, '\0');
62 return fs->m_reconcile_state;
63 }
64
gnc_float_split_get_reconcile_date(const FloatingSplit * fs)65 time64 gnc_float_split_get_reconcile_date (const FloatingSplit *fs)
66 {
67 g_return_val_if_fail (fs, G_MAXINT64);
68 return fs->m_reconcile_date;
69 }
70
gnc_float_split_get_amount(const FloatingSplit * fs)71 gnc_numeric gnc_float_split_get_amount (const FloatingSplit *fs)
72 {
73 g_return_val_if_fail (fs, gnc_numeric_zero());
74 return fs->m_amount;
75 }
76
gnc_float_split_get_value(const FloatingSplit * fs)77 gnc_numeric gnc_float_split_get_value (const FloatingSplit *fs)
78 {
79 g_return_val_if_fail (fs, gnc_numeric_zero());
80 return fs->m_value;
81 }
82
83
84 /* modifiers */
gnc_float_split_set_split(FloatingSplit * fs,Split * split)85 void gnc_float_split_set_split(FloatingSplit *fs, Split *split)
86 {
87 g_return_if_fail (fs);
88 fs->m_split = split;
89 };
90
gnc_float_split_set_account(FloatingSplit * fs,Account * account)91 void gnc_float_split_set_account (FloatingSplit *fs, Account *account) /* direct account pointer rather than account guid */
92 {
93 g_return_if_fail (fs);
94 fs->m_account = account;
95 };
96
gnc_float_split_set_transaction(FloatingSplit * fs,Transaction * transaction)97 void gnc_float_split_set_transaction (FloatingSplit *fs, Transaction *transaction) /* direct transaction pointer rather than transaction guid */
98 {
99 g_return_if_fail (fs);
100 fs->m_transaction = transaction;
101 };
102
gnc_float_split_set_memo(FloatingSplit * fs,const char * memo)103 void gnc_float_split_set_memo (FloatingSplit *fs, const char *memo)
104 {
105 g_return_if_fail (fs);
106 CACHE_REPLACE (fs->m_memo, memo);
107 };
108
gnc_float_split_set_action(FloatingSplit * fs,const char * action)109 void gnc_float_split_set_action (FloatingSplit *fs, const char *action)
110 {
111 g_return_if_fail (fs);
112 CACHE_REPLACE (fs->m_action, action);
113 };
114
gnc_float_split_set_reconcile_state(FloatingSplit * fs,char reconcile_state)115 void gnc_float_split_set_reconcile_state (FloatingSplit *fs, char reconcile_state)
116 {
117 g_return_if_fail (fs);
118 fs->m_reconcile_state = reconcile_state;
119 };
120
gnc_float_split_set_reconcile_date(FloatingSplit * fs,time64 reconcile_date)121 void gnc_float_split_set_reconcile_date (FloatingSplit *fs, time64 reconcile_date)
122 {
123 g_return_if_fail (fs);
124 fs->m_reconcile_date = reconcile_date;
125 };
126
gnc_float_split_set_amount(FloatingSplit * fs,const gnc_numeric amount)127 void gnc_float_split_set_amount (FloatingSplit *fs, const gnc_numeric amount)
128 {
129 g_return_if_fail (fs);
130
131 fs->m_amount = amount;
132 };
133
gnc_float_split_set_value(FloatingSplit * fs,const gnc_numeric value)134 void gnc_float_split_set_value (FloatingSplit *fs, const gnc_numeric value)
135 {
136 g_return_if_fail (fs);
137
138 fs->m_value = value;
139 };
140
141 /* This function takes a split and returns a representation
142 of it as a floating_split structure. Assumes the transaction is open
143 for editing.
144 */
gnc_split_to_float_split(Split * split)145 FloatingSplit *gnc_split_to_float_split (Split *split)
146 {
147 FloatingSplit *fs;
148
149 g_return_val_if_fail (split, NULL);
150
151 fs = g_new0 (FloatingSplit, 1);
152 fs->m_split = split;
153 fs->m_account = xaccSplitGetAccount (split);
154 fs->m_transaction = xaccSplitGetParent (split);
155 fs->m_memo = CACHE_INSERT (xaccSplitGetMemo (split));
156 fs->m_action = CACHE_INSERT (xaccSplitGetAction (split));
157 fs->m_reconcile_state = xaccSplitGetReconcile (split);
158 fs->m_reconcile_date = xaccSplitGetDateReconciled (split);
159 fs->m_amount = xaccSplitGetAmount (split);
160 fs->m_value = xaccSplitGetValue (split);
161
162 return fs;
163 }
164
165 /* Copy a temporary split representation onto a real split.
166 If possible, insert the split into the account of the
167 split representation. Not all values are copied. The reconcile
168 status and date are not copied. The split's guid is,
169 of course, unchanged.
170 */
gnc_float_split_to_split(const FloatingSplit * fs,Split * split)171 void gnc_float_split_to_split (const FloatingSplit *fs, Split *split)
172 {
173 g_return_if_fail(split);
174
175 if (fs->m_memo)
176 xaccSplitSetMemo (split, fs->m_memo);
177 if (fs->m_action)
178 xaccSplitSetAction (split, fs->m_action);
179 xaccSplitSetAmount (split, fs->m_amount);
180 xaccSplitSetValue (split, fs->m_value);
181 if (fs->m_account)
182 {
183 xaccAccountBeginEdit (fs->m_account);
184 xaccSplitSetAccount (split, fs->m_account);
185 xaccAccountCommitEdit (fs->m_account);
186 }
187 }
188
gnc_float_split_free(FloatingSplit * fs)189 void gnc_float_split_free (FloatingSplit *fs)
190 {
191 g_return_if_fail (fs);
192
193 CACHE_REMOVE (fs->m_memo);
194 CACHE_REMOVE (fs->m_action);
195 g_free (fs);
196 }
197
198 /* accessors */
gnc_float_txn_get_txn(const FloatingTxn * ft)199 Transaction *gnc_float_txn_get_txn (const FloatingTxn *ft)
200 {
201 g_return_val_if_fail (ft, NULL);
202 return ft->m_txn;
203 }
204
gnc_float_txn_get_currency(const FloatingTxn * ft)205 gnc_commodity *gnc_float_txn_get_currency (const FloatingTxn *ft)
206 {
207 g_return_val_if_fail (ft, NULL);
208 return ft->m_currency;
209 }
210
gnc_float_txn_get_date_entered(const FloatingTxn * ft)211 time64 gnc_float_txn_get_date_entered (const FloatingTxn *ft)
212 {
213 g_return_val_if_fail (ft, G_MAXINT64);
214 return ft->m_date_entered;
215 }
216
gnc_float_txn_get_date_posted(const FloatingTxn * ft)217 time64 gnc_float_txn_get_date_posted (const FloatingTxn *ft)
218 {
219 g_return_val_if_fail (ft, G_MAXINT64);
220 return ft->m_date_posted;
221 }
222
gnc_float_txn_get_num(const FloatingTxn * ft)223 const char *gnc_float_txn_get_num (const FloatingTxn *ft)
224 {
225 g_return_val_if_fail (ft, NULL);
226 return ft->m_num;
227 }
228
gnc_float_txn_get_description(const FloatingTxn * ft)229 const char *gnc_float_txn_get_description (const FloatingTxn *ft)
230 {
231 g_return_val_if_fail (ft, NULL);
232 return ft->m_description;
233 }
234
gnc_float_txn_get_notes(const FloatingTxn * ft)235 const char *gnc_float_txn_get_notes (const FloatingTxn *ft)
236 {
237 g_return_val_if_fail (ft, NULL);
238 return ft->m_notes;
239 }
240
gnc_float_txn_get_doclink(const FloatingTxn * ft)241 const char *gnc_float_txn_get_doclink (const FloatingTxn *ft)
242 {
243 g_return_val_if_fail (ft, NULL);
244 return ft->m_doclink;
245 }
246
gnc_float_txn_get_splits(const FloatingTxn * ft)247 SplitList *gnc_float_txn_get_splits (const FloatingTxn *ft)
248 {
249 g_return_val_if_fail (ft, NULL);
250 return ft->m_splits;
251 }
252
gnc_float_txn_get_float_split(const FloatingTxn * ft,guint index)253 FloatingSplit *gnc_float_txn_get_float_split (const FloatingTxn *ft, guint index)
254 {
255 FloatingSplit *fs = NULL;
256 guint size = 0;
257
258 g_return_val_if_fail (ft, NULL);
259 g_return_val_if_fail (ft->m_splits, NULL);
260 g_return_val_if_fail (index < g_list_length (ft->m_splits) , NULL);
261 return g_list_nth_data (ft->m_splits, index);
262 }
263
gnc_float_txn_get_other_float_split(const FloatingTxn * ft,FloatingSplit * fs)264 FloatingSplit *gnc_float_txn_get_other_float_split (const FloatingTxn *ft, FloatingSplit *fs)
265 {
266 guint size = 0, other = 0;
267
268 g_return_val_if_fail (ft, NULL);
269 g_return_val_if_fail (ft->m_splits, NULL);
270 g_return_val_if_fail (g_list_length (ft->m_splits) == 2 , NULL);
271
272 if (g_list_nth_data (ft->m_splits, 0) == fs)
273 other = 1;
274
275 return g_list_nth_data (ft->m_splits, other);
276 }
277
278 /* modifiers */
gnc_float_txn_set_txn(FloatingTxn * ft,Transaction * txn)279 void gnc_float_txn_set_txn (FloatingTxn *ft, Transaction *txn)
280 {
281 g_return_if_fail (ft);
282 ft->m_txn = txn;
283 };
284
gnc_float_txn_set_currency(FloatingTxn * ft,gnc_commodity * currency)285 void gnc_float_txn_set_currency (FloatingTxn *ft, gnc_commodity *currency)
286 {
287 g_return_if_fail (ft);
288 ft->m_currency = currency;
289 };
290
gnc_float_txn_set_date_entered(FloatingTxn * ft,time64 date_entered)291 void gnc_float_txn_set_date_entered (FloatingTxn *ft, time64 date_entered)
292 {
293 g_return_if_fail (ft);
294 ft->m_date_entered = date_entered;
295 };
296
gnc_float_txn_set_date_posted(FloatingTxn * ft,time64 date_posted)297 void gnc_float_txn_set_date_posted (FloatingTxn *ft, time64 date_posted)
298 {
299 g_return_if_fail (ft);
300 ft->m_date_posted = date_posted;
301 };
302
gnc_float_txn_set_num(FloatingTxn * ft,const char * num)303 void gnc_float_txn_set_num (FloatingTxn *ft, const char *num)
304 {
305 g_return_if_fail (ft);
306 CACHE_REPLACE (ft->m_num, num);
307 };
308
gnc_float_txn_set_description(FloatingTxn * ft,const char * description)309 void gnc_float_txn_set_description (FloatingTxn *ft, const char *description)
310 {
311 g_return_if_fail (ft);
312 CACHE_REPLACE (ft->m_description, description);
313 };
314
gnc_float_txn_set_notes(FloatingTxn * ft,const char * notes)315 void gnc_float_txn_set_notes (FloatingTxn *ft, const char *notes)
316 {
317 g_return_if_fail (ft);
318 CACHE_REPLACE (ft->m_notes, notes);
319 };
320
gnc_float_txn_set_doclink(FloatingTxn * ft,const char * doclink)321 void gnc_float_txn_set_doclink (FloatingTxn *ft, const char *doclink)
322 {
323 g_return_if_fail (ft);
324 CACHE_REPLACE (ft->m_doclink, doclink);
325 };
326
gnc_float_txn_set_splits(FloatingTxn * ft,SplitList * splits)327 void gnc_float_txn_set_splits (FloatingTxn *ft, SplitList *splits)
328 {
329 g_return_if_fail (ft);
330 ft->m_splits = splits;
331 };
332
gnc_float_txn_append_float_split(FloatingTxn * ft,FloatingSplit * fs)333 void gnc_float_txn_append_float_split (FloatingTxn *ft, FloatingSplit *fs)
334 {
335 g_return_if_fail (ft);
336 g_return_if_fail (fs);
337 ft->m_splits = g_list_append (ft->m_splits, fs);
338 }
339
340 /* This function takes a C transaction and returns
341 a representation of it as a floating_txn. */
gnc_txn_to_float_txn(Transaction * txn,gboolean use_cut_semantics)342 FloatingTxn *gnc_txn_to_float_txn (Transaction *txn, gboolean use_cut_semantics)
343 {
344 GList *iter;
345
346 FloatingTxn *ft = g_new0 (FloatingTxn, 1);
347
348 ft->m_txn = txn;
349 ft->m_currency = xaccTransGetCurrency (txn);
350 ft->m_date_entered = xaccTransGetDateEntered (txn);
351 if (use_cut_semantics)
352 {
353 ft->m_date_posted = xaccTransGetDate (txn);
354 ft->m_num = CACHE_INSERT (xaccTransGetNum (txn));
355 }
356 ft->m_description = CACHE_INSERT (xaccTransGetDescription (txn));
357 ft->m_notes = CACHE_INSERT (xaccTransGetNotes (txn));
358 ft->m_doclink = CACHE_INSERT (xaccTransGetDocLink (txn));
359
360 for (iter = xaccTransGetSplitList (txn); iter ; iter = iter->next)
361 {
362 Split *split = iter->data;
363 if (split)
364 {
365 FloatingSplit *fs = gnc_split_to_float_split (split);
366 ft->m_splits = g_list_prepend (ft->m_splits, fs);
367 }
368 }
369 ft->m_splits = g_list_reverse (ft->m_splits);
370
371 return ft;
372 }
373
gnc_float_txn_to_txn(const FloatingTxn * ft,Transaction * txn,gboolean do_commit)374 void gnc_float_txn_to_txn (const FloatingTxn *ft, Transaction *txn, gboolean do_commit)
375 {
376 gnc_float_txn_to_txn_swap_accounts (ft, txn, NULL, NULL, do_commit);
377 }
378
379 /* Copy a temporary representation of a transaction onto a real transaction.
380 I f they exist the two account*s (acct1 and acct2) are used to swap accounts
381 when when creating splits. */
gnc_float_txn_to_txn_swap_accounts(const FloatingTxn * ft,Transaction * txn,Account * acct1,Account * acct2,gboolean do_commit)382 void gnc_float_txn_to_txn_swap_accounts (const FloatingTxn *ft, Transaction *txn, Account *acct1, Account *acct2, gboolean do_commit)
383 {
384 GList *iter;
385
386 g_return_if_fail (ft);
387 g_return_if_fail (txn);
388
389 if (!xaccTransIsOpen (txn))
390 xaccTransBeginEdit (txn);
391
392 if (ft->m_currency)
393 xaccTransSetCurrency (txn, ft->m_currency);
394 if (ft->m_description)
395 xaccTransSetDescription (txn, ft->m_description);
396 if (ft->m_num)
397 xaccTransSetNum (txn, ft->m_num);
398 if (ft->m_notes)
399 xaccTransSetNotes (txn, ft->m_notes);
400 if (ft->m_doclink)
401 xaccTransSetDocLink (txn, ft->m_doclink);
402 if (ft->m_date_posted)
403 xaccTransSetDatePostedSecs (txn, ft->m_date_posted);
404
405 /* strip off the old splits */
406 while (xaccTransCountSplits (txn))
407 xaccSplitDestroy (xaccTransGetSplit (txn, 0));
408
409 /* and put on the new ones! Please note they go in the *same*
410 order as in the original transaction. This is important. */
411 for (iter = ft->m_splits; iter; iter = iter->next)
412 {
413 Account *old_acc, *new_acc;
414 Split *split;
415 FloatingSplit *fs = iter->data;
416 if (!fs)
417 continue;
418
419 split = xaccMallocSplit (xaccTransGetBook (txn));
420
421 old_acc = fs->m_account;
422 if (fs->m_account == acct1)
423 new_acc = acct2;
424 else if (fs->m_account == acct2)
425 new_acc = acct1;
426 else
427 new_acc = fs->m_account;
428
429 fs->m_account = new_acc;
430 gnc_float_split_to_split (fs, split);
431 fs->m_account = old_acc;
432 xaccSplitSetParent (split, txn);
433 }
434
435 /* close the transaction */
436 if (do_commit)
437 xaccTransCommitEdit (txn);
438 }
439
gnc_float_txn_free(FloatingTxn * ft)440 void gnc_float_txn_free (FloatingTxn *ft)
441 {
442 g_return_if_fail (ft);
443
444 CACHE_REMOVE (ft->m_num);
445 CACHE_REMOVE (ft->m_description);
446 CACHE_REMOVE (ft->m_notes);
447 CACHE_REMOVE (ft->m_doclink);
448 g_list_free_full (ft->m_splits, (GDestroyNotify)gnc_float_split_free);
449 g_free (ft);
450 }
451