1 /* ************************************************************************** */
2 /* This file manage CSV export format                                         */
3 /*                                                                            */
4 /*     Copyright (C)    2004 François Terrot (francois.terrot at grisbi.org)  */
5 /*          2005 Alain Portal (aportal@univ-montp2.fr)                        */
6 /*          2009 Benjamin Drieu (bdrieu@april.org)                            */
7 /*          2010-2018 Pierre Biava (grisbi@pierre.biava.name)                 */
8 /*          https://www.grisbi.org/                                            */
9 /*                                                                            */
10 /*  This program is free software; you can redistribute it and/or modify      */
11 /*  it under the terms of the GNU General Public License as published by      */
12 /*  the Free Software Foundation; either version 2 of the License, or         */
13 /*  (at your option) any later version.                                       */
14 /*                                                                            */
15 /*  This program is distributed in the hope that it will be useful,           */
16 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of            */
17 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
18 /*  GNU General Public License for more details.                              */
19 /*                                                                            */
20 /*  You should have received a copy of the GNU General Public License         */
21 /*  along with this program; if not, write to the Free Software               */
22 /*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23 /*                                                                            */
24 /* ************************************************************************** */
25 
26 /**
27  * \todo make the CSV parameter configurable
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 
34 #include "include.h"
35 #include <errno.h>
36 #include <glib/gi18n.h>
37 
38 /*START_INCLUDE*/
39 #include "export_csv.h"
40 #include "dialog.h"
41 #include "grisbi_win.h"
42 #include "gsb_data_account.h"
43 #include "gsb_data_archive_store.h"
44 #include "gsb_data_budget.h"
45 #include "gsb_data_category.h"
46 #include "gsb_data_currency.h"
47 #include "gsb_data_fyear.h"
48 #include "gsb_data_payee.h"
49 #include "gsb_data_payment.h"
50 #include "gsb_data_reconcile.h"
51 #include "gsb_data_transaction.h"
52 #include "gsb_file_util.h"
53 #include "gsb_real.h"
54 #include "structures.h"
55 #include "utils_dates.h"
56 #include "utils_files.h"
57 #include "utils_real.h"
58 #include "utils_str.h"
59 #include "erreur.h"
60 /*END_INCLUDE*/
61 
62 /*START_STATIC*/
63 static gboolean g_csv_with_title_line = TRUE; /*!< CSV configuration - does the file result contains a title line ?  */
64 static gchar *	g_csv_field_separator;		  /*!< CSV configuration - separator charater used between fields of a record */
65 static GsbReal	current_balance;
66 /*END_STATIC*/
67 
68 /*START_EXTERN*/
69 /*END_EXTERN*/
70 
71 /**
72  * \brief Clear a record field to default empty value.
73  *
74  * Free the memory used by the field value.
75  *
76  * \param a filed poointed
77  */
78 #define CSV_CLEAR_FIELD(a) \
79 if (a) \
80 { \
81 	g_free(a);  a = NULL; \
82 } \
83 
84 /**
85  * \brief write a string field.
86  * \internal
87  *
88  * The string field is quoted and converted from utf8 to locale charset.
89  * A end of field character id added after the field
90  * Also manage to add a empty string if field is empty
91  *
92  * \param   f   valid file stream to write
93  * \param   a   string field to add.
94  *
95  */
96 #define CSV_STR_FIELD(f,a) \
97 if (a) \
98 { \
99 	gchar *tmp_str; \
100 	tmp_str = g_locale_from_utf8 (a,-1,NULL,NULL,NULL); \
101 	fprintf(f,"\"%s\"%s",tmp_str,g_csv_field_separator); \
102 	g_free (tmp_str); \
103 } \
104 else \
105 { \
106 	fprintf(f,"\"\"%s",g_csv_field_separator); \
107 } \
108 
109 /**
110  * \brief Write a numerical field.
111  * \internal
112  *
113  * A end of field character id added after the field
114  * A 0 (zero) is put by default if the field is empty.
115  *
116  * \param   f   valid file stream to write
117  * \param   a   numerical field to add.
118  */
119 #define CSV_NUM_FIELD(f,a) \
120 if (a) \
121 { \
122 	gchar *tmp_str; \
123 	tmp_str = g_locale_from_utf8 (a,-1,NULL,NULL,NULL); \
124 	fprintf(f,"%s%s",tmp_str,g_csv_field_separator); \
125 	g_free (tmp_str); \
126 } \
127 else \
128 { \
129 	fprintf(f,"0%s",g_csv_field_separator); \
130 } \
131 
132 /**
133  * \brief write a date field without quotes.
134  * \internal
135  *
136  * The date field is converted from utf8 to locale charset.
137  * A end of field character id added after the field
138  * Also manage to add a empty string if field is empty
139  *
140  * \param   f   valid file stream to write
141  * \param   a   string field to add.
142  *
143  */
144 #define CSV_DATE_FIELD(f,a) \
145 if (a) \
146 { \
147 	gchar *tmp_str; \
148 	tmp_str = g_locale_from_utf8 (a,-1,NULL,NULL,NULL); \
149 	fprintf(f,"%s%s",tmp_str,g_csv_field_separator); \
150 	g_free (tmp_str); \
151 } \
152 else \
153 { \
154 	fprintf(f,"%s",g_csv_field_separator); \
155 } \
156 
157 /**
158  * \brief Write the end of record character
159  *
160  * \param   f   valid file stream to write
161  */
162 #define CSV_END_RECORD(f)  fprintf(f,"\n")
163 
164 #define EMPTY_STR_FIELD fprintf(csv_file,"\"\""); /*!< empty string field value */
165 #define EMPTY_NUM_FIELD fprintf(csv_file,"0");    /*!< empty numerical field value */
166 
167 /*START_GLOBAL*/
168 gchar*  csv_field_operation  = NULL; /*!< operation number (numerical) */
169 gchar*	csv_field_account    = NULL; /*!< account name */
170 gchar*  csv_field_ventil     = NULL; /*!< is operation a split (string) */
171 gchar*  csv_field_date       = NULL; /*!< date of operation (of main operation for split) (string) */
172 gchar*  csv_field_date_val   = NULL; /*!< value date of operation (of main operation for split) (string) */
173 gchar*  csv_field_pointage   = NULL; /*!< pointed/reconcialiation status (string) */
174 gchar*  csv_field_tiers      = NULL; /*!< Payee (string) */
175 gchar*  csv_field_credit     = NULL; /*!< credit (numerical) */
176 gchar*  csv_field_debit      = NULL; /*!< debit (numerical) */
177 gchar*  csv_field_solde      = NULL; /*!< balance (numerical) */
178 gchar*  csv_field_categ      = NULL; /*!< category (string) */
179 gchar*  csv_field_sous_categ = NULL; /*!< sub category (string) */
180 gchar*  csv_field_imput      = NULL; /*!< budgetary line (string) */
181 gchar*  csv_field_sous_imput = NULL; /*!< sub budgetary line (string) */
182 gchar*  csv_field_notes      = NULL; /*!< notes (string) */
183 gchar*  csv_field_exercice   = NULL; /*!< exercices (string) optional depending of global grisbi configuration */
184 gchar*  csv_field_piece      = NULL; /*!< (string) */
185 gchar*  csv_field_cheque     = NULL; /*!< cheques */
186 gchar*  csv_field_rappro     = NULL; /*!< reconciliation number (string) */
187 gchar*  csv_field_info_bank  = NULL; /*!< bank references (string) */
188 /*END_GLOBAL*/
189 
190 
191 /******************************************************************************/
192 /* Private functions                                                          */
193 /******************************************************************************/
194 /**
195  * retourne une string avec la bon format numérique pour les montants
196  *
197  * \param a number
198  *
199  * \return a string should be freed with g_free()
200  **/
csv_real_get_string_from_us_option(GsbReal number)201 static gchar *csv_real_get_string_from_us_option (GsbReal number)
202 {
203 	gchar *tmp_str;
204 
205 	if (etat.export_force_US_numbers)
206 	{
207 		tmp_str = utils_real_get_string_intl (number);
208 	}
209 	else
210 	{
211 		tmp_str = utils_real_get_string (number);
212 	}
213 
214 	return tmp_str;
215 }
216 
217 /**
218  * try to open the csv file in w mode
219  *
220  * \param filename
221  *
222  * \return a FILE pointer or NULL if problem
223  * */
gsb_csv_export_open_file(const gchar * filename)224 static FILE *gsb_csv_export_open_file (const gchar *filename)
225 {
226     FILE *csv_file;
227 
228     /* Création du fichier, si pb, on marque l'erreur et passe au fichier suivant */
229     csv_file = utils_files_utf8_fopen (filename, "w");
230     if (! csv_file)
231     {
232         gchar *sMessage = NULL;
233 
234         sMessage = g_strdup_printf (_("Unable to create file \"%s\" :\n%s"),
235                          filename, g_strerror (errno));
236         dialogue (sMessage);
237 
238         g_free (sMessage);
239 
240         return NULL;
241     }
242 
243     return csv_file;
244 }
245 
246 /**
247  * \brief clear temporary variable used to store field to display.
248  *
249  * \internal
250  *
251  * This function is to used before computing a new operation.
252  *
253  * The function is able to reset all or just a part of the variable
254  * depending of the need - typically the date is not reset when reading
255  * split operation items.
256  *
257  * \param clear_all partial or complete cleaning.
258  *
259  * \return
260  **/
csv_clear_fields(gboolean clear_all)261 static void csv_clear_fields(gboolean clear_all)
262 { /* {{{ */
263   if (clear_all)
264   {
265     CSV_CLEAR_FIELD(csv_field_date);
266     CSV_CLEAR_FIELD(csv_field_date_val);
267     CSV_CLEAR_FIELD(csv_field_pointage);
268     CSV_CLEAR_FIELD(csv_field_operation);
269     CSV_CLEAR_FIELD(csv_field_account);
270     CSV_CLEAR_FIELD(csv_field_tiers);
271     CSV_CLEAR_FIELD(csv_field_solde);
272   }
273 
274   CSV_CLEAR_FIELD(csv_field_notes);
275   CSV_CLEAR_FIELD(csv_field_debit);
276   CSV_CLEAR_FIELD(csv_field_credit);
277   CSV_CLEAR_FIELD(csv_field_ventil);
278   CSV_CLEAR_FIELD(csv_field_categ);
279   CSV_CLEAR_FIELD(csv_field_sous_categ);
280   CSV_CLEAR_FIELD(csv_field_imput);
281   CSV_CLEAR_FIELD(csv_field_sous_imput);
282   CSV_CLEAR_FIELD(csv_field_exercice);
283   CSV_CLEAR_FIELD(csv_field_piece);
284   CSV_CLEAR_FIELD(csv_field_cheque);
285   CSV_CLEAR_FIELD(csv_field_info_bank);
286   CSV_CLEAR_FIELD(csv_field_rappro);
287 } /* }}} csv_clear_fields */
288 
289 /**
290  * \brief Write down the current csv record.
291  *
292  * \internal
293  *
294  * The function appends the current csv record values followed by a end of record
295  * in the given file and then clean all fields (if requested)
296  * Depending of a global grisbi configuration some field may not be written (like exercice one)
297  *
298  * \param file      valid file stream to write
299  * \param clear_all partial or complete cleaning.
300  * \param print_balance print the balance or not
301  *
302  * \return
303  **/
csv_add_record(FILE * file,gboolean clear_all,gboolean print_balance)304 static void csv_add_record(FILE* file,
305 			   gboolean clear_all,
306 			   gboolean print_balance)
307 { /* {{{ */
308 	GrisbiWinEtat *w_etat;
309 
310 	w_etat = (GrisbiWinEtat *) grisbi_win_get_w_etat ();
311 
312   CSV_NUM_FIELD(file,csv_field_operation);
313   CSV_STR_FIELD(file,csv_field_account);
314   CSV_STR_FIELD(file,csv_field_ventil);
315   if (w_etat->export_quote_dates)
316   {
317 	CSV_STR_FIELD(file,csv_field_date);
318 	CSV_STR_FIELD(file,csv_field_date_val);
319   }
320   else
321   {
322     CSV_DATE_FIELD(file,csv_field_date);
323     CSV_DATE_FIELD(file,csv_field_date_val);
324   }
325   CSV_STR_FIELD(file,csv_field_cheque);
326   CSV_STR_FIELD(file,csv_field_exercice);
327   CSV_STR_FIELD(file,csv_field_pointage);
328   CSV_STR_FIELD(file,csv_field_tiers);
329   CSV_NUM_FIELD(file,csv_field_credit);
330   CSV_NUM_FIELD(file,csv_field_debit);
331   if (print_balance)
332   {
333       CSV_NUM_FIELD(file,csv_field_solde);
334   }
335   CSV_STR_FIELD(file,csv_field_categ);
336   CSV_STR_FIELD(file,csv_field_sous_categ);
337   CSV_STR_FIELD(file,csv_field_imput);
338   CSV_STR_FIELD(file,csv_field_sous_imput);
339   CSV_STR_FIELD(file,csv_field_notes);
340   CSV_STR_FIELD(file,csv_field_piece);
341   CSV_STR_FIELD(file,csv_field_rappro);
342   CSV_STR_FIELD(file,csv_field_info_bank);
343   CSV_END_RECORD(file);
344   csv_clear_fields(clear_all);
345 } /* }}} csv_add_record */
346 
347 /**
348  * add the title line to the csv file
349  *
350  * \param csv_file a FILE struct
351  * \param print_balance if set the balance or not in the export file
352  *
353  * \return TRUE ok, FALSE problem
354  **/
gsb_csv_export_title_line(FILE * csv_file,gboolean print_balance)355 static gboolean gsb_csv_export_title_line (FILE *csv_file,
356 										   gboolean print_balance)
357 {
358     CSV_CLEAR_FIELD (csv_field_operation);
359     csv_field_operation  = my_strdup (_("Transactions"));
360 
361     CSV_CLEAR_FIELD (csv_field_account);
362     csv_field_account    = my_strdup (_("Account name"));
363 
364     CSV_CLEAR_FIELD (csv_field_ventil);
365     csv_field_ventil     = my_strdup (_("Split"));
366 
367     CSV_CLEAR_FIELD (csv_field_date );
368     csv_field_date       = my_strdup (_("Date"));
369 
370     CSV_CLEAR_FIELD (csv_field_date_val);
371     csv_field_date_val   = my_strdup (_("Value date"));
372 
373     CSV_CLEAR_FIELD (csv_field_cheque);
374     csv_field_cheque     = my_strdup (_("Cheques"));
375 
376     CSV_CLEAR_FIELD (csv_field_exercice);
377     csv_field_exercice   = my_strdup (_("Financial year"));
378 
379     CSV_CLEAR_FIELD (csv_field_pointage);
380     csv_field_pointage   = my_strdup (_("C/R"));
381 
382     CSV_CLEAR_FIELD (csv_field_tiers);
383     csv_field_tiers      = my_strdup (_("Payee"));
384 
385     CSV_CLEAR_FIELD (csv_field_credit);
386     csv_field_credit     = my_strdup (_("Credit"));
387 
388     CSV_CLEAR_FIELD (csv_field_debit);
389     csv_field_debit      = my_strdup (_("Debit"));
390 
391     CSV_CLEAR_FIELD (csv_field_solde);
392     csv_field_solde      = my_strdup (_("Balance"));
393 
394     CSV_CLEAR_FIELD (csv_field_categ);
395     csv_field_categ      = my_strdup (_("Category"));
396 
397     CSV_CLEAR_FIELD (csv_field_sous_categ);
398     csv_field_sous_categ = my_strdup (_("Sub-categories"));
399 
400     CSV_CLEAR_FIELD (csv_field_notes);
401     csv_field_notes      = my_strdup (_("Notes"));
402 
403     CSV_CLEAR_FIELD (csv_field_imput);
404     csv_field_imput      = my_strdup (_("Budgetary lines"));
405 
406     CSV_CLEAR_FIELD (csv_field_sous_imput);
407     csv_field_sous_imput = my_strdup (_("Sub-budgetary lines"));
408 
409     CSV_CLEAR_FIELD (csv_field_piece);
410     csv_field_piece      = my_strdup (_("Voucher"));
411 
412     CSV_CLEAR_FIELD (csv_field_rappro);
413     csv_field_rappro     = my_strdup (_("Reconciliation number"));
414 
415     CSV_CLEAR_FIELD (csv_field_info_bank);
416     csv_field_info_bank  = my_strdup (_("Bank references"));
417 
418     csv_add_record(csv_file,TRUE, print_balance);
419     return TRUE;
420 }
421 
422 /**
423  * used to compare 2 iters and sort the by value date or date if not exist
424  * always put the white line below
425  *
426  * \param iter_1
427  * \param iter_2
428  *
429  * \return -1 if iter_1 is before iter_2
430  **/
gsb_csv_export_sort_by_value_date_or_date(gpointer transaction_pointer_1,gpointer transaction_pointer_2)431 static gint gsb_csv_export_sort_by_value_date_or_date (gpointer transaction_pointer_1,
432 													   gpointer transaction_pointer_2)
433 {
434     gint transaction_number_1;
435     gint transaction_number_2;
436     const GDate *value_date_1;
437     const GDate *value_date_2;
438 
439     transaction_number_1 = gsb_data_transaction_get_transaction_number (transaction_pointer_1);
440     transaction_number_2 = gsb_data_transaction_get_transaction_number (transaction_pointer_2);
441 
442     value_date_1 = gsb_data_transaction_get_value_date (transaction_number_1);
443     if (! value_date_1)
444         value_date_1 = gsb_data_transaction_get_date (transaction_number_1);
445 
446     value_date_2 = gsb_data_transaction_get_value_date (transaction_number_2);
447     if (! value_date_2)
448         value_date_2 = gsb_data_transaction_get_date (transaction_number_2);
449 
450     if (value_date_1)
451         return (g_date_compare (value_date_1, value_date_2));
452     else
453         return -1;
454 }
455 
456 /**
457  * export a transaction given in param in the file given in param
458  *
459  * \param transaction_number
460  * \param csv_file
461  * \param print_balance will set a balance for each transaction in the csv file
462  * 		not set for archive export, set (but usefull ?) for account export
463  *
464  * \return TRUE ok, FALSE problem
465  **/
gsb_csv_export_transaction(gint transaction_number,FILE * csv_file,gboolean print_balance)466 static gboolean gsb_csv_export_transaction (gint transaction_number,
467 											FILE *csv_file,
468 											gboolean print_balance)
469 {
470     GsbReal amount;
471     gint return_exponent;
472     gint account_number;
473 	const gchar *bank_str;
474 	gchar* tmp_str;
475 	const GDate *value_date, *date;
476 	gint budgetary_number;
477 	gint category_number;
478 	gint contra_transaction_number;
479 	gint financial_year_number;
480 	gint payment_method;
481 	gint reconcile_number;
482 
483     account_number = gsb_data_transaction_get_account_number (transaction_number);
484 
485     /* Si c'est une ventilation d'opération (càd une opération fille),
486     elle n'est pas traitée à la base du "if" mais plus loin, quand
487     son opé ventilée sera exportée */
488     if (gsb_data_transaction_get_mother_transaction_number (transaction_number))
489         return TRUE;
490 
491     return_exponent = gsb_data_currency_get_floating_point (gsb_data_account_get_currency (account_number));
492 
493 	/* met la date */
494 	date = gsb_data_transaction_get_date (transaction_number);
495 	if (date)
496 	{
497 	    CSV_CLEAR_FIELD (csv_field_date);
498 		if (etat.export_force_US_dates)
499 		{
500 			csv_field_date = gsb_format_gdate_safe (date);
501 		}
502 		else
503 		{
504 			csv_field_date = g_strdup_printf ("%.2d/%.2d/%d",
505 											  g_date_get_day (date),
506 											  g_date_get_month (date),
507 											  g_date_get_year (date));
508 		}
509 	}
510 
511 	value_date = gsb_data_transaction_get_value_date (transaction_number);
512 	if (value_date)
513 	{
514 	    CSV_CLEAR_FIELD (csv_field_date_val);
515 		if (etat.export_force_US_dates)
516 		{
517 			csv_field_date_val = gsb_format_gdate_safe (date);
518 		}
519 		else
520 		{
521 			csv_field_date_val = g_strdup_printf ("%.2d/%.2d/%d",
522 												  g_date_get_day (date),
523 												  g_date_get_month (date),
524 												  g_date_get_year (date));
525 		}
526 	}
527 
528 	/* met le pointage */
529     CSV_CLEAR_FIELD (csv_field_pointage);
530 	switch (gsb_data_transaction_get_marked_transaction (transaction_number))
531 	{
532 	    case OPERATION_NORMALE:
533             csv_field_pointage = my_strdup ("");
534 		break;
535 	    case OPERATION_POINTEE:
536             csv_field_pointage = my_strdup ("P");
537 		break;
538 	    case OPERATION_TELEPOINTEE:
539             csv_field_pointage = my_strdup ("T");
540 		break;
541 	    case OPERATION_RAPPROCHEE:
542             csv_field_pointage = my_strdup ("R");
543 		break;
544 	}
545 
546 	/* met les notes */
547 	CSV_CLEAR_FIELD(csv_field_notes);
548 	if (gsb_data_transaction_get_notes (transaction_number))
549 	    csv_field_notes = my_strdup (gsb_data_transaction_get_notes (transaction_number));
550 
551 	/* met le tiers */
552 	CSV_CLEAR_FIELD(csv_field_tiers);
553 	csv_field_tiers = g_strdup (gsb_data_payee_get_name (gsb_data_transaction_get_party_number (transaction_number), FALSE));
554 
555 	/* met le numero du rapprochement */
556 	reconcile_number = gsb_data_transaction_get_reconcile_number (transaction_number);
557 	if (reconcile_number)
558 	{
559 	    CSV_CLEAR_FIELD (csv_field_rappro);
560 	    csv_field_rappro = my_strdup (gsb_data_reconcile_get_name (reconcile_number));
561 	}
562 
563 	/* Met les informations bancaires de l'opération. Elles n'existent
564 	   qu'au niveau de l'opération mère */
565 	CSV_CLEAR_FIELD(csv_field_info_bank);
566 	bank_str = gsb_data_transaction_get_bank_references (transaction_number);
567 	if (bank_str)
568 	{
569 	    csv_field_info_bank = my_strdup (bank_str);
570 	}
571 
572 	/* met le montant, transforme la devise si necessaire */
573 	amount = gsb_data_transaction_get_adjusted_amount (transaction_number, return_exponent);
574 	CSV_CLEAR_FIELD (csv_field_credit);
575 	CSV_CLEAR_FIELD (csv_field_debit);
576 	if (amount.mantissa >= 0)
577 	    csv_field_credit = csv_real_get_string_from_us_option (amount);
578 	else
579 	    csv_field_debit  = csv_real_get_string_from_us_option (gsb_real_abs (amount));
580 
581 	/* met le cheque si c'est un type à numerotation automatique */
582 	payment_method = gsb_data_transaction_get_method_of_payment_number (transaction_number);
583 	CSV_CLEAR_FIELD (csv_field_cheque);
584 	if (gsb_data_payment_get_automatic_numbering (payment_method) > 0)
585 	    csv_field_cheque = my_strdup (gsb_data_transaction_get_method_of_payment_content (transaction_number));
586 
587 	/* met l'imputation et la sous imputation budgétaire */
588 	budgetary_number = gsb_data_transaction_get_budgetary_number (transaction_number);
589 	if (gsb_data_transaction_get_budgetary_number (transaction_number) != -1)
590 	{
591 		gint sub_budgetary_number;
592 
593 	    CSV_CLEAR_FIELD (csv_field_imput);
594 	    csv_field_imput = my_strdup (gsb_data_budget_get_name (budgetary_number, 0, ""));
595 
596 		sub_budgetary_number = gsb_data_transaction_get_sub_budgetary_number (transaction_number);
597 	    if (sub_budgetary_number != -1)
598 	    {
599 			CSV_CLEAR_FIELD (csv_field_sous_imput);
600 			csv_field_sous_imput = my_strdup (gsb_data_budget_get_sub_budget_name (budgetary_number,
601 																				   sub_budgetary_number,
602 																				   NULL));
603 	    }
604 	}
605 
606 	/* Piece comptable */
607 	CSV_CLEAR_FIELD (csv_field_piece);
608 	csv_field_piece = my_strdup (gsb_data_transaction_get_voucher (transaction_number));
609 
610 	/* Balance */
611 	if (print_balance)
612 	{
613 	    current_balance = gsb_real_add (current_balance, amount);
614 	    CSV_CLEAR_FIELD (csv_field_solde);
615 	    csv_field_solde = csv_real_get_string_from_us_option (current_balance);
616 	}
617 
618 	/* Number */
619 	CSV_CLEAR_FIELD (csv_field_operation);
620 	csv_field_operation = g_strdup_printf("%d", transaction_number);
621 
622 	/* Account name */
623 	CSV_CLEAR_FIELD (csv_field_account);
624 	csv_field_account = my_strdup (gsb_data_account_get_name (account_number));
625 
626 	/* Financial Year */
627 	financial_year_number = gsb_data_transaction_get_financial_year_number (transaction_number);
628 	if (financial_year_number != -1)
629 	{
630 	    CSV_CLEAR_FIELD (csv_field_exercice);
631 	    csv_field_exercice  = my_strdup (gsb_data_fyear_get_name (financial_year_number));
632 	}
633 
634 	/*  on met soit un virement, soit une ventilation, soit les catégories */
635 
636 	/* Si c'est une opération ventilée, on recherche toutes les ventilations
637 	   de cette opération et on les traite immédiatement. */
638 	/* et les met à la suite */
639 	/* la catégorie de l'opé sera celle de la première opé de ventilation */
640 	if (gsb_data_transaction_get_split_of_transaction (transaction_number))
641 	{
642 	    GSList *pSplitTransactionList;
643 
644 	    CSV_CLEAR_FIELD (csv_field_categ);
645 	    csv_field_categ = my_strdup (_("Split of transaction"));
646 
647 	    csv_add_record(csv_file,FALSE, print_balance);
648 
649 	    pSplitTransactionList = gsb_data_transaction_get_transactions_list ();
650 
651 	    while (pSplitTransactionList)
652 	    {
653 			gint pSplitTransaction;
654 
655 			pSplitTransaction = gsb_data_transaction_get_transaction_number (pSplitTransactionList->data);
656 
657 			if (gsb_data_transaction_get_account_number (pSplitTransaction) == account_number
658 				&& gsb_data_transaction_get_mother_transaction_number (pSplitTransaction) == transaction_number)
659 			{
660 				/* on commence par mettre la catég et sous categ de l'opé et de l'opé de ventilation */
661 				CSV_CLEAR_FIELD (csv_field_ventil);
662 				csv_field_ventil = my_strdup (_("B")); /*->mark */
663 
664 				CSV_CLEAR_FIELD (csv_field_operation);
665 				csv_field_operation = g_strdup_printf("%d", pSplitTransaction);
666 
667 				contra_transaction_number = gsb_data_transaction_get_contra_transaction_number (pSplitTransaction);
668 				if (contra_transaction_number > 0)
669 				{
670 					/* c'est un virement */
671 					CSV_CLEAR_FIELD (csv_field_categ);
672 					csv_field_categ = my_strdup (_("Transfer"));
673 
674 					tmp_str = g_strconcat ("[", gsb_data_account_get_name (contra_transaction_number), "]", NULL);
675 
676 					/* TODO dOm : is it necessary to duplicate memory with my_strdup since it was already newly allocated memory ? */
677 					CSV_CLEAR_FIELD (csv_field_sous_categ);
678 					csv_field_sous_categ = my_strdup (tmp_str);
679 					g_free (tmp_str);
680 				}
681 				else
682 				{
683 					category_number = gsb_data_transaction_get_category_number (pSplitTransaction);
684 					if (category_number != -1)
685 					{
686 						gint sub_category_number;
687 
688 						CSV_CLEAR_FIELD (csv_field_categ);
689 						csv_field_categ = my_strdup (gsb_data_category_get_name (category_number, 0, ""));
690 
691 						sub_category_number = gsb_data_transaction_get_sub_category_number (pSplitTransaction);
692 						if (sub_category_number != -1)
693 						{
694 							CSV_CLEAR_FIELD (csv_field_sous_categ);
695 							csv_field_sous_categ = my_strdup (gsb_data_category_get_sub_category_name (category_number,
696 																									   sub_category_number,
697 																									   NULL));
698 						}
699 					}
700 				}
701 
702 				/* met les notes de la ventilation */
703 				if (gsb_data_transaction_get_notes (pSplitTransaction))
704 				{
705 					CSV_CLEAR_FIELD (csv_field_notes);
706 					csv_field_notes = my_strdup (gsb_data_transaction_get_notes (pSplitTransaction));
707 				}
708 
709 				/* met le montant de la ventilation */
710 				amount = gsb_data_transaction_get_adjusted_amount (pSplitTransaction, return_exponent);
711 				CSV_CLEAR_FIELD (csv_field_credit);
712 				CSV_CLEAR_FIELD (csv_field_debit);
713 				if (amount.mantissa >= 0)
714 					csv_field_credit = csv_real_get_string_from_us_option (amount);
715 				else
716 					csv_field_debit  = csv_real_get_string_from_us_option (gsb_real_abs (amount));
717 
718 				/* met le rapprochement */
719 				reconcile_number = gsb_data_transaction_get_reconcile_number (pSplitTransaction);
720 				if (reconcile_number)
721 				{
722 					CSV_CLEAR_FIELD (csv_field_rappro);
723 					csv_field_rappro = my_strdup (gsb_data_reconcile_get_name (reconcile_number));
724 				}
725 
726 				/* met le chèque si c'est un type à numéotation automatique */
727 				payment_method = gsb_data_transaction_get_method_of_payment_number (pSplitTransaction);
728 				if (gsb_data_payment_get_automatic_numbering (payment_method))
729 				{
730 					CSV_CLEAR_FIELD (csv_field_cheque);
731 					csv_field_cheque = my_strdup (gsb_data_transaction_get_method_of_payment_content (pSplitTransaction));
732 				}
733 
734 				/* Budgetary lines */
735 				budgetary_number = gsb_data_transaction_get_budgetary_number (pSplitTransaction);
736 				if (budgetary_number != -1)
737 				{
738 					gint sub_budgetary_number;
739 
740 					CSV_CLEAR_FIELD (csv_field_imput);
741 					csv_field_imput = my_strdup (gsb_data_budget_get_name (budgetary_number, 0, ""));
742 
743 					sub_budgetary_number = gsb_data_transaction_get_sub_budgetary_number (pSplitTransaction);
744 					if (sub_budgetary_number != -1)
745 					{
746 						CSV_CLEAR_FIELD (csv_field_sous_imput);
747 						csv_field_sous_imput = my_strdup (gsb_data_budget_get_sub_budget_name (budgetary_number,
748 																							   sub_budgetary_number,
749 																							   NULL));
750 					}
751 				}
752 
753 				/* Piece comptable */
754 				CSV_CLEAR_FIELD (csv_field_piece);
755 				csv_field_piece = my_strdup (gsb_data_transaction_get_voucher (pSplitTransaction));
756 
757 				/* Financial Year */
758 				financial_year_number = gsb_data_transaction_get_financial_year_number (pSplitTransaction);
759 				if (financial_year_number != -1)
760 				{
761 					CSV_CLEAR_FIELD (csv_field_exercice);
762 					csv_field_exercice  = my_strdup (gsb_data_fyear_get_name (financial_year_number));
763 				}
764 
765 				csv_add_record(csv_file,FALSE, print_balance);
766 			}
767 
768 			pSplitTransactionList = pSplitTransactionList->next;
769 			csv_clear_fields(TRUE);
770 	    }
771 	}
772 	else
773 	{
774 		gint contra_transaction_account;
775 
776 		contra_transaction_number = gsb_data_transaction_get_contra_transaction_number (transaction_number);
777 	    switch (contra_transaction_number)
778 	    {
779 			case 0:
780 				/* normal category */
781 				category_number = gsb_data_transaction_get_category_number (transaction_number);
782 
783 				if (category_number != -1)
784 				{
785 					gint sub_category_number;
786 
787 					CSV_CLEAR_FIELD (csv_field_categ);
788 					csv_field_categ = my_strdup (gsb_data_category_get_name (category_number, 0, ""));
789 
790 					sub_category_number = gsb_data_transaction_get_sub_category_number (transaction_number);
791 					if (sub_category_number != -1)
792 					{
793 						CSV_CLEAR_FIELD (csv_field_sous_categ);
794 						csv_field_sous_categ = my_strdup (gsb_data_category_get_sub_category_name (category_number,
795 																								   sub_category_number,
796 																								   NULL));
797 					}
798 				}
799 				break;
800 			case -1:
801 				/* transfer to deleted account */
802 				CSV_CLEAR_FIELD (csv_field_categ);
803 				csv_field_categ = my_strdup (_("Transfer"));
804 
805 				tmp_str = g_strconcat ("[", _("Deleted account"), "]", NULL);
806 				/* TODO dOm : is it necessary to duplicate memory with my_strdup since it was already newly allocated memory ? */
807 				CSV_CLEAR_FIELD (csv_field_sous_categ);
808 				csv_field_sous_categ = my_strdup (tmp_str);
809 				g_free (tmp_str);
810 
811 				break;
812 			default:
813 				/* transfer */
814 				CSV_CLEAR_FIELD (csv_field_categ);
815 				csv_field_categ = my_strdup (_("Transfer"));
816 
817 				contra_transaction_account = gsb_data_transaction_get_contra_transaction_account (transaction_number);
818 				tmp_str = g_strconcat ("[", gsb_data_account_get_name (contra_transaction_account), "]", NULL);
819 				/* TODO dOm : is it necessary to duplicate memory with my_strdup since it was already newly allocated memory ? */
820 				CSV_CLEAR_FIELD (csv_field_sous_categ);
821 				csv_field_sous_categ = my_strdup (tmp_str);
822 				g_free (tmp_str);
823 	    }
824 	    csv_add_record(csv_file,TRUE, print_balance);
825 	}
826     return TRUE;
827 }
828 
829 /**
830  *
831  *
832  * \param
833  *
834  * \return
835  **/
gsb_csv_export_tree_view_list_export_title_line(FILE * csv_file,GtkTreeView * tree_view)836 static void gsb_csv_export_tree_view_list_export_title_line (FILE *csv_file, GtkTreeView *tree_view)
837 {
838     GList *list;
839     GList *list_tmp;
840 
841     list = gtk_tree_view_get_columns (tree_view);
842     list_tmp = list;
843 
844     while (list_tmp)
845     {
846         GtkTreeViewColumn *col;
847         const gchar *text;
848 
849         col = (GtkTreeViewColumn *) list_tmp->data;
850 
851         /* get the text */
852         text = gtk_tree_view_column_get_title (col);
853 
854         CSV_STR_FIELD(csv_file, text);
855 
856         list_tmp  = list_tmp->next;
857     }
858     CSV_END_RECORD(csv_file);
859 }
860 
861 /**
862  *
863  *
864  * \param
865  *
866  * \return
867  **/
gsb_csv_export_tree_view_list_foreach_callback(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,FILE * csv_file)868 static gboolean gsb_csv_export_tree_view_list_foreach_callback (GtkTreeModel *model,
869                         GtkTreePath *path,
870                         GtkTreeIter *iter,
871                         FILE *csv_file)
872 {
873     GtkTreeView *tree_view;
874     GList *list;
875     GList *list_tmp;
876     gint depth;
877 
878     /* on n'exporte que les lignes de plus haut niveau */
879     depth = gtk_tree_path_get_depth (path);
880     if (depth > 1)
881         return FALSE;
882 
883     tree_view = g_object_get_data (G_OBJECT (model), "tree_view");
884     list = gtk_tree_view_get_columns (tree_view);
885     list_tmp = list;
886 
887     while (list_tmp)
888     {
889         GtkTreeViewColumn *col;
890         gchar *text;
891         gint col_num_model;
892         GType col_type_model;
893 
894         col = list_tmp->data;
895 
896         col_num_model = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (col), "num_col_model"));
897         col_type_model = gtk_tree_model_get_column_type (model, col_num_model);
898 
899         /* get the text */
900         if (col_type_model == G_TYPE_STRING)
901             gtk_tree_model_get (model, iter, col_num_model, &text, -1);
902         else if (col_type_model == G_TYPE_INT)
903         {
904             gint number;
905 
906             gtk_tree_model_get (model, iter, col_num_model, &number, -1);
907             text = utils_str_itoa (number);
908         }
909         else
910             text = NULL;
911 
912         CSV_STR_FIELD (csv_file, text);
913         CSV_CLEAR_FIELD (text);
914 
915         list_tmp  = list_tmp->next;
916     }
917 
918     CSV_END_RECORD(csv_file);
919 
920     return FALSE;
921 }
922 
923 /**
924  *
925  *
926  * \param
927  *
928  * \return
929  **/
gsb_csv_export_tree_view_list_export_rows(FILE * csv_file,GtkTreeView * tree_view)930 static void gsb_csv_export_tree_view_list_export_rows (FILE *csv_file, GtkTreeView *tree_view)
931 {
932     GtkTreeModel *model;
933 
934     model = gtk_tree_view_get_model (tree_view);
935     g_object_set_data (G_OBJECT (model), "tree_view", tree_view);
936 
937     gtk_tree_model_foreach (model,
938                         (GtkTreeModelForeachFunc) gsb_csv_export_tree_view_list_foreach_callback,
939                         csv_file);
940 
941     g_object_steal_data (G_OBJECT (model), "tree_view");
942 }
943 
944 /******************************************************************************/
945 /* Public functions                                                           */
946 /******************************************************************************/
947 /**
948  * export an account into a csv file
949  *
950  * \param filename
951  * \param account_nb the account to export
952  *
953  * \return TRUE if ok, FALSE if problem
954  * */
gsb_csv_export_account(const gchar * filename,gint account_number)955 gboolean gsb_csv_export_account (const gchar *filename, gint account_number)
956 {
957     FILE *csv_file;
958     GSList *pTransactionList;
959     GSList *tmp_list;
960 
961     csv_file = gsb_csv_export_open_file (filename);
962 
963     if (!csv_file)
964         return FALSE;
965 
966     if (g_csv_with_title_line)
967         gsb_csv_export_title_line (csv_file, TRUE);
968 
969     /* set the initial balance */
970     if (csv_field_tiers)
971         g_free (csv_field_tiers);
972 
973     csv_field_tiers = g_strconcat (_("Initial balance") , " [",
974                         gsb_data_account_get_name (account_number),
975                         "]", NULL);
976 
977     /* set the initial current_balance,
978      * as we will write all the non archived transactions,
979      * we need to get the initial balance of the account, without the archived transactions */
980     current_balance = gsb_data_account_get_init_balance (account_number, -1);
981 
982     tmp_list = gsb_data_archive_store_get_archives_list ();
983     while (tmp_list)
984     {
985         gint archive_store_number;
986 
987         archive_store_number = gsb_data_archive_store_get_number (tmp_list->data);
988 
989         if (gsb_data_archive_store_get_account_number (archive_store_number) == account_number)
990             current_balance = gsb_real_add (current_balance,
991                                 gsb_data_archive_store_get_balance (archive_store_number));
992 
993         tmp_list = tmp_list->next;
994     }
995 
996     /* ok the balance is now good, can write it */
997     CSV_CLEAR_FIELD (csv_field_solde);
998     csv_field_solde = csv_real_get_string_from_us_option (current_balance);
999     if (current_balance.mantissa >= 0)
1000     {
1001         CSV_CLEAR_FIELD (csv_field_credit);
1002         csv_field_credit = csv_real_get_string_from_us_option (current_balance);
1003     }
1004     else
1005     {
1006         CSV_CLEAR_FIELD (csv_field_debit);
1007         csv_field_debit = csv_real_get_string_from_us_option (gsb_real_abs (current_balance));
1008     }
1009 
1010     csv_add_record (csv_file, TRUE, TRUE);
1011 
1012     /* export the transactions */
1013     pTransactionList = gsb_data_transaction_get_transactions_list ();
1014     tmp_list = g_slist_sort (g_slist_copy (pTransactionList),
1015                         (GCompareFunc) gsb_csv_export_sort_by_value_date_or_date);
1016 
1017     while (tmp_list)
1018     {
1019         gint pTransaction;
1020 
1021         pTransaction = gsb_data_transaction_get_transaction_number (tmp_list->data);
1022 
1023         if (gsb_data_transaction_get_account_number (pTransaction) == account_number)
1024         {
1025             /* export the transaction */
1026             /* for now, print the balance. is this usefull ? */
1027             gsb_csv_export_transaction (pTransaction, csv_file, TRUE);
1028         }
1029 
1030         tmp_list = tmp_list->next;
1031     }
1032 
1033     fclose (csv_file);
1034     g_slist_free (tmp_list);
1035 
1036     /* return */
1037     return TRUE;
1038 }
1039 
1040 /**
1041  * export an archive into the csv format
1042  *
1043  * \param filename name of the csv file
1044  * \param archive_number the archive to export
1045  *
1046  * \return TRUE ok, FALSE problem
1047  **/
gsb_csv_export_archive(const gchar * filename,gint archive_number)1048 gboolean gsb_csv_export_archive (const gchar *filename, gint archive_number)
1049 {
1050     FILE *csv_file;
1051     GSList *pTransactionList;
1052 
1053     csv_file = gsb_csv_export_open_file (filename);
1054 
1055     if (!csv_file)
1056 	return FALSE;
1057 
1058     if (g_csv_with_title_line)
1059 	gsb_csv_export_title_line (csv_file, FALSE);
1060 
1061     /* set all the transactions for that archive */
1062     pTransactionList = gsb_data_transaction_get_complete_transactions_list ();
1063     while (pTransactionList)
1064     {
1065 	gint pTransaction = gsb_data_transaction_get_transaction_number (pTransactionList->data);
1066 
1067 	if (gsb_data_transaction_get_archive_number (pTransaction) == archive_number)
1068 	/* export the transaction */
1069 	gsb_csv_export_transaction (pTransaction, csv_file, FALSE);
1070 
1071 	pTransactionList = pTransactionList->next;
1072     }
1073     fclose (csv_file);
1074 
1075     return TRUE;
1076 }
1077 
1078 /**
1079  *
1080  *
1081  * \param
1082  *
1083  * \return
1084  **/
gsb_csv_export_tree_view_list(const gchar * filename,GtkTreeView * tree_view)1085 gboolean gsb_csv_export_tree_view_list (const gchar *filename, GtkTreeView *tree_view)
1086 {
1087     FILE *csv_file;
1088 
1089     csv_file = gsb_csv_export_open_file (filename);
1090     if (!csv_file)
1091         return FALSE;
1092 
1093     gsb_csv_export_tree_view_list_export_title_line (csv_file, tree_view);
1094     gsb_csv_export_tree_view_list_export_rows (csv_file, tree_view);
1095 
1096     fclose (csv_file);
1097 
1098     return TRUE;
1099 }
1100 
1101 /**
1102  *
1103  *
1104  * \param
1105  *
1106  * \return
1107  **/
gsb_csv_export_get_csv_separator(void)1108 gchar *gsb_csv_export_get_csv_separator (void)
1109 {
1110 	return g_csv_field_separator;
1111 }
1112 
1113 /**
1114  *
1115  *
1116  * \param
1117  *
1118  * \return
1119  **/
gsb_csv_export_set_csv_separator(const gchar * separator)1120 void gsb_csv_export_set_csv_separator (const gchar *separator)
1121 {
1122 	if (g_csv_field_separator)
1123 		g_free (g_csv_field_separator);
1124 
1125 	if (separator)
1126 		g_csv_field_separator = g_strdup (separator);
1127 	else
1128 		g_csv_field_separator = NULL;
1129 }
1130 
1131 /**
1132  *
1133  *
1134  * \param
1135  *
1136  * \return
1137  **/
1138 /* Local Variables: */
1139 /* c-basic-offset: 4 */
1140 /* End: */
1141