diff --git a/contrib/gdpdu/gdpdu-01-03-2019.dtd b/contrib/gdpdu/gdpdu-01-03-2019.dtd
new file mode 100644
index 00000000000..d9a5992943c
--- /dev/null
+++ b/contrib/gdpdu/gdpdu-01-03-2019.dtd
@@ -0,0 +1,317 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/gdpdu/index.xml b/contrib/gdpdu/index.xml
new file mode 100644
index 00000000000..a174e66f27a
--- /dev/null
+++ b/contrib/gdpdu/index.xml
@@ -0,0 +1,121 @@
+
+
+
+ 1.0
+
+ Hier Firmenname eintragen
+ Hier Ort eintragen
+ Datentraegerüberlassung nach GDPdU vom Hier Datum eintragen
+
+
+ Cloud
+
+ Konten.csv
+ Konten
+ Konten
+
+
+ 20210101
+ 20231231
+
+ YYYYMMDD
+
+
+ ,
+
+ .
+
+ ;
+
+
+
+ Kontonummer
+
+
+
+ Typ
+
+
+
+ Volle Kontobezeichnung
+
+
+
+ Kontobezeichnung
+
+
+
+ Kontonummer
+
+
+
+ Beschreibung
+
+
+
+ Kontofarbe
+
+
+
+ Bemerkung
+
+
+
+ Symbol
+
+
+
+ Namensraum
+
+
+
+ Versteckt
+
+
+
+ Steuerrelevante Information
+
+
+
+ Platzhalter
+
+
+
+
+
+ Buchungen.csv
+ Buchungsstapel
+ Alle Buchungen
+
+ ,
+
+ .
+
+ ;
+
+
+ Datum
+
+ DD.MM.YYYY
+
+
+
+ Beschreibung
+
+
+
+ Wert
+
+
+
+ Sollkonto
+ Konten
+
+
+ Habenkonto
+ Konten
+
+
+
+
+
\ No newline at end of file
diff --git a/gnucash/gtkbuilder/assistant-csv-export.glade b/gnucash/gtkbuilder/assistant-csv-export.glade
index bd405dc0693..8427aa99c8c 100644
--- a/gnucash/gtkbuilder/assistant-csv-export.glade
+++ b/gnucash/gtkbuilder/assistant-csv-export.glade
@@ -90,6 +90,21 @@ Select the type of Export required and the separator that will be used.
0
+
+
+
+ 2
+ 0
+
+
diff --git a/gnucash/import-export/csv-exp/CMakeLists.txt b/gnucash/import-export/csv-exp/CMakeLists.txt
index 5ff28385d79..5dc2eecadd8 100644
--- a/gnucash/import-export/csv-exp/CMakeLists.txt
+++ b/gnucash/import-export/csv-exp/CMakeLists.txt
@@ -7,6 +7,7 @@ set(csv_export_SOURCES
assistant-csv-export.c
csv-tree-export.cpp
csv-transactions-export.cpp
+ csv-transaction-export-line.cpp
)
# Add dependency on config.h
@@ -18,6 +19,7 @@ set(csv_export_noinst_HEADERS
csv-export-helpers.hpp
csv-tree-export.h
csv-transactions-export.h
+ csv-transaction-export-line.hpp
)
add_library(gnc-csv-export ${csv_export_noinst_HEADERS} ${csv_export_SOURCES})
diff --git a/gnucash/import-export/csv-exp/assistant-csv-export.c b/gnucash/import-export/csv-exp/assistant-csv-export.c
index 89fab55db0b..4bacafb5b7c 100644
--- a/gnucash/import-export/csv-exp/assistant-csv-export.c
+++ b/gnucash/import-export/csv-exp/assistant-csv-export.c
@@ -66,6 +66,7 @@ void csv_export_assistant_summary_page_prepare (GtkAssistant *assistant, gpointe
void csv_export_quote_cb (GtkToggleButton *button, gpointer user_data);
void csv_export_simple_cb (GtkToggleButton *button, gpointer user_data);
+void csv_export_gdpdu_cb (GtkToggleButton *button, gpointer user_data);
void csv_export_sep_cb (GtkWidget *radio, gpointer user_data);
void csv_export_custom_entry_cb (GtkWidget *widget, gpointer user_data);
@@ -104,6 +105,7 @@ static const gchar *start_trans_simple_string = N_(
"in a register in 'Basic Ledger' mode. As such some transfer detail "
"could be lost.");
+
static const gchar *finish_tree_string = N_(
/* Translators: %s is the file name. */
"The account tree will be exported to the file '%s' when you click \"Apply\".\n\n"
@@ -272,6 +274,31 @@ csv_export_simple_cb (GtkToggleButton *button, gpointer user_data)
gtk_label_set_text (GTK_LABEL(info->start_label), msg);
g_free (msg);
+
+ gtk_widget_set_sensitive(info->comma_radio, !info->gdpdu_layout);
+ gtk_widget_set_sensitive(info->colon_radio, !info->gdpdu_layout);
+ gtk_widget_set_sensitive(info->semicolon_radio, !info->gdpdu_layout);
+ gtk_widget_set_sensitive(info->custom_radio, !info->gdpdu_layout);
+}
+
+/*******************************************************
+ * csv_export_gdpdu_cb
+ *
+ * call back for use of gdpdu_layout
+ *******************************************************/
+void
+csv_export_gdpdu_cb (GtkToggleButton *button, gpointer user_data)
+{
+ CsvExportInfo *info = user_data;
+
+ info->gdpdu_layout = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(button));
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(info->semicolon_radio), info->gdpdu_layout);
+
+ gtk_widget_set_sensitive(info->comma_radio, !info->gdpdu_layout);
+ gtk_widget_set_sensitive(info->colon_radio, !info->gdpdu_layout);
+ gtk_widget_set_sensitive(info->semicolon_radio, !info->gdpdu_layout);
+ gtk_widget_set_sensitive(info->custom_radio, !info->gdpdu_layout);
}
/*******************************************************
@@ -848,13 +875,12 @@ csv_export_close_handler (gpointer user_data)
static GtkWidget *
csv_export_assistant_create (CsvExportInfo *info)
{
- GtkBuilder *builder;
GtkWidget *button;
GtkWidget *table, *hbox;
- builder = gtk_builder_new();
- gnc_builder_add_from_file (builder , "assistant-csv-export.glade", "csv_export_assistant");
- info->assistant = GTK_WIDGET(gtk_builder_get_object (builder, "csv_export_assistant"));
+ info->builder = gtk_builder_new();
+ gnc_builder_add_from_file (info->builder , "assistant-csv-export.glade", "csv_export_assistant");
+ info->assistant = GTK_WIDGET(gtk_builder_get_object (info->builder, "csv_export_assistant"));
// Set the name for this assistant so it can be easily manipulated with css
gtk_widget_set_name (GTK_WIDGET(info->assistant), "gnc-id-assistant-csv-export");
@@ -864,22 +890,30 @@ csv_export_assistant_create (CsvExportInfo *info)
load_settings (info);
/* Start Page */
- info->start_page = GTK_WIDGET(gtk_builder_get_object(builder, "start_page"));
- info->start_label = GTK_WIDGET(gtk_builder_get_object(builder, "start_label"));
- info->custom_entry = GTK_WIDGET(gtk_builder_get_object(builder, "custom_entry"));
+ info->start_page = GTK_WIDGET(gtk_builder_get_object(info->builder, "start_page"));
+ info->start_label = GTK_WIDGET(gtk_builder_get_object(info->builder, "start_label"));
+ info->custom_entry = GTK_WIDGET(gtk_builder_get_object(info->builder, "custom_entry"));
+ info->simple_layout_check = GTK_WIDGET(gtk_builder_get_object(info->builder, "simple_layout"));
+ info->gdpdu_layout_check = GTK_WIDGET(gtk_builder_get_object(info->builder, "gdpdu_layout"));
+ info->comma_radio = GTK_WIDGET(gtk_builder_get_object(info->builder, "comma_radio"));
+ info->colon_radio = GTK_WIDGET(gtk_builder_get_object(info->builder, "colon_radio"));
+ info->semicolon_radio = GTK_WIDGET(gtk_builder_get_object(info->builder, "semicolon_radio"));
+ info->custom_radio = GTK_WIDGET(gtk_builder_get_object(info->builder, "custom_radio"));
+
gtk_widget_set_sensitive (info->custom_entry, FALSE);
/* Account Page */
- info->account_page = GTK_WIDGET(gtk_builder_get_object(builder, "account_page"));
+ info->account_page = GTK_WIDGET(gtk_builder_get_object(info->builder, "account_page"));
if ((info->export_type == XML_EXPORT_TREE) || (info->export_type == XML_EXPORT_REGISTER))
{
- GtkWidget *chkbox = GTK_WIDGET(gtk_builder_get_object(builder, "simple_layout"));
-
// Don't provide simple export layout for search registers and General Journal
if ((info->export_type == XML_EXPORT_TREE) ||
- (g_list_length (info->csva.account_list) == 0))
- gtk_widget_destroy (chkbox);
+ (g_list_length (info->csva.account_list) == 0)) {
+ gtk_widget_destroy (info->simple_layout_check);
+ gtk_widget_destroy (info->gdpdu_layout_check);
+ }
+
gtk_assistant_remove_page (GTK_ASSISTANT(info->assistant), 1); //remove accounts page
}
else
@@ -888,8 +922,8 @@ csv_export_assistant_create (CsvExportInfo *info)
GtkTreeSelection *selection;
GtkWidget *box, *label;
- info->csva.acct_info = GTK_WIDGET(gtk_builder_get_object (builder, "acct_info_vbox"));
- info->csva.num_acct_label = GTK_WIDGET(gtk_builder_get_object (builder, "num_accounts_label"));
+ info->csva.acct_info = GTK_WIDGET(gtk_builder_get_object (info->builder, "acct_info_vbox"));
+ info->csva.num_acct_label = GTK_WIDGET(gtk_builder_get_object (info->builder, "num_accounts_label"));
tree_view = gnc_tree_view_account_new (FALSE);
info->csva.account_treeview = GTK_WIDGET(tree_view);
@@ -900,19 +934,19 @@ csv_export_assistant_create (CsvExportInfo *info)
G_CALLBACK(csv_export_account_changed_cb), info);
gtk_widget_show (info->csva.account_treeview);
- box = GTK_WIDGET(gtk_builder_get_object (builder, "account_scroll"));
+ box = GTK_WIDGET(gtk_builder_get_object (info->builder, "account_scroll"));
gtk_container_add (GTK_CONTAINER(box), info->csva.account_treeview);
- label = GTK_WIDGET(gtk_builder_get_object (builder, "accounts_label"));
+ label = GTK_WIDGET(gtk_builder_get_object (info->builder, "accounts_label"));
gtk_label_set_mnemonic_widget (GTK_LABEL(label), GTK_WIDGET(tree_view));
/* select subaccounts button */
- button = GTK_WIDGET(gtk_builder_get_object (builder, "select_subaccounts_button"));
+ button = GTK_WIDGET(gtk_builder_get_object (info->builder, "select_subaccounts_button"));
info->csva.select_button = button;
g_signal_connect (G_OBJECT(button), "clicked",
G_CALLBACK(csv_export_select_subaccounts_clicked_cb), info);
- button = GTK_WIDGET(gtk_builder_get_object (builder, "select_all_button"));
+ button = GTK_WIDGET(gtk_builder_get_object (info->builder, "select_all_button"));
info->csva.select_button = button;
g_signal_connect (G_OBJECT(button), "clicked",
G_CALLBACK(csv_export_select_all_clicked_cb), info);
@@ -921,7 +955,7 @@ csv_export_assistant_create (CsvExportInfo *info)
G_CALLBACK(csv_export_cursor_changed_cb), info);
/* Set the date info */
- button = GTK_WIDGET(gtk_builder_get_object (builder, "show_range"));
+ button = GTK_WIDGET(gtk_builder_get_object (info->builder, "show_range"));
/* Get the Earliest and Latest dates in Book */
get_earliest_and_latest_in_book (info, gnc_get_current_book());
@@ -930,19 +964,19 @@ csv_export_assistant_create (CsvExportInfo *info)
info->csvd.end_time = info->csvd.latest_time;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), FALSE);
- table = GTK_WIDGET(gtk_builder_get_object (builder, "select_range_table"));
+ table = GTK_WIDGET(gtk_builder_get_object (info->builder, "select_range_table"));
info->csvd.table = table;
gtk_widget_set_sensitive (GTK_WIDGET(table), FALSE);
- info->csvd.start_date_choose = GTK_WIDGET(gtk_builder_get_object (builder, "start_date_choose"));
- info->csvd.start_date_today = GTK_WIDGET(gtk_builder_get_object (builder, "start_date_today"));
- info->csvd.end_date_choose = GTK_WIDGET(gtk_builder_get_object (builder, "end_date_choose"));
- info->csvd.end_date_today = GTK_WIDGET(gtk_builder_get_object (builder, "end_date_today"));
+ info->csvd.start_date_choose = GTK_WIDGET(gtk_builder_get_object (info->builder, "start_date_choose"));
+ info->csvd.start_date_today = GTK_WIDGET(gtk_builder_get_object (info->builder, "start_date_today"));
+ info->csvd.end_date_choose = GTK_WIDGET(gtk_builder_get_object (info->builder, "end_date_choose"));
+ info->csvd.end_date_today = GTK_WIDGET(gtk_builder_get_object (info->builder, "end_date_today"));
/* Start date info */
info->csvd.start_date = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE);
gtk_widget_set_sensitive (info->csvd.start_date, FALSE);
- hbox = GTK_WIDGET(gtk_builder_get_object (builder, "start_date_hbox"));
+ hbox = GTK_WIDGET(gtk_builder_get_object (info->builder, "start_date_hbox"));
gtk_box_pack_start (GTK_BOX(hbox), info->csvd.start_date, TRUE, TRUE, 0);
gtk_widget_show (info->csvd.start_date);
gnc_date_edit_set_time (GNC_DATE_EDIT(info->csvd.start_date), info->csvd.start_time);
@@ -952,7 +986,7 @@ csv_export_assistant_create (CsvExportInfo *info)
/* End date info */
info->csvd.end_date = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE);
gtk_widget_set_sensitive (info->csvd.end_date, FALSE);
- hbox = GTK_WIDGET(gtk_builder_get_object (builder, "end_date_hbox"));
+ hbox = GTK_WIDGET(gtk_builder_get_object (info->builder, "end_date_hbox"));
gtk_box_pack_start (GTK_BOX(hbox), info->csvd.end_date, TRUE, TRUE, 0);
gtk_widget_show (info->csvd.end_date);
gnc_date_edit_set_time (GNC_DATE_EDIT(info->csvd.end_date), info->csvd.end_time);
@@ -965,7 +999,7 @@ csv_export_assistant_create (CsvExportInfo *info)
}
/* File chooser Page */
- info->file_page = GTK_WIDGET(gtk_builder_get_object(builder, "file_page"));
+ info->file_page = GTK_WIDGET(gtk_builder_get_object(info->builder, "file_page"));
info->file_chooser = gtk_file_chooser_widget_new (GTK_FILE_CHOOSER_ACTION_SAVE);
g_signal_connect (G_OBJECT(info->file_chooser), "selection-changed",
@@ -978,10 +1012,10 @@ csv_export_assistant_create (CsvExportInfo *info)
gtk_widget_show (info->file_chooser);
/* Finish Page */
- info->finish_label = GTK_WIDGET(gtk_builder_get_object (builder, "end_page"));
+ info->finish_label = GTK_WIDGET(gtk_builder_get_object (info->builder, "end_page"));
/* Summary Page */
- info->summary_label = GTK_WIDGET(gtk_builder_get_object (builder, "summary_page"));
+ info->summary_label = GTK_WIDGET(gtk_builder_get_object (info->builder, "summary_page"));
g_signal_connect (G_OBJECT(info->assistant), "destroy",
G_CALLBACK(csv_export_assistant_destroy_cb), info);
@@ -990,12 +1024,12 @@ csv_export_assistant_create (CsvExportInfo *info)
GTK_WINDOW(info->assistant), gnc_ui_get_main_window(NULL));
if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_SAVE_GEOMETRY))
{
- GObject *object = gtk_builder_get_object (builder, "paned");
+ GObject *object = gtk_builder_get_object (info->builder, "paned");
gnc_prefs_bind (GNC_PREFS_GROUP, GNC_PREF_PANED_POS, NULL, object, "position");
}
- gtk_builder_connect_signals (builder, info);
- g_object_unref (G_OBJECT(builder));
+ gtk_builder_connect_signals (info->builder, info);
+ g_object_unref (G_OBJECT(info->builder));
return info->assistant;
}
diff --git a/gnucash/import-export/csv-exp/assistant-csv-export.h b/gnucash/import-export/csv-exp/assistant-csv-export.h
index a2cf8f299c0..5533d9d521d 100644
--- a/gnucash/import-export/csv-exp/assistant-csv-export.h
+++ b/gnucash/import-export/csv-exp/assistant-csv-export.h
@@ -74,6 +74,7 @@ typedef struct
Query *query;
+ GtkBuilder *builder;
GtkWidget *start_page;
GtkWidget *account_page;
GtkWidget *file_page;
@@ -81,6 +82,13 @@ typedef struct
GtkWidget *assistant;
GtkWidget *start_label;
GtkWidget *custom_entry;
+ GtkWidget *comma_radio;
+ GtkWidget *colon_radio;
+ GtkWidget *semicolon_radio;
+ GtkWidget *custom_radio;
+ GtkWidget *simple_layout_check;
+ GtkWidget *gdpdu_layout_check;
+
GtkWidget *file_chooser;
GtkWidget *finish_label;
@@ -92,6 +100,7 @@ typedef struct
char *separator_str;
gboolean use_quotes;
gboolean simple_layout;
+ gboolean gdpdu_layout;
gboolean use_custom;
gboolean failed;
diff --git a/gnucash/import-export/csv-exp/csv-export-helpers.cpp b/gnucash/import-export/csv-exp/csv-export-helpers.cpp
index a945881ac81..ed09cf773d1 100644
--- a/gnucash/import-export/csv-exp/csv-export-helpers.cpp
+++ b/gnucash/import-export/csv-exp/csv-export-helpers.cpp
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
#include
#include "gnc-ui-util.h"
@@ -38,56 +39,61 @@
/* 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"
+#define EOLSTR "\n"
#else
-# define EOLSTR "\r\n"
+#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)
+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)
+ ss.exceptions(std::ios::failbit | std::ios::badbit);
+ try
{
- 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;
+ 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 (need_quote)
- ss << QUOTE;
+ if (first)
+ first = false;
+ else
+ ss << sep_view;
- for (const char& p : str)
- {
- ss << p;
- if (p == QUOTE)
+ if (need_quote)
ss << QUOTE;
- }
- if (need_quote)
- ss << QUOTE;
+ for (const char &p : str)
+ {
+ ss << p;
+ if (p == QUOTE)
+ ss << QUOTE;
+ }
- if (ss.fail())
- return false;
+ if (need_quote)
+ ss << QUOTE;
+
+ if (ss.fail())
+ return false;
+ }
+ ss << EOLSTR;
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << e.what() << '\n';
}
- ss << EOLSTR;
return !ss.fail();
}
std::string
-account_get_fullname_str (Account *account)
+account_get_fullname_str(Account *account)
{
- auto name{gnc_account_get_full_name (account)};
+ auto name{gnc_account_get_full_name(account)};
auto rv{std::string(name)};
- g_free (name);
+ g_free(name);
return rv;
}
diff --git a/gnucash/import-export/csv-exp/csv-transaction-export-line.cpp b/gnucash/import-export/csv-exp/csv-transaction-export-line.cpp
new file mode 100644
index 00000000000..2af530bbc5b
--- /dev/null
+++ b/gnucash/import-export/csv-exp/csv-transaction-export-line.cpp
@@ -0,0 +1,458 @@
+/*******************************************************************\
+ * csv-transactions-export-line.cpp -- Convert Transaction to line *
+ * *
+ * Copyright (C) 2025 Johannes Triegel *
+ * *
+ * 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.h
+ @brief CSV Export Transactions
+ @author Copyright (c) 2025 Johannes Triegel
+*/
+
+#include
+
+#include
+#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-transaction-export-line.hpp"
+
+CsvTransactionExportLine::CsvTransactionExportLine(Split *split,
+ Transaction *transaction,
+ const char *separator,
+ bool use_quotes,
+ bool simple,
+ bool gdpdu,
+ bool is_trading_acc,
+ std::ofstream &ss) : m_split(split),
+ m_transaction(transaction),
+ m_separator(separator),
+ m_use_quotes(use_quotes),
+ m_simple(simple && !gdpdu),
+ m_gdpdu(gdpdu),
+ m_is_trading_acc(is_trading_acc),
+ m_ss(ss),
+ m_is_debit_split(false),
+ m_is_credit_split(false),
+ m_base_split(NULL),
+ m_base_split_account(NULL),
+ m_gdpdu_failed(false)
+{
+ GList *splits = xaccTransGetSplitList(m_transaction);
+ uint debit = 0;
+ uint credit = 0;
+
+ if (g_list_length(splits) > 2)
+ {
+ /* Check if the base is a debit or credit booking, e.g. which is the account everything comes to or from */
+ for (GList *split = splits; split != NULL; split = split->next)
+ {
+ gnc_numeric amount = xaccSplitGetAmount(static_cast(split->data));
+ if (gnc_numeric_positive_p(amount))
+ {
+ debit++;
+ }
+ else if (gnc_numeric_negative_p(amount))
+ {
+ credit++;
+ }
+ }
+ if (debit > 1 && credit > 1)
+ {
+ /* If you have a booking with multiple credit and debit accounts this cannot be exported without an extra account*/
+ m_gdpdu_failed = true;
+ return;
+ }
+ else if (credit > 1)
+ {
+ m_is_debit_split = true;
+ }
+ else
+ {
+ m_is_credit_split = true;
+ }
+
+ // Find the base_split
+ Split *m_base_split = NULL;
+ for (GList *split = splits; split != NULL; split = split->next)
+ {
+ gnc_numeric amount = xaccSplitGetAmount(static_cast(split->data));
+ if (gnc_numeric_positive_p(amount) && m_is_debit_split)
+ {
+ m_base_split = static_cast(split->data);
+ break;
+ }
+ else if (gnc_numeric_negative_p(amount) && m_is_credit_split)
+ {
+ m_base_split = static_cast(split->data);
+ break;
+ }
+ }
+ m_base_split_account = xaccSplitGetAccount(m_base_split);
+ }
+ else
+ {
+ m_is_debit_split = false;
+ m_is_credit_split = false;
+ m_base_split_account = NULL;
+ m_base_split = NULL;
+ }
+}
+
+bool CsvTransactionExportLine::is_split_transaction()
+{
+ return m_is_debit_split || m_is_credit_split;
+}
+
+std::string
+CsvTransactionExportLine::get_date(Transaction *trans)
+{
+ char datebuff[MAX_DATE_LENGTH + 1];
+ qof_print_date_buff(datebuff, MAX_DATE_LENGTH, xaccTransGetDate(m_transaction));
+ return datebuff;
+}
+
+std::string
+CsvTransactionExportLine::get_guid(Transaction *trans)
+{
+ return gnc::GUID(*qof_entity_get_guid(QOF_INSTANCE(m_transaction))).to_string();
+}
+
+// Reconcile Date
+std::string
+CsvTransactionExportLine::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
+std::string
+CsvTransactionExportLine::get_account_name(Split *split, bool full)
+{
+ auto account{xaccSplitGetAccount(split)};
+ return full ? account_get_fullname_str(account) : xaccAccountGetName(account);
+}
+
+// Account ode
+std::string
+CsvTransactionExportLine::get_account_number(Split *split)
+{
+ auto account{xaccSplitGetAccount(split)};
+ const gchar *code = xaccAccountGetCode(account);
+ return code ? code : _("Unknown");
+}
+
+// Account Code
+std::string
+CsvTransactionExportLine::get_other_account_number(Split *split)
+{
+ auto other{xaccSplitGetOtherSplit(split)};
+ return get_account_number(other);
+}
+
+// Number
+std::string
+CsvTransactionExportLine::get_number(Transaction *trans)
+{
+ auto num{xaccTransGetNum(m_transaction)};
+ return (num ? num : "");
+}
+
+// Description
+std::string
+CsvTransactionExportLine::get_description(Transaction *trans)
+{
+ auto desc{xaccTransGetDescription(m_transaction)};
+ return (desc ? desc : "");
+}
+
+// Notes
+std::string
+CsvTransactionExportLine::get_notes(Transaction *trans)
+{
+ auto notes{xaccTransGetNotes(m_transaction)};
+ return (notes ? notes : "");
+}
+
+// Void reason
+std::string
+CsvTransactionExportLine::get_void_reason(Transaction *trans)
+{
+ auto void_reason{xaccTransGetVoidReason(m_transaction)};
+ return (void_reason ? void_reason : "");
+}
+
+// Memo
+std::string
+CsvTransactionExportLine::get_memo(Split *split)
+{
+ auto memo{xaccSplitGetMemo(split)};
+ return (memo ? memo : "");
+}
+
+// Full Category Path or Not
+std::string
+CsvTransactionExportLine::get_category(Split *split, bool full)
+{
+ auto other{xaccSplitGetOtherSplit(split)};
+ return other ? get_account_name(other, full) : _("-- Split Transaction --");
+}
+
+// Action
+std::string
+CsvTransactionExportLine::get_action(Split *split)
+{
+ auto action{xaccSplitGetAction(split)};
+ return (action ? action : "");
+}
+
+// Reconcile
+std::string
+CsvTransactionExportLine::get_reconcile(Split *split)
+{
+ auto recon{gnc_get_reconcile_str(xaccSplitGetReconcile(split))};
+ return (recon ? recon : "");
+}
+
+// Transaction commodity
+std::string
+CsvTransactionExportLine::get_commodity(Transaction *trans)
+{
+ return gnc_commodity_get_unique_name(xaccTransGetCurrency(m_transaction));
+}
+
+// Amount with Symbol or not
+std::string
+CsvTransactionExportLine::get_amount(Split *split, bool t_void, bool symbol, bool positive)
+{
+ auto amt_num{t_void ? xaccSplitVoidFormerAmount(split) : xaccSplitGetAmount(split)};
+ if (positive)
+ amt_num = gnc_numeric_abs(amt_num);
+ auto pinfo{gnc_split_amount_print_info(split, symbol)};
+ if (!symbol)
+ pinfo.use_separators = 0;
+ return xaccPrintAmount(amt_num, pinfo);
+}
+
+// Value with Symbol or not
+std::string
+CsvTransactionExportLine::get_value(Split *split, bool t_void, bool symbol)
+{
+ auto tcurr{xaccTransGetCurrency(m_transaction)};
+ auto pai{gnc_commodity_print_info(tcurr, symbol)};
+ if (!symbol)
+ pai.use_separators = 0;
+ auto amt_num{t_void ? xaccSplitVoidFormerValue(split) : xaccSplitGetValue(split)};
+ return xaccPrintAmount(amt_num, pai);
+}
+
+// Share Price / Conversion factor
+std::string
+CsvTransactionExportLine::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
+std::string
+CsvTransactionExportLine::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));
+}
+
+bool CsvTransactionExportLine::print_csv()
+{
+ if (m_gdpdu && m_gdpdu_failed)
+ return false;
+
+ if (m_simple || (!is_split_transaction() && m_gdpdu))
+ {
+ auto amount = xaccSplitGetAmount(m_split);
+ /* Ignore bookings with zero value in gdpdu export*/
+ if (gnc_numeric_zero_p(amount) && m_gdpdu)
+ return true;
+
+ auto line = m_gdpdu ? make_gdpdu_trans_line(m_split) : make_simple_trans_line(m_split);
+ return gnc_csv_add_line(m_ss, line, m_use_quotes,
+ m_separator);
+ }
+ else if (is_split_transaction() && m_gdpdu)
+ {
+ bool ok = false;
+ GList *splits = xaccTransGetSplitList(m_transaction);
+ for (GList *split = splits; split != NULL; split = split->next)
+ {
+ Split *s = static_cast(split->data);
+
+ auto amount = xaccSplitGetAmount(s);
+ /* Ignore bookings with zero value in gdpdu export*/
+ if (gnc_numeric_zero_p(amount))
+ continue;
+
+ auto split_account = xaccSplitGetAccount(s);
+ if (!split_account)
+ {
+ continue;
+ }
+
+ if (xaccAccountEqual(split_account, m_base_split_account, true))
+ continue;
+
+ auto line = make_gdpdu_trans_split_line(s);
+ ok = gnc_csv_add_line(m_ss, line, m_use_quotes,
+ m_separator);
+ if (!ok)
+ break;
+ }
+ return ok;
+ }
+ else
+ {
+ /* Loop through the list of splits for the Transaction */
+ bool failed = false;
+ for (auto node = xaccTransGetSplitList(m_transaction); !failed && node;
+ node = node->next)
+ {
+ auto t_split{static_cast(node->data)};
+
+ // base split is already written on the trans_line
+ if (m_split == t_split)
+ continue;
+
+ // Only export trading splits if exporting a trading account
+ Account *tsplit_acc = xaccSplitGetAccount(t_split);
+ if (!m_is_trading_acc &&
+ (xaccAccountGetType(tsplit_acc) == ACCT_TYPE_TRADING))
+ continue;
+
+ // Write complex Split Line.
+ auto line = make_complex_trans_line(t_split);
+ failed = !gnc_csv_add_line(m_ss, line, m_use_quotes, m_separator);
+ }
+ return failed;
+ }
+}
+
+StringVec
+CsvTransactionExportLine::make_gdpdu_trans_split_line(Split *split)
+{
+ auto t_void{xaccTransGetVoidStatus(m_transaction)};
+
+ auto base_acc_code = xaccAccountGetCode(m_base_split_account);
+ if (!base_acc_code)
+ base_acc_code = _("Unknown");
+
+ return {
+ get_date(m_transaction),
+ get_number(m_transaction),
+ m_is_credit_split ? base_acc_code : get_account_number(split),
+ m_is_credit_split ? get_account_number(split) : base_acc_code,
+ get_description(m_transaction),
+ get_amount(split, t_void, false, true)};
+}
+
+StringVec
+CsvTransactionExportLine::make_gdpdu_trans_line(Split *split)
+{
+ auto t_void{xaccTransGetVoidStatus(m_transaction)};
+ auto amount = xaccSplitGetAmount(split);
+ auto account = xaccSplitGetAccount(split);
+ auto type = xaccAccountGetType(account);
+ bool pos = gnc_numeric_positive_p(amount);
+
+ /* It is possible that other types of accounts need to be taken into account here */
+ bool exchange = false;
+ switch (type) {
+ case ACCT_TYPE_EQUITY:
+ exchange = true;
+ break;
+ default:
+ break;
+ }
+
+ return {
+ get_date(m_transaction),
+ get_number(m_transaction),
+ pos || exchange ? get_other_account_number(split) : get_account_number(split),
+ pos || exchange ? get_account_number(split) : get_other_account_number(split),
+ get_description(m_transaction),
+ get_amount(split, t_void, false, true)};
+}
+
+StringVec
+CsvTransactionExportLine::make_complex_trans_line(Split *split)
+{
+ auto t_void{xaccTransGetVoidStatus(m_transaction)};
+ return {
+ get_date(m_transaction),
+ get_guid(m_transaction),
+ get_number(m_transaction),
+ get_description(m_transaction),
+ get_notes(m_transaction),
+ get_commodity(m_transaction),
+ get_void_reason(m_transaction),
+ 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)};
+}
+
+StringVec
+CsvTransactionExportLine::make_simple_trans_line(Split *split)
+{
+ auto t_void{xaccTransGetVoidStatus(m_transaction)};
+ return {
+ get_date(m_transaction),
+ get_account_name(split, true),
+ get_number(m_transaction),
+ get_description(m_transaction),
+ 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)};
+}
\ No newline at end of file
diff --git a/gnucash/import-export/csv-exp/csv-transaction-export-line.hpp b/gnucash/import-export/csv-exp/csv-transaction-export-line.hpp
new file mode 100644
index 00000000000..233b0fd8cf3
--- /dev/null
+++ b/gnucash/import-export/csv-exp/csv-transaction-export-line.hpp
@@ -0,0 +1,100 @@
+/*******************************************************************\
+ * csv-transactions-export-line.h -- Convert Transaction to line *
+ * *
+ * Copyright (C) 2025 Johannes Triegel *
+ * *
+ * 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.h
+ @brief CSV Export Transactions
+ @author Copyright (c) 2025 Johannes Triegel
+*/
+
+#ifndef CSV_TRANSACTIONS_EXPORT_LINE
+#define CSV_TRANSACTIONS_EXPORT_LINE
+
+#include
+#include
+
+#include "Transaction.h"
+#include "csv-export-helpers.hpp"
+
+class CsvTransactionExportLine
+{
+public:
+ CsvTransactionExportLine(Split *split,
+ Transaction *transaction,
+ const char *separator,
+ bool use_quotes,
+ bool simple,
+ bool gdpdu,
+ bool is_trading_acc,
+ std::ofstream &ss);
+
+ bool print_csv();
+
+protected:
+ std::string get_date(Transaction *trans);
+ std::string get_guid(Transaction *trans);
+ std::string get_reconcile_date(Split *split);
+ std::string get_account_name(Split *split, bool full);
+ std::string get_account_number(Split *split);
+ std::string get_other_account_number(Split *split);
+ std::string get_number(Transaction *trans);
+ std::string get_description(Transaction *trans);
+ std::string get_notes(Transaction *trans);
+ std::string get_void_reason(Transaction *trans);
+ std::string get_memo(Split *split);
+ std::string get_category(Split *split, bool full);
+ std::string get_action(Split *split);
+ std::string get_reconcile(Split *split);
+ std::string get_commodity(Transaction *trans);
+ std::string get_amount(Split *split, bool t_void, bool symbol, bool positive = false);
+ std::string get_value(Split *split, bool t_void, bool symbol);
+ std::string get_rate(Split *split, bool t_void);
+ std::string get_price(Split *split, bool t_void);
+
+ bool is_split_transaction();
+
+ StringVec make_simple_trans_split_line(Split *split);
+ StringVec make_simple_trans_line(Split *split);
+ StringVec make_gdpdu_trans_split_line(Split *split);
+ StringVec make_gdpdu_trans_line(Split *split);
+ StringVec make_complex_trans_line(Split *split);
+
+private:
+ Split *m_split;
+ Transaction *m_transaction;
+
+ const char *m_separator;
+ bool m_use_quotes;
+ bool m_simple;
+ bool m_gdpdu;
+ bool m_is_trading_acc;
+ std::ofstream &m_ss;
+
+ bool m_is_debit_split;
+ bool m_is_credit_split;
+
+ Split *m_base_split;
+ Account *m_base_split_account;
+
+ bool m_gdpdu_failed;
+};
+
+#endif
\ No newline at end of file
diff --git a/gnucash/import-export/csv-exp/csv-transactions-export.cpp b/gnucash/import-export/csv-exp/csv-transactions-export.cpp
index 74515e5b4bf..f70ceb690a5 100644
--- a/gnucash/import-export/csv-exp/csv-transactions-export.cpp
+++ b/gnucash/import-export/csv-exp/csv-transactions-export.cpp
@@ -42,217 +42,14 @@
#include "guid.hpp"
#include "csv-transactions-export.h"
-#include "csv-export-helpers.hpp"
+#include "csv-transaction-export-line.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)};
- return full ? account_get_fullname_str (account) : 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)
-{
- auto other{xaccSplitGetOtherSplit(split)};
- return other ? get_account_name (other, full) : _("-- Split Transaction --");
-}
-
-// 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)};
- auto pinfo{gnc_split_amount_print_info (split, symbol)};
- if (!symbol)
- pinfo.use_separators = 0;
- return xaccPrintAmount (amt_num, pinfo);
-}
-
-// 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)};
- if (!symbol)
- pai.use_separators = 0;
- 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;
+using TransSet = std::unordered_set;
/*******************************************************
* account_splits
@@ -261,85 +58,58 @@ using TransSet = std::unordered_set;
* send them to a file
*******************************************************/
static void
-export_query_splits (CsvExportInfo *info, bool is_trading_acct,
- std::ofstream& ss, TransSet& trans_set)
+export_query_splits(CsvExportInfo *info, bool is_trading_acct,
+ std::ofstream &ss, TransSet &trans_set)
{
- g_return_if_fail (info);
+ g_return_if_fail(info);
/* Run the query */
- for (GList *splits = qof_query_run (info->query); !info->failed && splits;
+ for (GList *splits = qof_query_run(info->query); /*!info->failed && */ splits;
splits = splits->next)
{
- auto split{static_cast(splits->data)};
- auto trans{xaccSplitGetParent (split)};
+ auto split{static_cast(splits->data)};
+ auto trans{xaccSplitGetParent(split)};
// Look for trans already exported in trans_set
- if (!trans_set.emplace (trans).second)
+ if (!trans_set.emplace(trans).second)
+ {
continue;
+ }
// Look for blank split
- Account *split_acc = xaccSplitGetAccount (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)
+ (xaccAccountGetType(split_acc) == ACCT_TYPE_TRADING))
{
- // 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(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);
- }
+ CsvTransactionExportLine line(split, trans, info->separator_str, info->use_quotes, info->simple_layout, info->gdpdu_layout, is_trading_acct, ss);
+ info->failed = !line.print_csv();
}
}
static void
-account_splits (CsvExportInfo *info, Account *acc,
- std::ofstream& ss, TransSet& trans_set)
+account_splits(CsvExportInfo *info, Account *acc,
+ std::ofstream &ss, TransSet &trans_set)
{
- g_return_if_fail (info && GNC_IS_ACCOUNT (acc));
+ g_return_if_fail(info && GNC_IS_ACCOUNT(acc));
// Setup the query for normal transaction export
- auto p1 = g_slist_prepend (g_slist_prepend (nullptr, (gpointer)TRANS_DATE_POSTED), (gpointer)SPLIT_TRANS);
- auto p2 = g_slist_prepend (nullptr, (gpointer)QUERY_DEFAULT_SORT);
- info->query = qof_query_create_for (GNC_ID_SPLIT);
- qof_query_set_book (info->query, gnc_get_current_book());
- qof_query_set_sort_order (info->query, p1, p2, nullptr);
- xaccQueryAddSingleAccountMatch (info->query, acc, QOF_QUERY_AND);
- xaccQueryAddDateMatchTT (info->query, true, info->csvd.start_time, true, info->csvd.end_time, QOF_QUERY_AND);
- export_query_splits (info, xaccAccountGetType (acc) == ACCT_TYPE_TRADING, ss, trans_set);
- qof_query_destroy (info->query);
+ auto p1 = g_slist_prepend(g_slist_prepend(nullptr, (gpointer)TRANS_DATE_POSTED), (gpointer)SPLIT_TRANS);
+ auto p2 = g_slist_prepend(nullptr, (gpointer)QUERY_DEFAULT_SORT);
+ info->query = qof_query_create_for(GNC_ID_SPLIT);
+ qof_query_set_book(info->query, gnc_get_current_book());
+ qof_query_set_sort_order(info->query, p1, p2, nullptr);
+ xaccQueryAddSingleAccountMatch(info->query, acc, QOF_QUERY_AND);
+ xaccQueryAddDateMatchTT(info->query, true, info->csvd.start_time, true, info->csvd.end_time, QOF_QUERY_AND);
+ export_query_splits(info, xaccAccountGetType(acc) == ACCT_TYPE_TRADING, ss, trans_set);
+ qof_query_destroy(info->query);
}
/*******************************************************
@@ -347,13 +117,13 @@ account_splits (CsvExportInfo *info, Account *acc,
*
* write a list of transactions to a text file
*******************************************************/
-void csv_transactions_export (CsvExportInfo *info)
+void csv_transactions_export(CsvExportInfo *info)
{
ENTER("");
DEBUG("File name is : %s", info->file_name);
StringVec headers;
- bool num_action = qof_book_use_split_action_for_num_field (gnc_get_current_book());
+ bool num_action = qof_book_use_split_action_for_num_field(gnc_get_current_book());
/* Header string */
if (info->simple_layout)
@@ -374,6 +144,20 @@ void csv_transactions_export (CsvExportInfo *info)
_("Rate/Price"),
};
}
+ /* Header string */
+ if (info->gdpdu_layout)
+ {
+ /* Translators: The following symbols will build the header
+ line of exported CSV files for german GdPDU-Export: */
+ headers = {
+ _("Date"),
+ (num_action ? _("Transaction Number") : _("Number")),
+ _("Debit Account"),
+ _("Credit Account"),
+ _("Description"),
+ _("Amount"),
+ };
+ }
else
headers = {
_("Date"),
@@ -398,7 +182,7 @@ void csv_transactions_export (CsvExportInfo *info)
/* Write header line */
auto ss{gnc_open_filestream(info->file_name)};
- info->failed = !gnc_csv_add_line (ss, headers, info->use_quotes, info->separator_str);
+ info->failed = !gnc_csv_add_line(ss, headers, info->use_quotes, info->separator_str);
/* Go through list of accounts */
TransSet trans_set;
@@ -407,16 +191,15 @@ void csv_transactions_export (CsvExportInfo *info)
{
case XML_EXPORT_TRANS:
for (auto ptr = info->csva.account_list; !ss.fail() && ptr; ptr = g_list_next(ptr))
- account_splits (info, GNC_ACCOUNT(ptr->data), ss, trans_set);
+ account_splits(info, GNC_ACCOUNT(ptr->data), ss, trans_set);
break;
case XML_EXPORT_REGISTER:
- export_query_splits (info, false, ss, trans_set);
+ export_query_splits(info, false, ss, trans_set);
break;
default:
- PERR ("unknown export_type %d", info->export_type);
+ PERR("unknown export_type %d", info->export_type);
}
info->failed = ss.fail();
LEAVE("");
}
-
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 14fc124d623..f48a21eb2de 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -323,6 +323,7 @@ gnucash/import-export/bi-import/dialog-bi-import-helper.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/csv-export-helpers.cpp
+gnucash/import-export/csv-exp/csv-transaction-export-line.cpp
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