mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Merge branch 'csv-tree-export-cpp' into stable #1598
This commit is contained in:
commit
e5349a8b36
@ -1,8 +1,12 @@
|
|||||||
|
|
||||||
|
add_subdirectory(test)
|
||||||
|
|
||||||
set(csv_export_SOURCES
|
set(csv_export_SOURCES
|
||||||
gnc-plugin-csv-export.c
|
gnc-plugin-csv-export.c
|
||||||
|
csv-export-helpers.cpp
|
||||||
assistant-csv-export.c
|
assistant-csv-export.c
|
||||||
csv-tree-export.c
|
csv-tree-export.cpp
|
||||||
csv-transactions-export.c
|
csv-transactions-export.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add dependency on config.h
|
# Add dependency on config.h
|
||||||
@ -11,6 +15,7 @@ set_source_files_properties (${csv_export_SOURCES} PROPERTIES OBJECT_DEPENDS ${C
|
|||||||
set(csv_export_noinst_HEADERS
|
set(csv_export_noinst_HEADERS
|
||||||
gnc-plugin-csv-export.h
|
gnc-plugin-csv-export.h
|
||||||
assistant-csv-export.h
|
assistant-csv-export.h
|
||||||
|
csv-export-helpers.hpp
|
||||||
csv-tree-export.h
|
csv-tree-export.h
|
||||||
csv-transactions-export.h
|
csv-transactions-export.h
|
||||||
)
|
)
|
||||||
|
84
gnucash/import-export/csv-exp/csv-export-helpers.cpp
Normal file
84
gnucash/import-export/csv-exp/csv-export-helpers.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*******************************************************************\
|
||||||
|
* csv-export-helpers.c -- Functions to assist csv export *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License as *
|
||||||
|
* published by the Free Software Foundation; either version 2 of *
|
||||||
|
* the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License*
|
||||||
|
* along with this program; if not, contact: *
|
||||||
|
* *
|
||||||
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||||
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||||
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||||
|
\********************************************************************/
|
||||||
|
/** @file csv-export-helprs.cpp
|
||||||
|
@brief CSV Export helper functions
|
||||||
|
@author Christopher Lam
|
||||||
|
*/
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "gnc-ui-util.h"
|
||||||
|
#include "csv-export-helpers.hpp"
|
||||||
|
|
||||||
|
/* This static indicates the debugging module that this .o belongs to. */
|
||||||
|
[[maybe_unused]] static QofLogModule log_module = GNC_MOD_ASSISTANT;
|
||||||
|
|
||||||
|
/* CSV spec requires CRLF line endings. Tweak the end-of-line string so this
|
||||||
|
* true for each platform */
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
# define EOLSTR "\n"
|
||||||
|
#else
|
||||||
|
# define EOLSTR "\r\n"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define QUOTE '"'
|
||||||
|
|
||||||
|
bool
|
||||||
|
gnc_csv_add_line (std::ostream& ss, const StringVec& str_vec,
|
||||||
|
bool use_quotes, const char* sep)
|
||||||
|
{
|
||||||
|
auto first{true};
|
||||||
|
auto sep_view{std::string_view (sep ? sep : "")};
|
||||||
|
for (const auto& str : str_vec)
|
||||||
|
{
|
||||||
|
auto need_quote = use_quotes
|
||||||
|
|| (!sep_view.empty() && str.find (sep_view) != std::string::npos)
|
||||||
|
|| str.find_first_of ("\"\n\r") != std::string::npos;
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
ss << sep_view;
|
||||||
|
|
||||||
|
if (need_quote)
|
||||||
|
ss << QUOTE;
|
||||||
|
|
||||||
|
for (const char& p : str)
|
||||||
|
{
|
||||||
|
ss << p;
|
||||||
|
if (p == QUOTE)
|
||||||
|
ss << QUOTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_quote)
|
||||||
|
ss << QUOTE;
|
||||||
|
|
||||||
|
if (ss.fail())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ss << EOLSTR;
|
||||||
|
|
||||||
|
return !ss.fail();
|
||||||
|
}
|
39
gnucash/import-export/csv-exp/csv-export-helpers.hpp
Normal file
39
gnucash/import-export/csv-exp/csv-export-helpers.hpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*******************************************************************\
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License as *
|
||||||
|
* published by the Free Software Foundation; either version 2 of *
|
||||||
|
* the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License*
|
||||||
|
* along with this program; if not, contact: *
|
||||||
|
* *
|
||||||
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||||
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||||
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||||
|
\********************************************************************/
|
||||||
|
|
||||||
|
#ifndef CSV_EXPORT_HELPERS
|
||||||
|
#define CSV_EXPORT_HELPERS
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using StringVec = std::vector<std::string>;
|
||||||
|
|
||||||
|
// add a csv-formatted line onto output stream. charsvec is the vector
|
||||||
|
// of std::strings, sep is the separator string. use_quotes to always
|
||||||
|
// "quote"; some strings may be quoted anyway if contains separator
|
||||||
|
// string, quote, \r or \n. This function returns a bool indicating
|
||||||
|
// success.
|
||||||
|
bool gnc_csv_add_line (std::ostream& ss, const StringVec& charsvec,
|
||||||
|
bool use_quotes, const char* sep);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,592 +0,0 @@
|
|||||||
/*******************************************************************\
|
|
||||||
* csv-actions-export.c -- Export Transactions to a file *
|
|
||||||
* *
|
|
||||||
* Copyright (C) 2012 Robert Fewell *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or *
|
|
||||||
* modify it under the terms of the GNU General Public License as *
|
|
||||||
* published by the Free Software Foundation; either version 2 of *
|
|
||||||
* the License, or (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License*
|
|
||||||
* along with this program; if not, contact: *
|
|
||||||
* *
|
|
||||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
|
||||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
|
||||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
|
||||||
\********************************************************************/
|
|
||||||
/** @file csv-transactions-export.c
|
|
||||||
@brief CSV Export Transactions
|
|
||||||
@author Copyright (c) 2012 Robert Fewell
|
|
||||||
*/
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <glib/gstdio.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include "gnc-commodity.h"
|
|
||||||
#include "gnc-ui-util.h"
|
|
||||||
#include "Query.h"
|
|
||||||
#include "Transaction.h"
|
|
||||||
#include "engine-helpers.h"
|
|
||||||
#include "qofbookslots.h"
|
|
||||||
|
|
||||||
#include "csv-transactions-export.h"
|
|
||||||
|
|
||||||
/* This static indicates the debugging module that this .o belongs to. */
|
|
||||||
static QofLogModule log_module = GNC_MOD_ASSISTANT;
|
|
||||||
|
|
||||||
/* CSV spec requires CRLF line endings. Tweak the end-of-line string so this
|
|
||||||
* true for each platform */
|
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
# define EOLSTR "\n"
|
|
||||||
#else
|
|
||||||
# define EOLSTR "\r\n"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************/
|
|
||||||
|
|
||||||
/*******************************************************
|
|
||||||
* write_line_to_file
|
|
||||||
*
|
|
||||||
* write a text string to a file pointer, return true if
|
|
||||||
* successful.
|
|
||||||
*******************************************************/
|
|
||||||
static
|
|
||||||
bool write_line_to_file (FILE *fh, char * line)
|
|
||||||
{
|
|
||||||
DEBUG("Account String: %s", line);
|
|
||||||
|
|
||||||
/* Write account line */
|
|
||||||
int len = strlen (line);
|
|
||||||
int written = fwrite (line, 1, len, fh);
|
|
||||||
|
|
||||||
return (written == len);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************
|
|
||||||
* csv_txn_test_field_string
|
|
||||||
*
|
|
||||||
* Test the field string for ," and new lines
|
|
||||||
*******************************************************/
|
|
||||||
static
|
|
||||||
gchar *csv_txn_test_field_string (CsvExportInfo *info, const gchar *string_in)
|
|
||||||
{
|
|
||||||
/* Check for " and then "" them */
|
|
||||||
gchar **parts = g_strsplit (string_in, "\"", -1);
|
|
||||||
gchar *string_parts = g_strjoinv ("\"\"", parts);
|
|
||||||
g_strfreev (parts);
|
|
||||||
|
|
||||||
/* Check for separator string and \n and " in field,
|
|
||||||
if so quote field if not already quoted */
|
|
||||||
bool need_quote = !g_strrstr (string_parts, info->separator_str) ||
|
|
||||||
!g_strrstr (string_parts, "\n") ||
|
|
||||||
!g_strrstr (string_parts, "\"");
|
|
||||||
|
|
||||||
gchar *string_out;
|
|
||||||
if (!info->use_quotes && need_quote)
|
|
||||||
string_out = g_strconcat ("\"", string_parts, "\"", NULL);
|
|
||||||
else
|
|
||||||
string_out = g_strdup (string_parts);
|
|
||||||
|
|
||||||
g_free (string_parts);
|
|
||||||
return string_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************** Helper functions *********************/
|
|
||||||
|
|
||||||
// Transaction Date
|
|
||||||
static gchar*
|
|
||||||
add_date (gchar *so_far, Transaction *trans, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
gchar *date = qof_print_date (xaccTransGetDate (trans));
|
|
||||||
gchar *result = g_strconcat (so_far, info->end_sep, date, info->mid_sep, NULL);
|
|
||||||
g_free (date);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Transaction GUID
|
|
||||||
static gchar*
|
|
||||||
add_guid (gchar *so_far, Transaction *trans, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
gchar *guid = guid_to_string (xaccTransGetGUID (trans));
|
|
||||||
gchar *result = g_strconcat (so_far, guid, info->mid_sep, NULL);
|
|
||||||
g_free (guid);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reconcile Date
|
|
||||||
static gchar*
|
|
||||||
add_reconcile_date (gchar *so_far, Split *split, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
gchar *result;
|
|
||||||
if (xaccSplitGetReconcile (split) == YREC)
|
|
||||||
{
|
|
||||||
time64 t = xaccSplitGetDateReconciled (split);
|
|
||||||
char str_rec_date[MAX_DATE_LENGTH + 1];
|
|
||||||
memset (str_rec_date, 0, sizeof(str_rec_date));
|
|
||||||
qof_print_date_buff (str_rec_date, MAX_DATE_LENGTH, t);
|
|
||||||
result = g_strconcat (so_far, str_rec_date, info->mid_sep, NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
result = g_strconcat (so_far, info->mid_sep, NULL);
|
|
||||||
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Account Name short or Long
|
|
||||||
static gchar*
|
|
||||||
add_account_name (gchar *so_far, Split *split, bool full, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
Account *account = xaccSplitGetAccount (split);
|
|
||||||
gchar *name = NULL;
|
|
||||||
if (full)
|
|
||||||
name = gnc_account_get_full_name (account);
|
|
||||||
else
|
|
||||||
name = g_strdup (xaccAccountGetName (account));
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, name);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (name);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Number
|
|
||||||
static gchar*
|
|
||||||
add_number (gchar *so_far, Transaction *trans, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
const gchar *num = xaccTransGetNum (trans);
|
|
||||||
num = num ? num : "";
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, num);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Description
|
|
||||||
static gchar*
|
|
||||||
add_description (gchar *so_far, Transaction *trans, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
const gchar *desc = xaccTransGetDescription (trans);
|
|
||||||
desc = desc ? desc : "";
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, desc);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notes
|
|
||||||
static gchar*
|
|
||||||
add_notes (gchar *so_far, Transaction *trans, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
const gchar *notes = xaccTransGetNotes (trans);
|
|
||||||
notes = notes ? notes : "" ;
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, notes);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Void reason
|
|
||||||
static gchar*
|
|
||||||
add_void_reason (gchar *so_far, Transaction *trans, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
const gchar *void_reason = xaccTransGetVoidReason (trans);
|
|
||||||
void_reason = void_reason ? void_reason : "";
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, void_reason);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Memo
|
|
||||||
static gchar*
|
|
||||||
add_memo (gchar *so_far, Split *split, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
const gchar *memo = xaccSplitGetMemo (split);
|
|
||||||
memo = memo ? memo : "";
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, memo);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Full Category Path or Not
|
|
||||||
static gchar*
|
|
||||||
add_category (gchar *so_far, Split *split, bool full, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
gchar *cat;
|
|
||||||
if (full)
|
|
||||||
cat = xaccSplitGetCorrAccountFullName (split);
|
|
||||||
else
|
|
||||||
cat = g_strdup(xaccSplitGetCorrAccountName (split));
|
|
||||||
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, cat);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (cat);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Action
|
|
||||||
static gchar*
|
|
||||||
add_action (gchar *so_far, Split *split, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
const gchar *action = xaccSplitGetAction (split);
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, action);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reconcile
|
|
||||||
static gchar*
|
|
||||||
add_reconcile (gchar *so_far, Split *split, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
const gchar *recon = gnc_get_reconcile_str (xaccSplitGetReconcile (split));
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, recon);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transaction commodity
|
|
||||||
static gchar*
|
|
||||||
add_commodity (gchar *so_far, Transaction *trans, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
const gchar *comm_m = gnc_commodity_get_unique_name (xaccTransGetCurrency (trans));
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, comm_m);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Amount with Symbol or not
|
|
||||||
static gchar*
|
|
||||||
add_amount (gchar *so_far, Split *split, bool t_void, bool symbol, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
const gchar *amt;
|
|
||||||
if (t_void)
|
|
||||||
amt = xaccPrintAmount (xaccSplitVoidFormerAmount (split), gnc_split_amount_print_info (split, symbol));
|
|
||||||
else
|
|
||||||
amt = xaccPrintAmount (xaccSplitGetAmount (split), gnc_split_amount_print_info (split, symbol));
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, amt);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value with Symbol or not
|
|
||||||
static gchar*
|
|
||||||
add_value (gchar *so_far, Split *split, bool t_void, bool symbol, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
Transaction *trans = xaccSplitGetParent(split);
|
|
||||||
gnc_commodity *tcurr = xaccTransGetCurrency (trans);
|
|
||||||
GNCPrintAmountInfo pai = gnc_commodity_print_info (tcurr, symbol);
|
|
||||||
const gchar *amt;
|
|
||||||
if (t_void)
|
|
||||||
amt = xaccPrintAmount (xaccSplitVoidFormerValue (split), pai);
|
|
||||||
else
|
|
||||||
amt = xaccPrintAmount (xaccSplitGetValue (split), pai);
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, amt);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->mid_sep, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Share Price / Conversion factor
|
|
||||||
static gchar*
|
|
||||||
add_rate (gchar *so_far, Split *split, bool t_void, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
gnc_commodity *curr = xaccAccountGetCommodity (xaccSplitGetAccount (split));
|
|
||||||
const gchar *amt;
|
|
||||||
if (t_void)
|
|
||||||
amt = xaccPrintAmount (gnc_numeric_zero(), gnc_default_price_print_info (curr));
|
|
||||||
else
|
|
||||||
amt = xaccPrintAmount (xaccSplitGetSharePrice (split), gnc_default_price_print_info (curr));
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, amt);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->end_sep, EOLSTR, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Share Price / Conversion factor
|
|
||||||
static gchar*
|
|
||||||
add_price (gchar *so_far, Split *split, bool t_void, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
gnc_commodity *curr = xaccAccountGetCommodity (xaccSplitGetAccount (split));
|
|
||||||
const gchar *string_amount;
|
|
||||||
if (t_void)
|
|
||||||
{
|
|
||||||
gnc_numeric cf = gnc_numeric_div (xaccSplitVoidFormerValue (split), xaccSplitVoidFormerAmount (split), GNC_DENOM_AUTO,
|
|
||||||
GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND_HALF_UP);
|
|
||||||
string_amount = xaccPrintAmount (cf, gnc_default_price_print_info (curr));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
string_amount = xaccPrintAmount (xaccSplitGetSharePrice (split), gnc_default_price_print_info (curr));
|
|
||||||
|
|
||||||
gchar *conv = csv_txn_test_field_string (info, string_amount);
|
|
||||||
gchar *result = g_strconcat (so_far, conv, info->end_sep, EOLSTR, NULL);
|
|
||||||
g_free (conv);
|
|
||||||
g_free (so_far);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
static gchar*
|
|
||||||
make_simple_trans_line (Transaction *trans, Split *split, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
bool t_void = xaccTransGetVoidStatus (trans);
|
|
||||||
|
|
||||||
gchar *exp_line = g_strdup("");
|
|
||||||
exp_line = add_date (exp_line, trans, info);
|
|
||||||
exp_line = add_account_name (exp_line, split, true, info);
|
|
||||||
exp_line = add_number (exp_line, trans, info);
|
|
||||||
exp_line = add_description (exp_line, trans, info);
|
|
||||||
exp_line = add_category (exp_line, split, true, info);
|
|
||||||
exp_line = add_reconcile (exp_line, split, info);
|
|
||||||
exp_line = add_amount (exp_line, split, t_void, true, info);
|
|
||||||
exp_line = add_amount (exp_line, split, t_void, false, info);
|
|
||||||
exp_line = add_value (exp_line, split, t_void, true, info);
|
|
||||||
exp_line = add_value (exp_line, split, t_void, false, info);
|
|
||||||
exp_line = add_rate (exp_line, split, t_void, info);
|
|
||||||
return exp_line;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gchar*
|
|
||||||
make_complex_trans_line (Transaction *trans, Split *split, CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
// Transaction fields
|
|
||||||
gchar *exp_line = g_strdup("");
|
|
||||||
exp_line = add_date (exp_line, trans, info);
|
|
||||||
exp_line = add_guid (exp_line, trans, info);
|
|
||||||
exp_line = add_number (exp_line, trans, info);
|
|
||||||
exp_line = add_description (exp_line, trans, info);
|
|
||||||
exp_line = add_notes (exp_line, trans, info);
|
|
||||||
exp_line = add_commodity (exp_line, trans, info);
|
|
||||||
exp_line = add_void_reason (exp_line, trans, info);
|
|
||||||
bool t_void = xaccTransGetVoidStatus (trans);
|
|
||||||
|
|
||||||
//Split fields
|
|
||||||
exp_line = add_action (exp_line, split, info);
|
|
||||||
exp_line = add_memo (exp_line, split, info);
|
|
||||||
exp_line = add_account_name (exp_line, split, true, info);
|
|
||||||
exp_line = add_account_name (exp_line, split, false, info);
|
|
||||||
exp_line = add_amount (exp_line, split, t_void, true, info);
|
|
||||||
exp_line = add_amount (exp_line, split, t_void, false, info);
|
|
||||||
exp_line = add_value (exp_line, split, t_void, true, info);
|
|
||||||
exp_line = add_value (exp_line, split, t_void, false, info);
|
|
||||||
exp_line = add_reconcile (exp_line, split, info);
|
|
||||||
exp_line = add_reconcile_date (exp_line, split, info);
|
|
||||||
exp_line = add_price (exp_line, split, t_void, info);
|
|
||||||
|
|
||||||
return exp_line;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************
|
|
||||||
* account_splits
|
|
||||||
*
|
|
||||||
* gather the splits / transactions for an account and
|
|
||||||
* send them to a file
|
|
||||||
*******************************************************/
|
|
||||||
static
|
|
||||||
void account_splits (CsvExportInfo *info, Account *acc, FILE *fh )
|
|
||||||
{
|
|
||||||
bool is_trading_acct = acc && (xaccAccountGetType (acc) == ACCT_TYPE_TRADING);
|
|
||||||
|
|
||||||
// Setup the query for normal transaction export
|
|
||||||
if (info->export_type == XML_EXPORT_TRANS)
|
|
||||||
{
|
|
||||||
info->query = qof_query_create_for (GNC_ID_SPLIT);
|
|
||||||
QofBook *book = gnc_get_current_book();
|
|
||||||
qof_query_set_book (info->query, book);
|
|
||||||
|
|
||||||
/* Sort by transaction date */
|
|
||||||
GSList *p1 = g_slist_prepend (NULL, TRANS_DATE_POSTED);
|
|
||||||
p1 = g_slist_prepend (p1, SPLIT_TRANS);
|
|
||||||
GSList *p2 = g_slist_prepend (NULL, QUERY_DEFAULT_SORT);
|
|
||||||
qof_query_set_sort_order (info->query, p1, p2, NULL);
|
|
||||||
|
|
||||||
xaccQueryAddSingleAccountMatch (info->query, acc, QOF_QUERY_AND);
|
|
||||||
xaccQueryAddDateMatchTT (info->query, true, info->csvd.start_time, true, info->csvd.end_time, QOF_QUERY_AND);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Run the query */
|
|
||||||
GList *trans_list = NULL;
|
|
||||||
for (GList *splits = qof_query_run (info->query); splits; splits = splits->next)
|
|
||||||
{
|
|
||||||
Split *split = splits->data;
|
|
||||||
|
|
||||||
// Look for trans already exported in trans_list
|
|
||||||
Transaction *trans = xaccSplitGetParent (split);
|
|
||||||
if (g_list_find (trans_list, trans))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Look for blank split
|
|
||||||
Account *split_acc = xaccSplitGetAccount (split);
|
|
||||||
if (!split_acc)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Only export trading splits when exporting a trading account
|
|
||||||
if (!is_trading_acct &&
|
|
||||||
(xaccAccountGetType (split_acc) == ACCT_TYPE_TRADING))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (info->simple_layout)
|
|
||||||
{
|
|
||||||
// Write line in simple layout, equivalent to a single line register view
|
|
||||||
gchar *line = make_simple_trans_line (trans, split, info);
|
|
||||||
info->failed = !write_line_to_file (fh, line);
|
|
||||||
g_free (line);
|
|
||||||
if (info->failed)
|
|
||||||
break;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write complex Transaction Line.
|
|
||||||
gchar *line = make_complex_trans_line (trans, split, info);
|
|
||||||
info->failed = !write_line_to_file (fh, line);
|
|
||||||
g_free (line);
|
|
||||||
if (info->failed)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Loop through the list of splits for the Transaction */
|
|
||||||
for (GList *node = xaccTransGetSplitList (trans); node; node = node->next)
|
|
||||||
{
|
|
||||||
Split *t_split = node->data;
|
|
||||||
|
|
||||||
// base split is already written on the trans_line
|
|
||||||
if (split == t_split)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Only export trading splits if exporting a trading account
|
|
||||||
Account *tsplit_acc = xaccSplitGetAccount (t_split);
|
|
||||||
if (!is_trading_acct &&
|
|
||||||
(xaccAccountGetType (tsplit_acc) == ACCT_TYPE_TRADING))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Write complex Split Line.
|
|
||||||
line = make_complex_trans_line (trans, t_split, info);
|
|
||||||
info->failed = !write_line_to_file (fh, line);
|
|
||||||
g_free (line);
|
|
||||||
if (info->failed)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
trans_list = g_list_prepend (trans_list, trans);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->export_type == XML_EXPORT_TRANS)
|
|
||||||
qof_query_destroy (info->query);
|
|
||||||
g_list_free (trans_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************
|
|
||||||
* csv_transactions_export
|
|
||||||
*
|
|
||||||
* write a list of transactions to a text file
|
|
||||||
*******************************************************/
|
|
||||||
void csv_transactions_export (CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
ENTER("");
|
|
||||||
DEBUG("File name is : %s", info->file_name);
|
|
||||||
|
|
||||||
info->failed = false;
|
|
||||||
|
|
||||||
/* Set up separators */
|
|
||||||
if (info->use_quotes)
|
|
||||||
{
|
|
||||||
info->end_sep = "\"";
|
|
||||||
info->mid_sep = g_strconcat ("\"", info->separator_str, "\"", NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
info->end_sep = "";
|
|
||||||
info->mid_sep = g_strconcat (info->separator_str, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open File for writing */
|
|
||||||
FILE *fh = g_fopen (info->file_name, "w" );
|
|
||||||
if (!fh)
|
|
||||||
{
|
|
||||||
info->failed = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gchar *header;
|
|
||||||
bool num_action = qof_book_use_split_action_for_num_field (gnc_get_current_book());
|
|
||||||
/* Header string */
|
|
||||||
if (info->simple_layout)
|
|
||||||
{
|
|
||||||
header = g_strconcat (info->end_sep,
|
|
||||||
/* Translators: The following symbols will build the *
|
|
||||||
* header line of exported CSV files: */
|
|
||||||
_("Date"), info->mid_sep, _("Account Name"),
|
|
||||||
info->mid_sep, (num_action ? _("Transaction Number") : _("Number")),
|
|
||||||
info->mid_sep, _("Description"), info->mid_sep, _("Full Category Path"),
|
|
||||||
info->mid_sep, _("Reconcile"),
|
|
||||||
info->mid_sep, _("Amount With Sym"), info->mid_sep, _("Amount Num."),
|
|
||||||
info->mid_sep, _("Value With Sym"), info->mid_sep, _("Value Num."),
|
|
||||||
info->mid_sep, _("Rate/Price"),
|
|
||||||
info->end_sep, EOLSTR, NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
header = g_strconcat (info->end_sep, _("Date"), info->mid_sep, _("Transaction ID"),
|
|
||||||
info->mid_sep, (num_action ? _("Transaction Number") : _("Number")),
|
|
||||||
info->mid_sep, _("Description"), info->mid_sep, _("Notes"),
|
|
||||||
info->mid_sep, _("Commodity/Currency"), info->mid_sep, _("Void Reason"),
|
|
||||||
info->mid_sep, (num_action ? _("Number/Action") : _("Action")), info->mid_sep, _("Memo"),
|
|
||||||
info->mid_sep, _("Full Account Name"), info->mid_sep, _("Account Name"),
|
|
||||||
info->mid_sep, _("Amount With Sym"), info->mid_sep, _("Amount Num."),
|
|
||||||
info->mid_sep, _("Value With Sym"), info->mid_sep, _("Value Num."),
|
|
||||||
info->mid_sep, _("Reconcile"), info->mid_sep, _("Reconcile Date"), info->mid_sep, _("Rate/Price"),
|
|
||||||
info->end_sep, EOLSTR, NULL);
|
|
||||||
}
|
|
||||||
DEBUG("Header String: %s", header);
|
|
||||||
|
|
||||||
/* Write header line */
|
|
||||||
info->failed = !write_line_to_file (fh, header);
|
|
||||||
g_free (header);
|
|
||||||
if (info->failed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Go through list of accounts */
|
|
||||||
for (GList *ptr = info->csva.account_list; ptr; ptr = g_list_next(ptr))
|
|
||||||
{
|
|
||||||
Account *acc = ptr->data;
|
|
||||||
DEBUG("Account being processed is : %s", xaccAccountGetName (acc));
|
|
||||||
account_splits (info, acc, fh);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose (fh);
|
|
||||||
LEAVE("");
|
|
||||||
}
|
|
||||||
|
|
431
gnucash/import-export/csv-exp/csv-transactions-export.cpp
Normal file
431
gnucash/import-export/csv-exp/csv-transactions-export.cpp
Normal file
@ -0,0 +1,431 @@
|
|||||||
|
/*******************************************************************\
|
||||||
|
* csv-actions-export.c -- Export Transactions to a file *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2012 Robert Fewell *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License as *
|
||||||
|
* published by the Free Software Foundation; either version 2 of *
|
||||||
|
* the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License*
|
||||||
|
* along with this program; if not, contact: *
|
||||||
|
* *
|
||||||
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||||
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||||
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||||
|
\********************************************************************/
|
||||||
|
/** @file csv-transactions-export.c
|
||||||
|
@brief CSV Export Transactions
|
||||||
|
@author Copyright (c) 2012 Robert Fewell
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#include "gnc-commodity.h"
|
||||||
|
#include "gnc-ui-util.h"
|
||||||
|
#include "Query.h"
|
||||||
|
#include "Transaction.h"
|
||||||
|
#include "engine-helpers.h"
|
||||||
|
#include "qofbookslots.h"
|
||||||
|
#include "guid.hpp"
|
||||||
|
|
||||||
|
#include "csv-transactions-export.h"
|
||||||
|
#include "csv-export-helpers.hpp"
|
||||||
|
|
||||||
|
/* This static indicates the debugging module that this .o belongs to. */
|
||||||
|
static QofLogModule log_module = GNC_MOD_ASSISTANT;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
|
||||||
|
/******************** Helper functions *********************/
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
get_date (Transaction *trans)
|
||||||
|
{
|
||||||
|
char datebuff [MAX_DATE_LENGTH + 1];
|
||||||
|
qof_print_date_buff(datebuff, MAX_DATE_LENGTH, xaccTransGetDate (trans));
|
||||||
|
return datebuff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
get_guid (Transaction *trans)
|
||||||
|
{
|
||||||
|
return gnc::GUID (*qof_entity_get_guid (QOF_INSTANCE (trans))).to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconcile Date
|
||||||
|
static std::string
|
||||||
|
get_reconcile_date (Split *split)
|
||||||
|
{
|
||||||
|
if (xaccSplitGetReconcile (split) != YREC)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
char datebuff[MAX_DATE_LENGTH + 1];
|
||||||
|
qof_print_date_buff (datebuff, MAX_DATE_LENGTH, xaccSplitGetDateReconciled (split));
|
||||||
|
return datebuff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account Name short or Long
|
||||||
|
static std::string
|
||||||
|
get_account_name (Split *split, bool full)
|
||||||
|
{
|
||||||
|
auto account{xaccSplitGetAccount (split)};
|
||||||
|
if (full)
|
||||||
|
{
|
||||||
|
auto name{gnc_account_get_full_name (account)};
|
||||||
|
auto rv{std::string(name)};
|
||||||
|
g_free (name);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return xaccAccountGetName (account);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number
|
||||||
|
static std::string
|
||||||
|
get_number (Transaction *trans)
|
||||||
|
{
|
||||||
|
auto num{xaccTransGetNum (trans)};
|
||||||
|
return (num ? num : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Description
|
||||||
|
static std::string
|
||||||
|
get_description (Transaction *trans)
|
||||||
|
{
|
||||||
|
auto desc{xaccTransGetDescription (trans)};
|
||||||
|
return (desc ? desc : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notes
|
||||||
|
static std::string
|
||||||
|
get_notes (Transaction *trans)
|
||||||
|
{
|
||||||
|
auto notes{xaccTransGetNotes (trans)};
|
||||||
|
return (notes ? notes : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Void reason
|
||||||
|
static std::string
|
||||||
|
get_void_reason (Transaction *trans)
|
||||||
|
{
|
||||||
|
auto void_reason{xaccTransGetVoidReason (trans)};
|
||||||
|
return (void_reason ? void_reason : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memo
|
||||||
|
static std::string
|
||||||
|
get_memo (Split *split)
|
||||||
|
{
|
||||||
|
auto memo{xaccSplitGetMemo (split)};
|
||||||
|
return (memo ? memo : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full Category Path or Not
|
||||||
|
static std::string
|
||||||
|
get_category (Split *split, bool full)
|
||||||
|
{
|
||||||
|
if (full)
|
||||||
|
{
|
||||||
|
auto cat{xaccSplitGetCorrAccountFullName (split)};
|
||||||
|
auto rv{std::string (cat)};
|
||||||
|
g_free (cat);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return xaccSplitGetCorrAccountName (split);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action
|
||||||
|
static std::string
|
||||||
|
get_action (Split *split)
|
||||||
|
{
|
||||||
|
auto action{xaccSplitGetAction (split)};
|
||||||
|
return (action ? action : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconcile
|
||||||
|
static std::string
|
||||||
|
get_reconcile (Split *split)
|
||||||
|
{
|
||||||
|
auto recon{gnc_get_reconcile_str (xaccSplitGetReconcile (split))};
|
||||||
|
return (recon ? recon : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transaction commodity
|
||||||
|
static std::string
|
||||||
|
get_commodity (Transaction *trans)
|
||||||
|
{
|
||||||
|
return gnc_commodity_get_unique_name (xaccTransGetCurrency (trans));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Amount with Symbol or not
|
||||||
|
static std::string
|
||||||
|
get_amount (Split *split, bool t_void, bool symbol)
|
||||||
|
{
|
||||||
|
auto amt_num{t_void ? xaccSplitVoidFormerAmount (split) : xaccSplitGetAmount (split)};
|
||||||
|
return xaccPrintAmount (amt_num, gnc_split_amount_print_info (split, symbol));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value with Symbol or not
|
||||||
|
static std::string
|
||||||
|
get_value (Split *split, bool t_void, bool symbol)
|
||||||
|
{
|
||||||
|
auto trans{xaccSplitGetParent(split)};
|
||||||
|
auto tcurr{xaccTransGetCurrency (trans)};
|
||||||
|
auto pai{gnc_commodity_print_info (tcurr, symbol)};
|
||||||
|
auto amt_num{t_void ? xaccSplitVoidFormerValue (split): xaccSplitGetValue (split)};
|
||||||
|
return xaccPrintAmount (amt_num, pai);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Share Price / Conversion factor
|
||||||
|
static std::string
|
||||||
|
get_rate (Split *split, bool t_void)
|
||||||
|
{
|
||||||
|
auto curr{xaccAccountGetCommodity (xaccSplitGetAccount (split))};
|
||||||
|
auto amt_num{t_void ? gnc_numeric_zero() : xaccSplitGetSharePrice (split)};
|
||||||
|
return xaccPrintAmount (amt_num, gnc_default_price_print_info (curr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Share Price / Conversion factor
|
||||||
|
static std::string
|
||||||
|
get_price (Split *split, bool t_void)
|
||||||
|
{
|
||||||
|
auto curr{xaccAccountGetCommodity (xaccSplitGetAccount (split))};
|
||||||
|
auto cf{t_void
|
||||||
|
? gnc_numeric_div (xaccSplitVoidFormerValue (split),
|
||||||
|
xaccSplitVoidFormerAmount (split),
|
||||||
|
GNC_DENOM_AUTO,
|
||||||
|
GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND_HALF_UP)
|
||||||
|
: xaccSplitGetSharePrice (split)};
|
||||||
|
return xaccPrintAmount (cf, gnc_default_price_print_info (curr));
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
static StringVec
|
||||||
|
make_simple_trans_line (Transaction *trans, Split *split)
|
||||||
|
{
|
||||||
|
auto t_void{xaccTransGetVoidStatus (trans)};
|
||||||
|
return {
|
||||||
|
get_date (trans),
|
||||||
|
get_account_name (split, true),
|
||||||
|
get_number (trans),
|
||||||
|
get_description (trans),
|
||||||
|
get_category (split, true),
|
||||||
|
get_reconcile (split),
|
||||||
|
get_amount (split, t_void, true),
|
||||||
|
get_amount (split, t_void, false),
|
||||||
|
get_value (split, t_void, true),
|
||||||
|
get_value (split, t_void, false),
|
||||||
|
get_rate (split, t_void)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringVec
|
||||||
|
make_complex_trans_line (Transaction *trans, Split *split)
|
||||||
|
{
|
||||||
|
auto t_void{xaccTransGetVoidStatus (trans)};
|
||||||
|
return {
|
||||||
|
get_date (trans),
|
||||||
|
get_guid (trans),
|
||||||
|
get_number (trans),
|
||||||
|
get_description (trans),
|
||||||
|
get_notes (trans),
|
||||||
|
get_commodity (trans),
|
||||||
|
get_void_reason (trans),
|
||||||
|
get_action (split),
|
||||||
|
get_memo (split),
|
||||||
|
get_account_name (split, true),
|
||||||
|
get_account_name (split, false),
|
||||||
|
get_amount (split, t_void, true),
|
||||||
|
get_amount (split, t_void, false),
|
||||||
|
get_value (split, t_void, true),
|
||||||
|
get_value (split, t_void, false),
|
||||||
|
get_reconcile (split),
|
||||||
|
get_reconcile_date (split),
|
||||||
|
get_price (split, t_void)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
using TransSet = std::unordered_set<Transaction*>;
|
||||||
|
|
||||||
|
/*******************************************************
|
||||||
|
* account_splits
|
||||||
|
*
|
||||||
|
* gather the splits / transactions for an account and
|
||||||
|
* send them to a file
|
||||||
|
*******************************************************/
|
||||||
|
static
|
||||||
|
void account_splits (CsvExportInfo *info, Account *acc, std::ofstream& ss,
|
||||||
|
TransSet& trans_set)
|
||||||
|
{
|
||||||
|
bool is_trading_acct = acc && (xaccAccountGetType (acc) == ACCT_TYPE_TRADING);
|
||||||
|
|
||||||
|
// Setup the query for normal transaction export
|
||||||
|
if (info->export_type == XML_EXPORT_TRANS)
|
||||||
|
{
|
||||||
|
info->query = qof_query_create_for (GNC_ID_SPLIT);
|
||||||
|
QofBook *book = gnc_get_current_book();
|
||||||
|
qof_query_set_book (info->query, book);
|
||||||
|
|
||||||
|
/* Sort by transaction date */
|
||||||
|
GSList *p1 = g_slist_prepend (NULL, (gpointer)TRANS_DATE_POSTED);
|
||||||
|
p1 = g_slist_prepend (p1, (gpointer)SPLIT_TRANS);
|
||||||
|
GSList *p2 = g_slist_prepend (NULL, (gpointer)QUERY_DEFAULT_SORT);
|
||||||
|
qof_query_set_sort_order (info->query, p1, p2, NULL);
|
||||||
|
|
||||||
|
xaccQueryAddSingleAccountMatch (info->query, acc, QOF_QUERY_AND);
|
||||||
|
xaccQueryAddDateMatchTT (info->query, true, info->csvd.start_time, true, info->csvd.end_time, QOF_QUERY_AND);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run the query */
|
||||||
|
for (GList *splits = qof_query_run (info->query); !info->failed && splits;
|
||||||
|
splits = splits->next)
|
||||||
|
{
|
||||||
|
auto split{static_cast<Split*>(splits->data)};
|
||||||
|
auto trans{xaccSplitGetParent (split)};
|
||||||
|
|
||||||
|
// Look for trans already exported in trans_set
|
||||||
|
if (!trans_set.emplace (trans).second)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Look for blank split
|
||||||
|
Account *split_acc = xaccSplitGetAccount (split);
|
||||||
|
if (!split_acc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Only export trading splits when exporting a trading account
|
||||||
|
if (!is_trading_acct &&
|
||||||
|
(xaccAccountGetType (split_acc) == ACCT_TYPE_TRADING))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (info->simple_layout)
|
||||||
|
{
|
||||||
|
// Write line in simple layout, equivalent to a single line register view
|
||||||
|
auto line = make_simple_trans_line (trans, split);
|
||||||
|
info->failed = !gnc_csv_add_line (ss, line, info->use_quotes,
|
||||||
|
info->separator_str);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write complex Transaction Line.
|
||||||
|
auto line = make_complex_trans_line (trans, split);
|
||||||
|
info->failed = !gnc_csv_add_line (ss, line, info->use_quotes,
|
||||||
|
info->separator_str);
|
||||||
|
|
||||||
|
/* Loop through the list of splits for the Transaction */
|
||||||
|
for (auto node = xaccTransGetSplitList (trans); !info->failed && node;
|
||||||
|
node = node->next)
|
||||||
|
{
|
||||||
|
auto t_split{static_cast<Split*>(node->data)};
|
||||||
|
|
||||||
|
// base split is already written on the trans_line
|
||||||
|
if (split == t_split)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Only export trading splits if exporting a trading account
|
||||||
|
Account *tsplit_acc = xaccSplitGetAccount (t_split);
|
||||||
|
if (!is_trading_acct &&
|
||||||
|
(xaccAccountGetType (tsplit_acc) == ACCT_TYPE_TRADING))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Write complex Split Line.
|
||||||
|
auto line = make_complex_trans_line (trans, t_split);
|
||||||
|
info->failed = !gnc_csv_add_line (ss, line, info->use_quotes,
|
||||||
|
info->separator_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->export_type == XML_EXPORT_TRANS)
|
||||||
|
qof_query_destroy (info->query);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************
|
||||||
|
* csv_transactions_export
|
||||||
|
*
|
||||||
|
* write a list of transactions to a text file
|
||||||
|
*******************************************************/
|
||||||
|
void csv_transactions_export (CsvExportInfo *info)
|
||||||
|
{
|
||||||
|
ENTER("");
|
||||||
|
DEBUG("File name is : %s", info->file_name);
|
||||||
|
|
||||||
|
/* Open File for writing */
|
||||||
|
auto ss{std::ofstream (info->file_name, std::ofstream::out)};
|
||||||
|
|
||||||
|
StringVec headers;
|
||||||
|
bool num_action = qof_book_use_split_action_for_num_field (gnc_get_current_book());
|
||||||
|
|
||||||
|
/* Header string */
|
||||||
|
if (info->simple_layout)
|
||||||
|
{
|
||||||
|
/* Translators: The following symbols will build the header
|
||||||
|
line of exported CSV files: */
|
||||||
|
headers = {
|
||||||
|
_("Date"),
|
||||||
|
_("Account Name"),
|
||||||
|
(num_action ? _("Transaction Number") : _("Number")),
|
||||||
|
_("Description"),
|
||||||
|
_("Full Category Path"),
|
||||||
|
_("Reconcile"),
|
||||||
|
_("Amount With Sym"),
|
||||||
|
_("Amount Num."),
|
||||||
|
_("Value With Sym"),
|
||||||
|
_("Value Num."),
|
||||||
|
_("Rate/Price"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
headers = {
|
||||||
|
_("Date"),
|
||||||
|
_("Transaction ID"),
|
||||||
|
(num_action ? _("Transaction Number") : _("Number")),
|
||||||
|
_("Description"),
|
||||||
|
_("Notes"),
|
||||||
|
_("Commodity/Currency"),
|
||||||
|
_("Void Reason"),
|
||||||
|
(num_action ? _("Number/Action") : _("Action")),
|
||||||
|
_("Memo"),
|
||||||
|
_("Full Account Name"),
|
||||||
|
_("Account Name"),
|
||||||
|
_("Amount With Sym"),
|
||||||
|
_("Amount Num."),
|
||||||
|
_("Value With Sym"),
|
||||||
|
_("Value Num."),
|
||||||
|
_("Reconcile"),
|
||||||
|
_("Reconcile Date"),
|
||||||
|
_("Rate/Price"),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Write header line */
|
||||||
|
info->failed = !gnc_csv_add_line (ss, headers, info->use_quotes, info->separator_str);
|
||||||
|
|
||||||
|
/* Go through list of accounts */
|
||||||
|
TransSet trans_set;
|
||||||
|
for (auto ptr = info->csva.account_list; !info->failed && ptr;
|
||||||
|
ptr = g_list_next(ptr))
|
||||||
|
{
|
||||||
|
auto acc{static_cast<Account*>(ptr->data)};
|
||||||
|
DEBUG("Account being processed is : %s", xaccAccountGetName (acc));
|
||||||
|
account_splits (info, acc, ss, trans_set);
|
||||||
|
info->failed = ss.fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
LEAVE("");
|
||||||
|
}
|
||||||
|
|
@ -30,10 +30,18 @@
|
|||||||
|
|
||||||
#include "assistant-csv-export.h"
|
#include "assistant-csv-export.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/** The csv_transactions_export() will let the user export the
|
/** The csv_transactions_export() will let the user export the
|
||||||
* transactions to a delimited file.
|
* transactions to a delimited file.
|
||||||
*/
|
*/
|
||||||
void csv_transactions_export (CsvExportInfo *info);
|
void csv_transactions_export (CsvExportInfo *info);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,265 +0,0 @@
|
|||||||
/*******************************************************************\
|
|
||||||
* csv-tree-export.c -- Export Account Tree to a file *
|
|
||||||
* *
|
|
||||||
* Copyright (C) 2012 Robert Fewell *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or *
|
|
||||||
* modify it under the terms of the GNU General Public License as *
|
|
||||||
* published by the Free Software Foundation; either version 2 of *
|
|
||||||
* the License, or (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License*
|
|
||||||
* along with this program; if not, contact: *
|
|
||||||
* *
|
|
||||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
|
||||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
|
||||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
|
||||||
\********************************************************************/
|
|
||||||
/** @file csv-tree-export.c
|
|
||||||
@brief CSV Export Account Tree
|
|
||||||
@author Copyright (c) 2012 Robert Fewell
|
|
||||||
*/
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
#include <glib/gi18n.h>
|
|
||||||
#include <glib/gstdio.h>
|
|
||||||
|
|
||||||
#include "gnc-commodity.h"
|
|
||||||
#include "gnc-ui-util.h"
|
|
||||||
|
|
||||||
#include "csv-tree-export.h"
|
|
||||||
|
|
||||||
/* This static indicates the debugging module that this .o belongs to. */
|
|
||||||
static QofLogModule log_module = GNC_MOD_ASSISTANT;
|
|
||||||
|
|
||||||
/* CSV spec requires CRLF line endings. Tweak the end-of-line string so this
|
|
||||||
* true for each platform */
|
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
# define EOLSTR "\n"
|
|
||||||
#else
|
|
||||||
# define EOLSTR "\r\n"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/******************************************************************/
|
|
||||||
|
|
||||||
/*******************************************************
|
|
||||||
* write_line_to_file
|
|
||||||
*
|
|
||||||
* write a text string to a file pointer, return TRUE if
|
|
||||||
* successful.
|
|
||||||
*******************************************************/
|
|
||||||
static
|
|
||||||
gboolean write_line_to_file (FILE *fh, char * line)
|
|
||||||
{
|
|
||||||
int len, written;
|
|
||||||
DEBUG("Account String: %s", line);
|
|
||||||
|
|
||||||
/* Write account line */
|
|
||||||
len = strlen (line);
|
|
||||||
written = fwrite (line, 1, len, fh);
|
|
||||||
|
|
||||||
if (written != len)
|
|
||||||
return FALSE;
|
|
||||||
else
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************
|
|
||||||
* csv_test_field_string
|
|
||||||
*
|
|
||||||
* Test the field string for ," and new lines
|
|
||||||
*******************************************************/
|
|
||||||
static
|
|
||||||
gchar *csv_test_field_string (CsvExportInfo *info, const gchar *string_in)
|
|
||||||
{
|
|
||||||
gboolean need_quote = FALSE;
|
|
||||||
gchar **parts;
|
|
||||||
gchar *string_parts;
|
|
||||||
gchar *string_out;
|
|
||||||
|
|
||||||
/* Check for " and then "" them */
|
|
||||||
parts = g_strsplit (string_in, "\"", -1);
|
|
||||||
string_parts = g_strjoinv ("\"\"", parts);
|
|
||||||
g_strfreev (parts);
|
|
||||||
|
|
||||||
/* Check for separator string and \n and " in field,
|
|
||||||
if so quote field if not already quoted */
|
|
||||||
if (g_strrstr (string_parts, info->separator_str) != NULL)
|
|
||||||
need_quote = TRUE;
|
|
||||||
if (g_strrstr (string_parts, "\n") != NULL)
|
|
||||||
need_quote = TRUE;
|
|
||||||
if (g_strrstr (string_parts, "\"") != NULL)
|
|
||||||
need_quote = TRUE;
|
|
||||||
|
|
||||||
if (!info->use_quotes && need_quote)
|
|
||||||
string_out = g_strconcat ("\"", string_parts, "\"", NULL);
|
|
||||||
else
|
|
||||||
string_out = g_strdup (string_parts);
|
|
||||||
|
|
||||||
g_free (string_parts);
|
|
||||||
return string_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************
|
|
||||||
* csv_tree_export
|
|
||||||
*
|
|
||||||
* write a list of accounts settings to a text file
|
|
||||||
*******************************************************/
|
|
||||||
void csv_tree_export (CsvExportInfo *info)
|
|
||||||
{
|
|
||||||
FILE *fh;
|
|
||||||
Account *root;
|
|
||||||
Account *acc;
|
|
||||||
GList *accts, *ptr;
|
|
||||||
|
|
||||||
ENTER("");
|
|
||||||
DEBUG("File name is : %s", info->file_name);
|
|
||||||
|
|
||||||
/* Get list of Accounts */
|
|
||||||
root = gnc_book_get_root_account (gnc_get_current_book());
|
|
||||||
accts = gnc_account_get_descendants_sorted (root);
|
|
||||||
info->failed = FALSE;
|
|
||||||
|
|
||||||
/* Open File for writing */
|
|
||||||
fh = g_fopen (info->file_name, "w");
|
|
||||||
if (fh != NULL)
|
|
||||||
{
|
|
||||||
gchar *header;
|
|
||||||
gchar *part1;
|
|
||||||
gchar *part2;
|
|
||||||
const gchar *currentSel;
|
|
||||||
gchar *end_sep;
|
|
||||||
gchar *mid_sep;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
|
|
||||||
/* Set up separators */
|
|
||||||
if (info->use_quotes)
|
|
||||||
{
|
|
||||||
end_sep = "\"";
|
|
||||||
mid_sep = g_strconcat ("\"", info->separator_str, "\"", NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
end_sep = "";
|
|
||||||
mid_sep = g_strconcat (info->separator_str, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Header string, 'eol = end of line marker' */
|
|
||||||
header = g_strconcat (end_sep, _("Type"), mid_sep, _("Full Account Name"), mid_sep, _("Account Name"), mid_sep,
|
|
||||||
_("Account Code"), mid_sep, _("Description"), mid_sep, _("Account Color"), mid_sep,
|
|
||||||
_("Notes"), mid_sep, _("Symbol"), mid_sep, _("Namespace"), mid_sep,
|
|
||||||
_("Hidden"), mid_sep, _("Tax Info"), mid_sep, _("Placeholder"), end_sep, EOLSTR, NULL);
|
|
||||||
DEBUG("Header String: %s", header);
|
|
||||||
|
|
||||||
/* Write header line */
|
|
||||||
if (!write_line_to_file (fh, header))
|
|
||||||
{
|
|
||||||
info->failed = TRUE;
|
|
||||||
g_free (mid_sep);
|
|
||||||
g_free (header);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
g_free (header);
|
|
||||||
|
|
||||||
/* Go through list of accounts */
|
|
||||||
for (ptr = accts, i = 0; ptr; ptr = g_list_next (ptr), i++)
|
|
||||||
{
|
|
||||||
gchar *fullname = NULL;
|
|
||||||
gchar *str_temp = NULL;
|
|
||||||
acc = ptr->data;
|
|
||||||
DEBUG("Account being processed is : %s", xaccAccountGetName (acc));
|
|
||||||
/* Type */
|
|
||||||
currentSel = xaccAccountTypeEnumAsString (xaccAccountGetType (acc));
|
|
||||||
part1 = g_strconcat (end_sep, currentSel, mid_sep, NULL);
|
|
||||||
/* Full Name */
|
|
||||||
fullname = gnc_account_get_full_name (acc);
|
|
||||||
str_temp = csv_test_field_string (info, fullname);
|
|
||||||
part2 = g_strconcat (part1, str_temp, mid_sep, NULL);
|
|
||||||
g_free (str_temp);
|
|
||||||
g_free (fullname);
|
|
||||||
g_free (part1);
|
|
||||||
/* Name */
|
|
||||||
currentSel = xaccAccountGetName (acc);
|
|
||||||
str_temp = csv_test_field_string (info, currentSel);
|
|
||||||
part1 = g_strconcat (part2, str_temp, mid_sep, NULL);
|
|
||||||
g_free (str_temp);
|
|
||||||
g_free (part2);
|
|
||||||
/* Code */
|
|
||||||
currentSel = xaccAccountGetCode (acc) ? xaccAccountGetCode (acc) : "";
|
|
||||||
str_temp = csv_test_field_string (info, currentSel);
|
|
||||||
part2 = g_strconcat (part1, str_temp, mid_sep, NULL);
|
|
||||||
g_free (str_temp);
|
|
||||||
g_free (part1);
|
|
||||||
/* Description */
|
|
||||||
currentSel = xaccAccountGetDescription (acc) ? xaccAccountGetDescription (acc) : "";
|
|
||||||
str_temp = csv_test_field_string (info, currentSel);
|
|
||||||
part1 = g_strconcat (part2, str_temp, mid_sep, NULL);
|
|
||||||
g_free (str_temp);
|
|
||||||
g_free (part2);
|
|
||||||
/* Color */
|
|
||||||
currentSel = xaccAccountGetColor (acc) ? xaccAccountGetColor (acc) : "" ;
|
|
||||||
str_temp = csv_test_field_string (info, currentSel);
|
|
||||||
part2 = g_strconcat (part1, str_temp, mid_sep, NULL);
|
|
||||||
g_free (str_temp);
|
|
||||||
g_free (part1);
|
|
||||||
/* Notes */
|
|
||||||
currentSel = xaccAccountGetNotes (acc) ? xaccAccountGetNotes (acc) : "" ;
|
|
||||||
str_temp = csv_test_field_string (info, currentSel);
|
|
||||||
part1 = g_strconcat (part2, str_temp, mid_sep, NULL);
|
|
||||||
g_free (str_temp);
|
|
||||||
g_free (part2);
|
|
||||||
/* Commodity Symbol */
|
|
||||||
currentSel = gnc_commodity_get_mnemonic (xaccAccountGetCommodity (acc));
|
|
||||||
str_temp = csv_test_field_string (info, currentSel);
|
|
||||||
part2 = g_strconcat (part1, str_temp, mid_sep, NULL);
|
|
||||||
g_free (str_temp);
|
|
||||||
g_free (part1);
|
|
||||||
/* Commodity Namespace */
|
|
||||||
currentSel = gnc_commodity_get_namespace (xaccAccountGetCommodity (acc));
|
|
||||||
str_temp = csv_test_field_string (info, currentSel);
|
|
||||||
part1 = g_strconcat (part2, str_temp, mid_sep, NULL);
|
|
||||||
g_free (str_temp);
|
|
||||||
g_free (part2);
|
|
||||||
/* Hidden */
|
|
||||||
currentSel = xaccAccountGetHidden (acc) ? "T" : "F" ;
|
|
||||||
part2 = g_strconcat (part1, currentSel, mid_sep, NULL);
|
|
||||||
g_free (part1);
|
|
||||||
/* Tax */
|
|
||||||
currentSel = xaccAccountGetTaxRelated (acc) ? "T" : "F" ;
|
|
||||||
part1 = g_strconcat (part2, currentSel, mid_sep, NULL);
|
|
||||||
g_free (part2);
|
|
||||||
/* Place Holder / end of line marker */
|
|
||||||
currentSel = xaccAccountGetPlaceholder (acc) ? "T" : "F" ;
|
|
||||||
part2 = g_strconcat (part1, currentSel, end_sep, EOLSTR, NULL);
|
|
||||||
g_free (part1);
|
|
||||||
|
|
||||||
DEBUG("Account String: %s", part2);
|
|
||||||
|
|
||||||
/* Write to file */
|
|
||||||
if (!write_line_to_file (fh, part2))
|
|
||||||
{
|
|
||||||
info->failed = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
g_free (part2);
|
|
||||||
}
|
|
||||||
g_free (mid_sep);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
info->failed = TRUE;
|
|
||||||
if (fh)
|
|
||||||
fclose (fh);
|
|
||||||
|
|
||||||
g_list_free (accts);
|
|
||||||
LEAVE("");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
112
gnucash/import-export/csv-exp/csv-tree-export.cpp
Normal file
112
gnucash/import-export/csv-exp/csv-tree-export.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*******************************************************************\
|
||||||
|
* csv-tree-export.cpp -- Export Account Tree to a file *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2012 Robert Fewell *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License as *
|
||||||
|
* published by the Free Software Foundation; either version 2 of *
|
||||||
|
* the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License*
|
||||||
|
* along with this program; if not, contact: *
|
||||||
|
* *
|
||||||
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||||
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||||
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||||
|
\********************************************************************/
|
||||||
|
/** @file csv-tree-export.c
|
||||||
|
@brief CSV Export Account Tree
|
||||||
|
@author Copyright (c) 2012 Robert Fewell
|
||||||
|
*/
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "gnc-commodity.h"
|
||||||
|
#include "gnc-ui-util.h"
|
||||||
|
#include "csv-tree-export.h"
|
||||||
|
#include "csv-export-helpers.hpp"
|
||||||
|
|
||||||
|
/* This static indicates the debugging module that this .o belongs to. */
|
||||||
|
static QofLogModule log_module = GNC_MOD_ASSISTANT;
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
account_get_fullname_str (Account *account)
|
||||||
|
{
|
||||||
|
auto name{gnc_account_get_full_name (account)};
|
||||||
|
auto rv{std::string(name)};
|
||||||
|
g_free (name);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************
|
||||||
|
* csv_tree_export
|
||||||
|
*
|
||||||
|
* write a list of accounts settings to a text file
|
||||||
|
*******************************************************/
|
||||||
|
void
|
||||||
|
csv_tree_export (CsvExportInfo *info)
|
||||||
|
{
|
||||||
|
ENTER("");
|
||||||
|
DEBUG("File name is : %s", info->file_name);
|
||||||
|
|
||||||
|
/* Open File for writing */
|
||||||
|
auto ss{std::ofstream (info->file_name, std::ofstream::out)};
|
||||||
|
|
||||||
|
/* Header string */
|
||||||
|
StringVec headervec = {
|
||||||
|
_("Type"), _("Full Account Name"), _("Account Name"),
|
||||||
|
_("Account Code"), _("Description"), _("Account Color"),
|
||||||
|
_("Notes"), _("Symbol"), _("Namespace"),
|
||||||
|
_("Hidden"), _("Tax Info"), _("Placeholder")
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Write header line */
|
||||||
|
info->failed = ss.fail() ||
|
||||||
|
!gnc_csv_add_line (ss, headervec, info->use_quotes, info->separator_str);
|
||||||
|
|
||||||
|
/* Get list of Accounts */
|
||||||
|
auto root{gnc_book_get_root_account (gnc_get_current_book())};
|
||||||
|
auto accts{gnc_account_get_descendants_sorted (root)};
|
||||||
|
auto str_or_empty = [](const char* a){ return a ? a : ""; };
|
||||||
|
auto bool_to_char = [](bool b){ return b ? "T" : "F"; };
|
||||||
|
|
||||||
|
/* Go through list of accounts */
|
||||||
|
for (GList *ptr = accts; !info->failed && ptr; ptr = g_list_next (ptr))
|
||||||
|
{
|
||||||
|
auto acc{static_cast<Account*>(ptr->data)};
|
||||||
|
DEBUG("Account being processed is : %s", xaccAccountGetName (acc));
|
||||||
|
|
||||||
|
StringVec line = {
|
||||||
|
xaccAccountTypeEnumAsString (xaccAccountGetType (acc)),
|
||||||
|
account_get_fullname_str (acc),
|
||||||
|
xaccAccountGetName (acc),
|
||||||
|
str_or_empty (xaccAccountGetCode (acc)),
|
||||||
|
str_or_empty (xaccAccountGetDescription (acc)),
|
||||||
|
str_or_empty (xaccAccountGetColor (acc)),
|
||||||
|
str_or_empty (xaccAccountGetNotes (acc)),
|
||||||
|
gnc_commodity_get_mnemonic (xaccAccountGetCommodity (acc)),
|
||||||
|
gnc_commodity_get_namespace (xaccAccountGetCommodity (acc)),
|
||||||
|
bool_to_char (xaccAccountGetHidden (acc)),
|
||||||
|
bool_to_char (xaccAccountGetTaxRelated (acc)),
|
||||||
|
bool_to_char (xaccAccountGetPlaceholder (acc)),
|
||||||
|
};
|
||||||
|
info->failed = !gnc_csv_add_line (ss, line, info->use_quotes, info->separator_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (accts);
|
||||||
|
LEAVE("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -29,10 +29,18 @@
|
|||||||
|
|
||||||
#include "assistant-csv-export.h"
|
#include "assistant-csv-export.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/** The csv_tree_export() will let the user export the
|
/** The csv_tree_export() will let the user export the
|
||||||
* account tree to a delimited file.
|
* account tree to a delimited file.
|
||||||
*/
|
*/
|
||||||
void csv_tree_export (CsvExportInfo *info);
|
void csv_tree_export (CsvExportInfo *info);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
25
gnucash/import-export/csv-exp/test/CMakeLists.txt
Normal file
25
gnucash/import-export/csv-exp/test/CMakeLists.txt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
set (test-csv-export-helpers_SOURCES
|
||||||
|
test-csv-export-helpers.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set (test-csv-export-helpers_INCLUDE_DIRS
|
||||||
|
${CMAKE_BINARY_DIR}/common
|
||||||
|
${CMAKE_SOURCE_DIR}/libgnucash/engine
|
||||||
|
)
|
||||||
|
|
||||||
|
set (test-csv-export-helpers_LIBS
|
||||||
|
gnc-csv-export
|
||||||
|
gtest
|
||||||
|
)
|
||||||
|
|
||||||
|
gnc_add_test (test-csv-export-helpers
|
||||||
|
"${test-csv-export-helpers_SOURCES}"
|
||||||
|
test-csv-export-helpers_INCLUDE_DIRS
|
||||||
|
test-csv-export-helpers_LIBS
|
||||||
|
)
|
||||||
|
|
||||||
|
set_dist_list (test-csv-export_DIST
|
||||||
|
CMakeLists.txt
|
||||||
|
${test-csv-export-helpers_SOURCES}
|
||||||
|
)
|
@ -0,0 +1,92 @@
|
|||||||
|
/********************************************************************
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License as *
|
||||||
|
* published by the Free Software Foundation; either version 2 of *
|
||||||
|
* the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License*
|
||||||
|
* along with this program; if not, you can retrieve it from *
|
||||||
|
* https://www.gnu.org/licenses/old-licenses/gpl-2.0.html *
|
||||||
|
* or contact: *
|
||||||
|
* *
|
||||||
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||||
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||||
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
// #include "config.h"
|
||||||
|
#include "csv-export-helpers.hpp"
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
# define EOLSTR "\n"
|
||||||
|
#else
|
||||||
|
# define EOLSTR "\r\n"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST (CsvHelperTest, EmptyTests)
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
gnc_csv_add_line (ss, {}, false, nullptr);
|
||||||
|
ASSERT_EQ (ss.str(), EOLSTR);
|
||||||
|
|
||||||
|
std::ostringstream().swap(ss);
|
||||||
|
gnc_csv_add_line (ss, {}, true, ",");
|
||||||
|
ASSERT_EQ (ss.str(), EOLSTR);
|
||||||
|
|
||||||
|
std::ostringstream().swap(ss);
|
||||||
|
gnc_csv_add_line (ss, {}, false, ",");
|
||||||
|
ASSERT_EQ (ss.str(), EOLSTR);
|
||||||
|
|
||||||
|
std::ostringstream().swap(ss);
|
||||||
|
gnc_csv_add_line (ss, {}, true, nullptr);
|
||||||
|
ASSERT_EQ (ss.str(), EOLSTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST (CsvHelperTest, BasicTests)
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
gnc_csv_add_line (ss, { "A","B","C","","D" }, false, ",");
|
||||||
|
ASSERT_EQ (ss.str(), "A,B,C,,D" EOLSTR);
|
||||||
|
|
||||||
|
std::ostringstream().swap(ss);
|
||||||
|
gnc_csv_add_line (ss, { "A","B","C","","D" }, false, "");
|
||||||
|
ASSERT_EQ (ss.str(), "ABCD" EOLSTR);
|
||||||
|
|
||||||
|
std::ostringstream().swap(ss);
|
||||||
|
gnc_csv_add_line (ss, { "A","B","C","","D" }, false, nullptr);
|
||||||
|
ASSERT_EQ (ss.str(), "ABCD" EOLSTR);
|
||||||
|
|
||||||
|
std::ostringstream().swap(ss);
|
||||||
|
gnc_csv_add_line (ss, { "A","B","C","","D" }, false, ";");
|
||||||
|
ASSERT_EQ (ss.str(), "A;B;C;;D" EOLSTR);
|
||||||
|
|
||||||
|
std::ostringstream().swap(ss);
|
||||||
|
gnc_csv_add_line (ss, { "A","B","C","","D" }, true, ",");
|
||||||
|
ASSERT_EQ (ss.str(), "\"A\",\"B\",\"C\",\"\",\"D\"" EOLSTR);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST (CsvHelperTest, ForcedQuote)
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
gnc_csv_add_line (ss, { "A","B","C","\"","D" }, false, ",");
|
||||||
|
ASSERT_EQ (ss.str(), "A,B,C,\"\"\"\",D" EOLSTR);
|
||||||
|
|
||||||
|
std::ostringstream().swap(ss);
|
||||||
|
gnc_csv_add_line (ss, { "A","B","C","",",D" }, false, ",");
|
||||||
|
ASSERT_EQ (ss.str(), "A,B,C,,\",D\"" EOLSTR);
|
||||||
|
|
||||||
|
std::ostringstream().swap(ss);
|
||||||
|
gnc_csv_add_line (ss, { "A","B","C","\n","D\r" }, false, ";");
|
||||||
|
ASSERT_EQ (ss.str(), "A;B;C;\"\n\";\"D\r\"" EOLSTR);
|
||||||
|
|
||||||
|
}
|
@ -326,8 +326,9 @@ gnucash/import-export/bi-import/dialog-bi-import-gui.c
|
|||||||
gnucash/import-export/bi-import/dialog-bi-import-helper.c
|
gnucash/import-export/bi-import/dialog-bi-import-helper.c
|
||||||
gnucash/import-export/bi-import/gnc-plugin-bi-import.c
|
gnucash/import-export/bi-import/gnc-plugin-bi-import.c
|
||||||
gnucash/import-export/csv-exp/assistant-csv-export.c
|
gnucash/import-export/csv-exp/assistant-csv-export.c
|
||||||
gnucash/import-export/csv-exp/csv-transactions-export.c
|
gnucash/import-export/csv-exp/csv-export-helpers.cpp
|
||||||
gnucash/import-export/csv-exp/csv-tree-export.c
|
gnucash/import-export/csv-exp/csv-transactions-export.cpp
|
||||||
|
gnucash/import-export/csv-exp/csv-tree-export.cpp
|
||||||
gnucash/import-export/csv-exp/gnc-plugin-csv-export.c
|
gnucash/import-export/csv-exp/gnc-plugin-csv-export.c
|
||||||
gnucash/import-export/csv-imp/assistant-csv-account-import.c
|
gnucash/import-export/csv-imp/assistant-csv-account-import.c
|
||||||
gnucash/import-export/csv-imp/assistant-csv-price-import.cpp
|
gnucash/import-export/csv-imp/assistant-csv-price-import.cpp
|
||||||
|
Loading…
Reference in New Issue
Block a user