GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-log-replay.cpp
1/********************************************************************\
2 * This program is free software; you can redistribute it and/or *
3 * modify it under the terms of the GNU General Public License as *
4 * published by the Free Software Foundation; either version 2 of *
5 * the License, or (at your option) any later version. *
6 * *
7 * This program is distributed in the hope that it will be useful, *
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
10 * GNU General Public License for more details. *
11 * *
12 * You should have received a copy of the GNU General Public License*
13 * along with this program; if not, contact: *
14 * *
15 * Free Software Foundation Voice: +1-617-542-5942 *
16 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
17 * Boston, MA 02110-1301, USA gnu@gnu.org *
18\********************************************************************/
26#include <config.h>
27
28#include <gtk/gtk.h>
29#include <glib/gi18n.h>
30#include <glib/gstdio.h>
31#include <string.h>
32#include <sys/time.h>
33#include <errno.h>
34
35#include "Account.h"
36#include "Transaction.h"
37#include "TransactionP.hpp"
38#include "TransLog.h"
39#include "Scrub.h"
40#include "gnc-log-replay.h"
41#include "gnc-file.h"
42#include "qof.h"
43#include "qofinstance-p.h"
44#include "gnc-ui-util.h"
45#include "gnc-gui-query.h"
46
47#define GNC_PREFS_GROUP "dialogs.log-replay"
48
49/* NW: If you want a new log_module, just define
50a unique string either in gnc-engine.h or
51locally.*/
52static QofLogModule log_module = GNC_MOD_IMPORT;
53
54/* fprintf (trans_log, "mod guid time_now " \
55 "date_entered date_posted " \
56 "acc_guid acc_name num description " \
57 "memo action reconciled " \
58 "amount value date_reconciled\n");
59 "%c\t%s/%s\t%s\t%s\t%s\t%s\t%s\t%s\t"
60 "%s\t%s\t%s\t%c\t%lld/%lld\t%lld/%lld\t%s\n",
61*/
62#define STRING_FIELD_SIZE 256
63typedef struct _split_record
64{
65 enum _enum_action {LOG_BEGIN_EDIT, LOG_ROLLBACK, LOG_COMMIT, LOG_DELETE} log_action;
66 int log_action_present;
67 GncGUID trans_guid;
68 int trans_guid_present;
69 GncGUID split_guid;
70 int split_guid_present;
71 time64 log_date;
72 int log_date_present;
73 time64 date_entered;
74 int date_entered_present;
75 time64 date_posted;
76 int date_posted_present;
77 GncGUID acc_guid;
78 int acc_guid_present;
79 char acc_name[STRING_FIELD_SIZE];
80 int acc_name_present;
81 char trans_num[STRING_FIELD_SIZE];
82 int trans_num_present;
83 char trans_descr[STRING_FIELD_SIZE];
84 int trans_descr_present;
85 char trans_notes[STRING_FIELD_SIZE];
86 int trans_notes_present;
87 char split_memo[STRING_FIELD_SIZE];
88 int split_memo_present;
89 char split_action[STRING_FIELD_SIZE];
90 int split_action_present;
91 char split_reconcile;
92 int split_reconcile_present;
93 gnc_numeric amount;
94 int amount_present;
95 gnc_numeric value;
96 int value_present;
97 time64 date_reconciled;
98 int date_reconciled_present;
100/********************************************************************\
101 * gnc_file_log_replay_import
102 * Entry point
103\********************************************************************/
104
105static char *olds;
106/* This version of strtok will only match SINGLE occurrence of delim,
107 returning a 0 length valid string between two consecutive ocurence of delim.
108 It will also return a 0 length string instead of NULL when it reaches the end of s
109*/
110static char * my_strtok (char *s, const char *delim)
111{
112 char *token;
113 /*DEBUG("strtok(): Start...");*/
114 if (s == NULL)
115 s = olds;
116
117 /* Scan leading delimiters. */
118 /*s += strspn (s, delim);*/ /*Don't do it, or we will loose count.*/
119 if (*s == '\0')
120 {
121 olds = s;
122 return s;
123 }
124
125 /* Find the end of the token. */
126 token = s;
127 s = strpbrk (token, delim);
128 if (s == NULL)
129 {
130 /* This token finishes the string. */
131 olds = strchr (token, '\0');
132 }
133 else
134 {
135 /* Terminate the token and make OLDS point past it. */
136 *s = '\0';
137 olds = s + 1;
138 }
139 return token;
140}
141
142static split_record interpret_split_record( char *record_line)
143{
144 char * tok_ptr;
145 split_record record;
146 memset(&record, 0, sizeof(record));
147 DEBUG("interpret_split_record(): Start...");
148 if (strlen(tok_ptr = my_strtok(record_line, "\t")) != 0)
149 {
150 switch (tok_ptr[0])
151 {
152 case 'B':
153 record.log_action = split_record::_enum_action::LOG_BEGIN_EDIT;
154 break;
155 case 'D':
156 record.log_action = split_record::_enum_action::LOG_DELETE;
157 break;
158 case 'C':
159 record.log_action = split_record::_enum_action::LOG_COMMIT;
160 break;
161 case 'R':
162 record.log_action = split_record::_enum_action::LOG_ROLLBACK;
163 break;
164 }
165 record.log_action_present = TRUE;
166 }
167 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
168 {
169 string_to_guid(tok_ptr, &(record.trans_guid));
170 record.trans_guid_present = TRUE;
171 }
172 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
173 {
174 string_to_guid(tok_ptr, &(record.split_guid));
175 record.split_guid_present = TRUE;
176 }
177 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
178 {
179 record.log_date = gnc_iso8601_to_time64_gmt(tok_ptr);
180 record.log_date_present = TRUE;
181 }
182 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
183 {
184 record.date_entered = gnc_iso8601_to_time64_gmt(tok_ptr);
185 record.date_entered_present = TRUE;
186 }
187 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
188 {
189 record.date_posted = gnc_iso8601_to_time64_gmt(tok_ptr);
190 record.date_posted_present = TRUE;
191 }
192 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
193 {
194 string_to_guid(tok_ptr, &(record.acc_guid));
195 record.acc_guid_present = TRUE;
196 }
197 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
198 {
199 strncpy(record.acc_name, tok_ptr, STRING_FIELD_SIZE - 1);
200 record.acc_name_present = TRUE;
201 }
202 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
203 {
204 strncpy(record.trans_num, tok_ptr, STRING_FIELD_SIZE - 1);
205 record.trans_num_present = TRUE;
206 }
207 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
208 {
209 strncpy(record.trans_descr, tok_ptr, STRING_FIELD_SIZE - 1);
210 record.trans_descr_present = TRUE;
211 }
212 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
213 {
214 strncpy(record.trans_notes, tok_ptr, STRING_FIELD_SIZE - 1);
215 record.trans_notes_present = TRUE;
216 }
217 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
218 {
219 strncpy(record.split_memo, tok_ptr, STRING_FIELD_SIZE - 1);
220 record.split_memo_present = TRUE;
221 }
222 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
223 {
224 strncpy(record.split_action, tok_ptr, STRING_FIELD_SIZE - 1);
225 record.split_action_present = TRUE;
226 }
227 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
228 {
229 record.split_reconcile = tok_ptr[0];
230 record.split_reconcile_present = TRUE;
231 }
232 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
233 {
234 record.amount = gnc_numeric_from_string (tok_ptr);
235 record.amount_present = TRUE;
236 }
237 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
238 {
239 record.value = gnc_numeric_from_string (tok_ptr);
240 record.value_present = TRUE;
241 }
242 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
243 {
244 record.date_reconciled = gnc_iso8601_to_time64_gmt(tok_ptr);
245 record.date_reconciled_present = TRUE;
246 }
247
248 if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
249 {
250 PERR("interpret_split_record(): Expected number of fields exceeded!");
251 }
252 DEBUG("interpret_split_record(): End");
253 return record;
254}
255
256static void dump_split_record(split_record record)
257{
258 char * string_ptr = NULL;
259 char string_buf[256];
260
261 DEBUG("dump_split_record(): Start...");
262 if (record.log_action_present)
263 {
264 switch (record.log_action)
265 {
266 case split_record::_enum_action::LOG_BEGIN_EDIT:
267 DEBUG("Log action: LOG_BEGIN_EDIT");
268 break;
269 case split_record::_enum_action::LOG_DELETE:
270 DEBUG("Log action: LOG_DELETE");
271 break;
272 case split_record::_enum_action::LOG_COMMIT:
273 DEBUG("Log action: LOG_COMMIT");
274 break;
275 case split_record::_enum_action::LOG_ROLLBACK:
276 DEBUG("Log action: LOG_ROLLBACK");
277 break;
278 }
279 }
280 if (record.trans_guid_present)
281 {
282 guid_to_string_buff(&record.trans_guid, string_buf);
283 DEBUG("Transaction GncGUID: %s", string_buf);
284 }
285 if (record.split_guid_present)
286 {
287 guid_to_string_buff(&record.split_guid, string_buf);
288 DEBUG("Split GncGUID: %s", string_buf);
289 }
290 if (record.log_date_present)
291 {
292 gnc_time64_to_iso8601_buff (record.log_date, string_buf);
293 DEBUG("Log entry date: %s", string_buf);
294 }
295 if (record.date_entered_present)
296 {
297 gnc_time64_to_iso8601_buff (record.date_entered, string_buf);
298 DEBUG("Date entered: %s", string_buf);
299 }
300 if (record.date_posted_present)
301 {
302 gnc_time64_to_iso8601_buff (record.date_posted, string_buf);
303 DEBUG("Date posted: %s", string_buf);
304 }
305 if (record.acc_guid_present)
306 {
307 guid_to_string_buff(&record.acc_guid, string_buf);
308 DEBUG("Account GncGUID: %s", string_buf);
309 }
310 if (record.acc_name_present)
311 {
312 DEBUG("Account name: %s", record.acc_name);
313 }
314 if (record.trans_num_present)
315 {
316 DEBUG("Transaction number: %s", record.trans_num);
317 }
318 if (record.trans_descr_present)
319 {
320 DEBUG("Transaction description: %s", record.trans_descr);
321 }
322 if (record.trans_notes_present)
323 {
324 DEBUG("Transaction notes: %s", record.trans_notes);
325 }
326 if (record.split_memo_present)
327 {
328 DEBUG("Split memo: %s", record.split_memo);
329 }
330 if (record.split_action_present)
331 {
332 DEBUG("Split action: %s", record.split_action);
333 }
334 if (record.split_reconcile_present)
335 {
336 DEBUG("Split reconcile: %c", record.split_reconcile);
337 }
338 if (record.amount_present)
339 {
340 string_ptr = gnc_numeric_to_string(record.amount);
341 DEBUG("Record amount: %s", string_ptr);
342 g_free(string_ptr);
343 }
344 if (record.value_present)
345 {
346 string_ptr = gnc_numeric_to_string(record.value);
347 DEBUG("Record value: %s", string_ptr);
348 g_free(string_ptr);
349 }
350 if (record.date_reconciled_present)
351 {
352 gnc_time64_to_iso8601_buff (record.date_reconciled, string_buf);
353 DEBUG("Reconciled date: %s", string_buf);
354 }
355}
356
357/* File pointer must already be at the beginning of a record */
358static void process_trans_record( FILE *log_file)
359{
360 char read_buf[2048];
361 char *read_retval;
362 char * trans_ro = NULL;
363 const char * record_end_str = "===== END";
364 int first_record = TRUE;
365 int record_ended = FALSE;
366 split_record record;
367 Transaction * trans = NULL;
368 Split * split = NULL;
369 Account * acct = NULL;
370 QofBook * book = gnc_get_current_book();
371
372 DEBUG("process_trans_record(): Begin...\n");
373
374 while ( record_ended == FALSE)
375 {
376 read_retval = fgets(read_buf, sizeof(read_buf), log_file);
377 if (read_retval != NULL &&
378 strncmp(record_end_str, read_buf, strlen(record_end_str)) != 0) /* If we are not at the end of the record */
379 {
380 /*DEBUG("process_trans_record(): Line read: %s%s",read_buf ,"\n");*/
381
382 record = interpret_split_record(g_strchomp(read_buf));
383 dump_split_record( record);
384 if (record.log_action_present)
385 {
386 switch (record.log_action)
387 {
388 case split_record::_enum_action::LOG_BEGIN_EDIT:
389 DEBUG("process_trans_record():Ignoring log action: LOG_BEGIN_EDIT"); /*Do nothing, there is no point*/
390 break;
391 case split_record::_enum_action::LOG_ROLLBACK:
392 DEBUG("process_trans_record():Ignoring log action: LOG_ROLLBACK");/*Do nothing, since we didn't do the begin_edit either*/
393 break;
394 case split_record::_enum_action::LOG_DELETE:
395 DEBUG("process_trans_record(): Playing back LOG_DELETE");
396 if ((trans = xaccTransLookup (&(record.trans_guid), book)) != NULL
397 && first_record == TRUE)
398 {
399 first_record = FALSE;
400 if (xaccTransGetReadOnly(trans))
401 {
402 PWARN("Destroying a read only transaction.");
403 xaccTransClearReadOnly(trans);
404 }
405 xaccTransBeginEdit(trans);
406 xaccTransDestroy(trans);
407 }
408 else if (first_record == TRUE)
409 {
410 PERR("The transaction to delete was not found!");
411 }
412 else
413 xaccTransDestroy(trans);
414 break;
415 case split_record::_enum_action::LOG_COMMIT:
416 DEBUG("process_trans_record(): Playing back LOG_COMMIT");
417 if (record.trans_guid_present == TRUE
418 && first_record == TRUE)
419 {
420 trans = xaccTransLookupDirect (record.trans_guid, book);
421 if (trans != NULL)
422 {
423 DEBUG("process_trans_record(): Transaction to be edited was found");
424 xaccTransBeginEdit(trans);
425 trans_ro = g_strdup(xaccTransGetReadOnly(trans));
426 if (trans_ro)
427 {
428 PWARN("Replaying a read only transaction.");
429 xaccTransClearReadOnly(trans);
430 }
431 }
432 else
433 {
434 DEBUG("process_trans_record(): Creating a new transaction");
435 trans = xaccMallocTransaction (book);
436 xaccTransBeginEdit(trans);
437 }
438
439 qof_instance_set_guid (QOF_INSTANCE (trans),
440 &(record.trans_guid));
441 /*Fill the transaction info*/
442 if (record.date_entered_present)
443 {
444 xaccTransSetDateEnteredSecs(trans, record.date_entered);
445 }
446 if (record.date_posted_present)
447 {
448 xaccTransSetDatePostedSecs(trans, record.date_posted);
449 }
450 if (record.trans_num_present)
451 {
452 xaccTransSetNum(trans, record.trans_num);
453 }
454 if (record.trans_descr_present)
455 {
456 xaccTransSetDescription(trans, record.trans_descr);
457 }
458 if (record.trans_notes_present)
459 {
460 xaccTransSetNotes(trans, record.trans_notes);
461 }
462 }
463 if (record.split_guid_present == TRUE) /*Fill the split info*/
464 {
465 gboolean is_new_split;
466
467 split = xaccSplitLookupDirect (record.split_guid, book);
468 if (split != NULL)
469 {
470 DEBUG("process_trans_record(): Split to be edited was found");
471 is_new_split = FALSE;
472 }
473 else
474 {
475 DEBUG("process_trans_record(): Creating a new split");
476 split = xaccMallocSplit(book);
477 is_new_split = TRUE;
478 }
479 xaccSplitSetGUID (split, &(record.split_guid));
480 if (record.acc_guid_present)
481 {
482 acct = xaccAccountLookupDirect(record.acc_guid, book);
483 xaccAccountInsertSplit(acct, split);
484
485 // No currency in the txn yet? Set one now.
486 if (!xaccTransGetCurrency(trans))
488 }
489 if (is_new_split)
490 xaccTransAppendSplit(trans, split);
491
492 if (record.split_memo_present)
493 {
494 xaccSplitSetMemo(split, record.split_memo);
495 }
496 if (record.split_action_present)
497 {
498 xaccSplitSetAction(split, record.split_action);
499 }
500 if (record.date_reconciled_present)
501 {
502 xaccSplitSetDateReconciledSecs (split, record.date_reconciled);
503 }
504 if (record.split_reconcile_present)
505 {
506 xaccSplitSetReconcile(split, record.split_reconcile);
507 }
508
509 if (record.amount_present)
510 {
511 xaccSplitSetAmount(split, record.amount);
512 }
513 if (record.value_present)
514 {
515 xaccSplitSetValue(split, record.value);
516 }
517 }
518 first_record = FALSE;
519 break;
520 }
521 }
522 else
523 {
524 PERR("Corrupted record");
525 }
526 }
527 else /* The record ended */
528 {
529 record_ended = TRUE;
530 DEBUG("process_trans_record(): Record ended\n");
531 if (trans != NULL) /*If we played with a transaction, commit it here*/
532 {
534 xaccTransSetReadOnly(trans, trans_ro);
535 xaccTransCommitEdit(trans);
536 g_free(trans_ro);
537 }
538 }
539 }
540}
541
542void gnc_file_log_replay (GtkWindow *parent)
543{
544 char *selected_filename;
545 char *default_dir;
546 char read_buf[256];
547 char *read_retval;
548 GtkFileFilter *filter;
549 FILE *log_file;
550 const char * record_start_str = "===== START";
551 /* NOTE: This string must match src/engine/TransLog.c (sans newline) */
552 const char * expected_header = "mod\ttrans_guid\tsplit_guid\ttime_now\t"
553 "date_entered\tdate_posted\tacc_guid\tacc_name\tnum\tdescription\t"
554 "notes\tmemo\taction\treconciled\tamount\tvalue\tdate_reconciled";
555
556 // qof_log_set_level(GNC_MOD_IMPORT, QOF_LOG_DEBUG);
557 ENTER(" ");
558
559 /* Don't log the log replay. This would only result in redundant logs */
561
562 default_dir = gnc_get_default_directory(GNC_PREFS_GROUP);
563
564 filter = gtk_file_filter_new();
565 gtk_file_filter_set_name(filter, "*.log");
566 gtk_file_filter_add_pattern(filter, "*.[Ll][Oo][Gg]");
567 selected_filename = gnc_file_dialog(parent,
568 _("Select a .log file to replay"),
569 g_list_prepend(NULL, filter),
570 default_dir,
571 GNC_FILE_DIALOG_OPEN);
572 g_free(default_dir);
573
574 if (selected_filename != NULL)
575 {
576 /* Remember the directory as the default. */
577 default_dir = g_path_get_dirname(selected_filename);
578 gnc_set_default_directory(GNC_PREFS_GROUP, default_dir);
579 g_free(default_dir);
580
581 /*strncpy(file,selected_filename, 255);*/
582 DEBUG("Filename found: %s", selected_filename);
583 if (xaccFileIsCurrentLog(selected_filename))
584 {
585 g_warning("Cannot open the current log file: %s", selected_filename);
586 gnc_error_dialog(NULL,
587 /* Translators: %s is the file name. */
588 _("Cannot open the current log file: %s"),
589 selected_filename);
590 }
591 else
592 {
593 DEBUG("Opening selected file");
594 log_file = g_fopen(selected_filename, "r");
595 if (!log_file || ferror(log_file) != 0)
596 {
597 int err = errno;
598 perror("File open failed");
599 /* Translators: First argument is the filename,
600 * second argument is the error.
601 */
602 gnc_error_dialog(NULL,
603 _("Failed to open log file: %s: %s"),
604 selected_filename,
605 strerror(err));
606 }
607 else
608 {
609 if ((read_retval = fgets(read_buf, sizeof(read_buf), log_file)) == NULL)
610 {
611 DEBUG("Read error or EOF");
612 gnc_info_dialog(NULL, "%s",
613 _("The log file you selected was empty."));
614 }
615 else
616 {
617 if (strncmp(expected_header, read_buf, strlen(expected_header)) != 0)
618 {
619 PERR("File header not recognised:\n%s", read_buf);
620 PERR("Expected:\n%s", expected_header);
621 gnc_error_dialog(NULL, "%s",
622 _("The log file you selected cannot be read. "
623 "The file header was not recognized."));
624 }
625 else
626 {
627 do
628 {
629 read_retval = fgets(read_buf, sizeof(read_buf), log_file);
630 /*DEBUG("Chunk read: %s",read_retval);*/
631 if (read_retval && strncmp(record_start_str, read_buf, strlen(record_start_str)) == 0) /* If a record started */
632 {
633 process_trans_record(log_file);
634 }
635 }
636 while (feof(log_file) == 0);
637 }
638 }
639 fclose(log_file);
640 }
641 }
642 g_free(selected_filename);
643 }
644 /* Start logging again */
646
647 LEAVE("");
648}
649
650
Account handling public routines.
convert single-entry accounts to clean double-entry
API for the transaction logger.
API for Transactions and Splits (journal entries)
.log replay module interface
utility functions for the GnuCash UI
char * gnc_time64_to_iso8601_buff(time64 time, char *buff)
The gnc_time64_to_iso8601_buff() routine takes the input UTC time64 value and prints it as an ISO-860...
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
void xaccTransSetNum(Transaction *trans, const char *xnum)
Sets the transaction Number (or ID) field; rather than use this function directly,...
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id,...
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction,...
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account.
Definition Account.h:1069
void xaccTransSetReadOnly(Transaction *trans, const char *reason)
Set the transaction to be ReadOnly by setting a non-NULL value as "reason".
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
void xaccTransSetNotes(Transaction *trans, const char *notes)
Sets the transaction Notes.
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition guid.cpp:208
gnc_commodity * gnc_account_or_default_currency(const Account *account, gboolean *currency_from_account_found)
Returns a gnc_commodity that is a currency, suitable for being a Transaction's currency.
void gnc_file_log_replay(GtkWindow *parent)
The gnc_file_log_replay() routine will pop up a standard file selection dialogue asking the user to p...
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
gnc_numeric gnc_numeric_from_string(const gchar *str)
Read a gnc_numeric from str, skipping any leading whitespace.
void xaccTransScrubCurrency(Transaction *trans)
The xaccTransScrubCurrency method fixes transactions without a common_currency by looking for the mos...
Definition Scrub.cpp:1121
gboolean xaccFileIsCurrentLog(const gchar *name)
Test a filename to see if it is the name of the current logfile.
Definition TransLog.cpp:141
void xaccLogEnable(void)
document me
Definition TransLog.cpp:100
void xaccLogDisable(void)
document me
Definition TransLog.cpp:96
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction's commodity.
Split * xaccMallocSplit(QofBook *book)
Constructor.
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
Set the date on which this split was reconciled by specifying the time as time64.
void xaccSplitSetAction(Split *split, const char *actn)
The Action is an arbitrary user-assigned string.
Definition Split.cpp:1786
STRUCTS.
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47