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