GnuCash  5.6-150-g038405b370+
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
50 a unique string either in gnc-engine.h or
51 locally.*/
52 static 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
63 typedef 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;
99 } split_record;
100 /********************************************************************\
101  * gnc_file_log_replay_import
102  * Entry point
103 \********************************************************************/
104 
105 static 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 */
110 static 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 
142 static 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 
256 static 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.trans_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 */
358 static 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  {
533  xaccTransScrubCurrency(trans);
534  xaccTransSetReadOnly(trans, trans_ro);
535  xaccTransCommitEdit(trans);
536  g_free(trans_ro);
537  }
538  }
539  }
540 }
541 
542 void 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_orig = "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  static char *expected_header = NULL;
556 
557  /* Use g_strdup_printf so we don't get accidental tab -> space conversion */
558  if (!expected_header)
559  expected_header = g_strdup(expected_header_orig);
560 
561  // qof_log_set_level(GNC_MOD_IMPORT, QOF_LOG_DEBUG);
562  ENTER(" ");
563 
564  /* Don't log the log replay. This would only result in redundant logs */
565  xaccLogDisable();
566 
567  default_dir = gnc_get_default_directory(GNC_PREFS_GROUP);
568 
569  filter = gtk_file_filter_new();
570  gtk_file_filter_set_name(filter, "*.log");
571  gtk_file_filter_add_pattern(filter, "*.[Ll][Oo][Gg]");
572  selected_filename = gnc_file_dialog(parent,
573  _("Select a .log file to replay"),
574  g_list_prepend(NULL, filter),
575  default_dir,
576  GNC_FILE_DIALOG_OPEN);
577  g_free(default_dir);
578 
579  if (selected_filename != NULL)
580  {
581  /* Remember the directory as the default. */
582  default_dir = g_path_get_dirname(selected_filename);
583  gnc_set_default_directory(GNC_PREFS_GROUP, default_dir);
584  g_free(default_dir);
585 
586  /*strncpy(file,selected_filename, 255);*/
587  DEBUG("Filename found: %s", selected_filename);
588  if (xaccFileIsCurrentLog(selected_filename))
589  {
590  g_warning("Cannot open the current log file: %s", selected_filename);
591  gnc_error_dialog(NULL,
592  /* Translators: %s is the file name. */
593  _("Cannot open the current log file: %s"),
594  selected_filename);
595  }
596  else
597  {
598  DEBUG("Opening selected file");
599  log_file = g_fopen(selected_filename, "r");
600  if (!log_file || ferror(log_file) != 0)
601  {
602  int err = errno;
603  perror("File open failed");
604  /* Translators: First argument is the filename,
605  * second argument is the error.
606  */
607  gnc_error_dialog(NULL,
608  _("Failed to open log file: %s: %s"),
609  selected_filename,
610  strerror(err));
611  }
612  else
613  {
614  if ((read_retval = fgets(read_buf, sizeof(read_buf), log_file)) == NULL)
615  {
616  DEBUG("Read error or EOF");
617  gnc_info_dialog(NULL, "%s",
618  _("The log file you selected was empty."));
619  }
620  else
621  {
622  if (strncmp(expected_header, read_buf, strlen(expected_header)) != 0)
623  {
624  PERR("File header not recognised:\n%s", read_buf);
625  PERR("Expected:\n%s", expected_header);
626  gnc_error_dialog(NULL, "%s",
627  _("The log file you selected cannot be read. "
628  "The file header was not recognized."));
629  }
630  else
631  {
632  do
633  {
634  read_retval = fgets(read_buf, sizeof(read_buf), log_file);
635  /*DEBUG("Chunk read: %s",read_retval);*/
636  if (read_retval && strncmp(record_start_str, read_buf, strlen(record_start_str)) == 0) /* If a record started */
637  {
638  process_trans_record(log_file);
639  }
640  }
641  while (feof(log_file) == 0);
642  }
643  }
644  fclose(log_file);
645  }
646  }
647  g_free(selected_filename);
648  }
649  /* Start logging again */
650  xaccLogEnable();
651 
652  LEAVE("");
653 }
654 
655 
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:92
time64 gnc_iso8601_to_time64_gmt(const gchar *)
The gnc_iso8601_to_time64_gmt() routine converts an ISO-8601 style date/time string to time64...
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:381
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
void xaccTransScrubCurrency(Transaction *trans)
The xaccTransScrubCurrency method fixes transactions without a common_currency by looking for the mos...
Definition: Scrub.cpp:1105
void xaccSplitSetAction(Split *split, const char *actn)
The Action is an arbitrary user-assigned string.
Definition: Split.cpp:1748
utility functions for the GnuCash UI
void xaccTransSetNotes(Transaction *trans, const char *notes)
Sets the transaction Notes.
STRUCTS.
void xaccLogDisable(void)
document me
Definition: TransLog.cpp:95
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
.log replay module interface
gboolean string_to_guid(const gchar *string, GncGUID *guid)
Given a string, replace the given guid with the parsed one unless the given value is null...
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
void xaccTransSetNum(Transaction *trans, const char *xnum)
Sets the transaction Number (or ID) field; rather than use this function directly, see &#39;gnc_set_num_action&#39; in engine/engine-helpers.c & .h which takes a user-set book option for selecting the source for the num-cell (the transaction-number or the split-action field) in registers/reports into account automatically.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
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:173
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
convert single-entry accounts to clean double-entry
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: gmock-Split.cpp:77
Account handling public routines.
void xaccTransSetReadOnly(Transaction *trans, const char *reason)
Set the transaction to be ReadOnly by setting a non-NULL value as "reason".
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
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...
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
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&#39;s currency.
API for the transaction logger.
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
Set the date on which this split was reconciled by specifying the time as time64. ...
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction, specified by a time64 (see ctime(3)).
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1048
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
gnc_numeric gnc_numeric_from_string(const gchar *str)
Read a gnc_numeric from str, skipping any leading whitespace.
gboolean xaccFileIsCurrentLog(const gchar *name)
Test a filename to see if it is the name of the current logfile.
Definition: TransLog.cpp:141
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
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...
Definition: gnc-date.cpp:1139
void xaccLogEnable(void)
document me
Definition: TransLog.cpp:99