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