GnuCash c935c2f+
Loading...
Searching...
No Matches
csv-transactions-export.cpp
1/*******************************************************************\
2 * csv-actions-export.c -- Export Transactions to a file *
3 * *
4 * Copyright (C) 2012 Robert Fewell *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License*
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22\********************************************************************/
27#include "config.h"
28
29#include <glib/gstdio.h>
30#include <stdbool.h>
31
32#include <string>
33#include <unordered_set>
34
35#include <gnc-filepath-utils.h>
36#include "gnc-commodity.h"
37#include "gnc-ui-util.h"
38#include "Query.h"
39#include "Transaction.h"
40#include "engine-helpers.h"
41#include "qofbookslots.h"
42#include "guid.hpp"
43
45#include "csv-export-helpers.hpp"
46
47/* This static indicates the debugging module that this .o belongs to. */
48static QofLogModule log_module = GNC_MOD_ASSISTANT;
49
50
51/*******************************************************************/
52
53/******************** Helper functions *********************/
54
55static std::string
56get_date (Transaction *trans)
57{
58 char datebuff [MAX_DATE_LENGTH + 1];
60 return datebuff;
61}
62
63
64static std::string
65get_guid (Transaction *trans)
66{
67 return gnc::GUID (*qof_entity_get_guid (QOF_INSTANCE (trans))).to_string();
68}
69
70// Reconcile Date
71static std::string
72get_reconcile_date (Split *split)
73{
74 if (xaccSplitGetReconcile (split) != YREC)
75 return "";
76
77 char datebuff[MAX_DATE_LENGTH + 1];
79 return datebuff;
80}
81
82// Account Name short or Long
83static std::string
84get_account_name (Split *split, bool full)
85{
86 auto account{xaccSplitGetAccount (split)};
87 return full ? account_get_fullname_str (account) : xaccAccountGetName (account);
88}
89
90// Number
91static std::string
92get_number (Transaction *trans)
93{
94 auto num{xaccTransGetNum (trans)};
95 return (num ? num : "");
96}
97
98// Description
99static std::string
100get_description (Transaction *trans)
101{
102 auto desc{xaccTransGetDescription (trans)};
103 return (desc ? desc : "");
104}
105
106// Notes
107static std::string
108get_notes (Transaction *trans)
109{
110 auto notes{xaccTransGetNotes (trans)};
111 return (notes ? notes : "");
112}
113
114// Void reason
115static std::string
116get_void_reason (Transaction *trans)
117{
118 auto void_reason{xaccTransGetVoidReason (trans)};
119 return (void_reason ? void_reason : "");
120}
121
122// Memo
123static std::string
124get_memo (Split *split)
125{
126 auto memo{xaccSplitGetMemo (split)};
127 return (memo ? memo : "");
128}
129
130// Full Category Path or Not
131static std::string
132get_category (Split *split, bool full)
133{
134 auto other{xaccSplitGetOtherSplit(split)};
135 return other ? get_account_name (other, full) : _("-- Split Transaction --");
136}
137
138// Action
139static std::string
140get_action (Split *split)
141{
142 auto action{xaccSplitGetAction (split)};
143 return (action ? action : "");
144}
145
146// Reconcile
147static std::string
148get_reconcile (Split *split)
149{
150 auto recon{gnc_get_reconcile_str (xaccSplitGetReconcile (split))};
151 return (recon ? recon : "");
152}
153
154// Transaction commodity
155static std::string
156get_commodity (Transaction *trans)
157{
159}
160
161// Amount with Symbol or not
162static std::string
163get_amount (Split *split, bool t_void, bool symbol)
164{
165 auto amt_num{t_void ? xaccSplitVoidFormerAmount (split) : xaccSplitGetAmount (split)};
166 auto pinfo{gnc_split_amount_print_info (split, symbol)};
167 if (!symbol)
168 pinfo.use_separators = 0;
169 return xaccPrintAmount (amt_num, pinfo);
170}
171
172// Value with Symbol or not
173static std::string
174get_value (Split *split, bool t_void, bool symbol)
175{
176 auto trans{xaccSplitGetParent(split)};
177 auto tcurr{xaccTransGetCurrency (trans)};
178 auto pai{gnc_commodity_print_info (tcurr, symbol)};
179 if (!symbol)
180 pai.use_separators = 0;
181 auto amt_num{t_void ? xaccSplitVoidFormerValue (split): xaccSplitGetValue (split)};
182 return xaccPrintAmount (amt_num, pai);
183}
184
185// Share Price / Conversion factor
186static std::string
187get_rate (Split *split, bool t_void)
188{
189 auto curr{xaccAccountGetCommodity (xaccSplitGetAccount (split))};
190 auto amt_num{t_void ? gnc_numeric_zero() : xaccSplitGetSharePrice (split)};
191 return xaccPrintAmount (amt_num, gnc_default_price_print_info (curr));
192}
193
194// Share Price / Conversion factor
195static std::string
196get_price (Split *split, bool t_void)
197{
198 auto curr{xaccAccountGetCommodity (xaccSplitGetAccount (split))};
199 auto cf{t_void
203 GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND_HALF_UP)
204 : xaccSplitGetSharePrice (split)};
205 return xaccPrintAmount (cf, gnc_default_price_print_info (curr));
206}
207
208/******************************************************************************/
209
210static StringVec
211make_simple_trans_line (Transaction *trans, Split *split)
212{
213 auto t_void{xaccTransGetVoidStatus (trans)};
214 return {
215 get_date (trans),
216 get_account_name (split, true),
217 get_number (trans),
218 get_description (trans),
219 get_category (split, true),
220 get_reconcile (split),
221 get_amount (split, t_void, true),
222 get_amount (split, t_void, false),
223 get_value (split, t_void, true),
224 get_value (split, t_void, false),
225 get_rate (split, t_void)
226 };
227}
228
229static StringVec
230make_complex_trans_line (Transaction *trans, Split *split)
231{
232 auto t_void{xaccTransGetVoidStatus (trans)};
233 return {
234 get_date (trans),
235 get_guid (trans),
236 get_number (trans),
237 get_description (trans),
238 get_notes (trans),
239 get_commodity (trans),
240 get_void_reason (trans),
241 get_action (split),
242 get_memo (split),
243 get_account_name (split, true),
244 get_account_name (split, false),
245 get_amount (split, t_void, true),
246 get_amount (split, t_void, false),
247 get_value (split, t_void, true),
248 get_value (split, t_void, false),
249 get_reconcile (split),
250 get_reconcile_date (split),
251 get_price (split, t_void)
252 };
253}
254
255using TransSet = std::unordered_set<Transaction*>;
256
257/*******************************************************
258 * account_splits
259 *
260 * gather the splits / transactions for an account and
261 * send them to a file
262 *******************************************************/
263static void
264export_query_splits (CsvExportInfo *info, bool is_trading_acct,
265 std::ofstream& ss, TransSet& trans_set)
266{
267 g_return_if_fail (info);
268
269 /* Run the query */
270 for (GList *splits = qof_query_run (info->query); !info->failed && splits;
271 splits = splits->next)
272 {
273 auto split{static_cast<Split*>(splits->data)};
274 auto trans{xaccSplitGetParent (split)};
275
276 // Look for trans already exported in trans_set
277 if (!trans_set.emplace (trans).second)
278 continue;
279
280 // Look for blank split
281 Account *split_acc = xaccSplitGetAccount (split);
282 if (!split_acc)
283 continue;
284
285 // Only export trading splits when exporting a trading account
286 if (!is_trading_acct &&
287 (xaccAccountGetType (split_acc) == ACCT_TYPE_TRADING))
288 continue;
289
290 if (info->simple_layout)
291 {
292 // Write line in simple layout, equivalent to a single line register view
293 auto line = make_simple_trans_line (trans, split);
294 info->failed = !gnc_csv_add_line (ss, line, info->use_quotes,
295 info->separator_str);
296 continue;
297 }
298
299 /* Loop through the list of splits for the Transaction */
300 for (auto node = xaccTransGetSplitList (trans); !info->failed && node;
301 node = node->next)
302 {
303 auto t_split{static_cast<Split*>(node->data)};
304
305 // Only export trading splits if exporting a trading account
306 Account *tsplit_acc = xaccSplitGetAccount (t_split);
307 if (!is_trading_acct &&
308 (xaccAccountGetType (tsplit_acc) == ACCT_TYPE_TRADING))
309 continue;
310
311 // Write complex Split Line.
312 auto line = make_complex_trans_line (trans, t_split);
313 info->failed = !gnc_csv_add_line (ss, line, info->use_quotes,
314 info->separator_str);
315 }
316 }
317}
318
319static void
320account_splits (CsvExportInfo *info, Account *acc,
321 std::ofstream& ss, TransSet& trans_set)
322{
323 g_return_if_fail (info && GNC_IS_ACCOUNT (acc));
324 // Setup the query for normal transaction export
325 auto p1 = g_slist_prepend (g_slist_prepend (nullptr, (gpointer)TRANS_DATE_POSTED), (gpointer)SPLIT_TRANS);
326 auto p2 = g_slist_prepend (nullptr, (gpointer)QUERY_DEFAULT_SORT);
327 info->query = qof_query_create_for (GNC_ID_SPLIT);
328 qof_query_set_book (info->query, gnc_get_current_book());
329 qof_query_set_sort_order (info->query, p1, p2, nullptr);
330 xaccQueryAddSingleAccountMatch (info->query, acc, QOF_QUERY_AND);
331 xaccQueryAddDateMatchTT (info->query, true, info->csvd.start_time, true, info->csvd.end_time, QOF_QUERY_AND);
332 export_query_splits (info, xaccAccountGetType (acc) == ACCT_TYPE_TRADING, ss, trans_set);
333 qof_query_destroy (info->query);
334}
335
336/*******************************************************
337 * csv_transactions_export
338 *
339 * write a list of transactions to a text file
340 *******************************************************/
341void csv_transactions_export (CsvExportInfo *info)
342{
343 ENTER("");
344 DEBUG("File name is : %s", info->file_name);
345
346 StringVec headers;
347 bool num_action = qof_book_use_split_action_for_num_field (gnc_get_current_book());
348
349 /* Header string */
350 if (info->simple_layout)
351 {
352 /* Translators: The following symbols will build the header
353 line of exported CSV files: */
354 headers = {
355 _("Date"),
356 _("Account Name"),
357 (num_action ? _("Transaction Number") : _("Number")),
358 _("Description"),
359 _("Full Category Path"),
360 _("Reconcile"),
361 _("Amount With Sym"),
362 _("Amount Num."),
363 _("Value With Sym"),
364 _("Value Num."),
365 _("Rate/Price"),
366 };
367 }
368 else
369 headers = {
370 _("Date"),
371 _("Transaction ID"),
372 (num_action ? _("Transaction Number") : _("Number")),
373 _("Description"),
374 _("Notes"),
375 _("Commodity/Currency"),
376 _("Void Reason"),
377 (num_action ? _("Number/Action") : _("Action")),
378 _("Memo"),
379 _("Full Account Name"),
380 _("Account Name"),
381 _("Amount With Sym"),
382 _("Amount Num."),
383 _("Value With Sym"),
384 _("Value Num."),
385 _("Reconcile"),
386 _("Reconcile Date"),
387 _("Rate/Price"),
388 };
389
390 /* Write header line */
391 auto ss{gnc_open_filestream(info->file_name)};
392 info->failed = !gnc_csv_add_line (ss, headers, info->use_quotes, info->separator_str);
393
394 /* Go through list of accounts */
395 TransSet trans_set;
396
397 switch (info->export_type)
398 {
399 case XML_EXPORT_TRANS:
400 for (auto ptr = info->csva.account_list; !ss.fail() && ptr; ptr = g_list_next(ptr))
401 account_splits (info, GNC_ACCOUNT(ptr->data), ss, trans_set);
402 break;
403 case XML_EXPORT_REGISTER:
404 export_query_splits (info, false, ss, trans_set);
405 break;
406 default:
407 PERR ("unknown export_type %d", info->export_type);
408 }
409
410 info->failed = ss.fail();
411 LEAVE("");
412}
413
API for Transactions and Splits (journal entries)
CSV Export Transactions.
Commodity handling public routines.
File path resolution utility functions.
utility functions for the GnuCash UI
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition Account.cpp:3289
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition Account.cpp:3267
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Definition Account.cpp:3408
gboolean qof_book_use_split_action_for_num_field(const QofBook *book)
Returns TRUE if this book uses split action field as the 'Num' field, FALSE if it uses transaction nu...
const char * gnc_commodity_get_unique_name(const gnc_commodity *cm)
Retrieve the 'unique' name for the specified commodity.
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
Definition gnc-date.h:108
size_t qof_print_date_buff(char *buff, const size_t len, time64 t)
Convenience: calls through to qof_print_date_dmy_buff().
Definition gnc-date.cpp:574
const char * xaccTransGetVoidReason(const Transaction *trans)
Returns the user supplied textual reason why a transaction was voided.
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
const char * xaccTransGetNotes(const Transaction *trans)
Gets the transaction Notes.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
const char * xaccTransGetNum(const Transaction *trans)
Gets the transaction Number (or ID) field; rather than use this function directly,...
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
const GncGUID * qof_entity_get_guid(gconstpointer ent)
#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 ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
#define GNC_HOW_DENOM_SIGFIGS(n)
Build a 'how' value that will generate a denominator that will keep at least n significant figures in...
#define QUERY_DEFAULT_SORT
Default sort object type.
Definition qofquery.h:105
void qof_query_set_book(QofQuery *query, QofBook *book)
Set the book to be searched.
void qof_query_set_sort_order(QofQuery *q, QofQueryParamList *params1, QofQueryParamList *params2, QofQueryParamList *params3)
When a query is run, the results are sorted before being returned.
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
GList * qof_query_run(QofQuery *query)
Perform the query, return the results.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
const char * xaccSplitGetAction(const Split *split)
Returns the action string.
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
Definition Split.cpp:1859
gnc_numeric xaccSplitVoidFormerValue(const Split *split)
Returns the original pre-void value of a split.
Definition Split.cpp:2199
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
gnc_numeric xaccSplitGetSharePrice(const Split *split)
Returns the price of the split, that is, the value divided by the amount.
Definition Split.cpp:1995
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
gnc_numeric xaccSplitVoidFormerAmount(const Split *split)
Returns the original pre-void amount of a split.
Definition Split.cpp:2191
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits.
#define YREC
The Split has been reconciled.
Definition Split.h:74
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
STRUCTS.