1 /* ************************************************************************** */
2 /* */
3 /* Copyright (C) 2000-2008 Cédric Auger (cedric@grisbi.org) */
4 /* 2003-2008 Benjamin Drieu (bdrieu@april.org) */
5 /* https://www.grisbi.org */
6 /* */
7 /* This program is free software; you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation; either version 2 of the License, or */
10 /* (at your option) any later version. */
11 /* */
12 /* This program is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
15 /* GNU General Public License for more details. */
16 /* */
17 /* You should have received a copy of the GNU General Public License */
18 /* along with this program; if not, write to the Free Software */
19 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
20 /* */
21 /* ************************************************************************** */
22
23 /**
24 * \file gsb_data_reconciliation.c
25 * work with the reconciliation structure, no GUI here
26 */
27
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "include.h"
34 #include <string.h>
35
36 /*START_INCLUDE*/
37 #include "gsb_data_reconcile.h"
38 #include "dialog.h"
39 #include "gsb_data_transaction.h"
40 #include "gsb_transactions_list.h"
41 #include "gsb_real.h"
42 #include "utils_dates.h"
43 #include "utils_str.h"
44 /*END_INCLUDE*/
45
46 /** \struct describe an reconciliation operation */
47 typedef struct _ReconcileStruct ReconcileStruct;
48
49 struct _ReconcileStruct
50 {
51 gint reconcile_number;
52 gchar *reconcile_name;
53 gint account_number;
54
55 GDate *reconcile_init_date;
56 GDate *reconcile_final_date;
57
58 GsbReal reconcile_init_balance;
59 GsbReal reconcile_final_balance;
60 };
61
62
63 /*START_STATIC*/
64 /*END_STATIC*/
65
66 /*START_EXTERN*/
67 /*END_EXTERN*/
68
69
70 /** contains a g_list of ReconcileStruct */
71 static GList *reconcile_list;
72
73 /** a pointer to the last reconcile used (to increase the speed) */
74 static ReconcileStruct *reconcile_buffer;
75
76 /******************************************************************************/
77 /* Private functions */
78 /******************************************************************************/
79 /**
80 * This function is called to free the memory used by a ReconcileStruct structure
81 *
82 * \param
83 *
84 * \return
85 **/
_gsb_data_reconcile_free(ReconcileStruct * reconcile)86 static void _gsb_data_reconcile_free (ReconcileStruct *reconcile)
87 {
88 if (!reconcile)
89 return;
90 g_free (reconcile->reconcile_name);
91 if (reconcile->reconcile_init_date)
92 g_date_free (reconcile->reconcile_init_date);
93 if (reconcile->reconcile_final_date)
94 g_date_free (reconcile->reconcile_final_date);
95
96 g_free (reconcile);
97 if (reconcile_buffer == reconcile)
98 reconcile_buffer = NULL;
99 }
100
101 /**
102 * compare deux rapprochements par date
103 *
104 * \param reconcile_1
105 * \param reconcile_2
106 *
107 * \return 0 -1 1 comme strcmp
108 **/
gsb_data_reconcile_cmp_int(ReconcileStruct * reconcile_1,ReconcileStruct * reconcile_2)109 static gint gsb_data_reconcile_cmp_int (ReconcileStruct *reconcile_1,
110 ReconcileStruct *reconcile_2)
111 {
112 gint result;
113
114 if (!reconcile_1->reconcile_final_date)
115 return -1;
116 else if (!reconcile_2->reconcile_final_date)
117 return 1;
118 else
119 result = g_date_compare (reconcile_1->reconcile_final_date,
120 reconcile_2->reconcile_final_date);
121 if (result == 0)
122 return reconcile_1->reconcile_number - reconcile_2->reconcile_number;
123 else
124 return result;
125 }
126
127 /**
128 * find and return the structure of the reconcile asked
129 *
130 * \param reconcile_number number of reconcile
131 *
132 * \return the adr of the struct of the reconcile (NULL if doesn't exit)
133 **/
gsb_data_reconcile_get_structure(gint reconcile_number)134 static gpointer gsb_data_reconcile_get_structure (gint reconcile_number)
135 {
136 GList *tmp;
137
138 if (!reconcile_number)
139 return NULL;
140
141 /* before checking all the reconciles, we check the buffer */
142 if (reconcile_buffer
143 &&
144 reconcile_buffer->reconcile_number == reconcile_number)
145 return reconcile_buffer;
146
147 tmp = reconcile_list;
148 while (tmp)
149 {
150 ReconcileStruct *reconcile;
151
152 reconcile = tmp->data;
153
154 if (reconcile->reconcile_number == reconcile_number)
155 {
156 reconcile_buffer = reconcile;
157 return reconcile;
158 }
159 tmp = tmp->next;
160 }
161 return NULL;
162 }
163
164 /******************************************************************************/
165 /* Public functions */
166 /******************************************************************************/
167 /**
168 * set the reconciles global variables to NULL, usually when we init all the global variables
169 *
170 * \param none
171 *
172 * \return FALSE
173 **/
gsb_data_reconcile_init_variables(void)174 gboolean gsb_data_reconcile_init_variables (void)
175 {
176 if (reconcile_list)
177 {
178 GList* tmp_list;
179
180 tmp_list = reconcile_list;
181 while (tmp_list)
182 {
183 ReconcileStruct *reconcile;
184
185 reconcile = tmp_list->data;
186 tmp_list = tmp_list->next;
187 _gsb_data_reconcile_free (reconcile);
188 }
189 g_list_free (reconcile_list);
190 }
191 reconcile_list = NULL;
192 reconcile_buffer = NULL;
193 return FALSE;
194 }
195
196 /**
197 * return the number of the reconcile given in param
198 *
199 * \param reconcile_ptr a pointer to the struct of the reconcile
200 *
201 * \return the number of the reconcile, 0 if problem
202 **/
gsb_data_reconcile_get_no_reconcile(gpointer reconcile_ptr)203 gint gsb_data_reconcile_get_no_reconcile (gpointer reconcile_ptr)
204 {
205 ReconcileStruct *reconcile;
206
207 if (!reconcile_ptr)
208 return 0;
209
210 reconcile = reconcile_ptr;
211 reconcile_buffer = reconcile;
212 return reconcile->reconcile_number;
213 }
214
215 /**
216 * give the g_list of reconcile structure
217 *
218 * \param none
219 *
220 * \return the g_list of reconciles structure
221 **/
gsb_data_reconcile_get_reconcile_list(void)222 GList *gsb_data_reconcile_get_reconcile_list (void)
223 {
224 return reconcile_list;
225 }
226
227 /**
228 * find and return the last number of reconcile
229 *
230 * \param none
231 *
232 * \return last number of reconcile
233 **/
gsb_data_reconcile_max_number(void)234 gint gsb_data_reconcile_max_number (void)
235 {
236 GList *tmp;
237 gint number_tmp = 0;
238
239 tmp = reconcile_list;
240
241 while (tmp)
242 {
243 ReconcileStruct *reconcile;
244
245 reconcile = tmp->data;
246
247 if (reconcile->reconcile_number > number_tmp)
248 number_tmp = reconcile->reconcile_number;
249
250 tmp = tmp->next;
251 }
252 return number_tmp;
253 }
254
255 /**
256 * create a new reconcile, give it a number, append it to the list
257 * and return the number
258 *
259 * \param name the name of the reconcile (can be freed after, it's a copy) or NULL
260 *
261 * \return the number of the new reconcile or 0 if memory problem (a message will be showed)
262 **/
gsb_data_reconcile_new(const gchar * name)263 gint gsb_data_reconcile_new (const gchar *name)
264 {
265 ReconcileStruct *reconcile;
266
267 reconcile = g_malloc0 (sizeof (ReconcileStruct));
268 if (!reconcile)
269 {
270 dialogue_error_memory ();
271 return 0;
272 }
273
274 reconcile->reconcile_number = gsb_data_reconcile_max_number () + 1;
275 reconcile->reconcile_name = my_strdup (name);
276 reconcile_list = g_list_append (reconcile_list, reconcile);
277
278 return reconcile->reconcile_number;
279 }
280
281 /**
282 * remove a reconcile
283 * all the transactions marked by that reconcile will be marked P
284 * and lose the link to that reconcile
285 *
286 * \param reconcile_number the reconcile we want to remove
287 *
288 * \return TRUE ok
289 **/
gsb_data_reconcile_remove(gint reconcile_number)290 gboolean gsb_data_reconcile_remove (gint reconcile_number)
291 {
292 ReconcileStruct *reconcile;
293 GSList *list_tmp;
294
295 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
296
297 if (!reconcile)
298 return FALSE;
299
300 reconcile_list = g_list_remove (reconcile_list, reconcile);
301 _gsb_data_reconcile_free (reconcile);
302
303 /* remove that reconcile of the transactions */
304 list_tmp = gsb_data_transaction_get_complete_transactions_list ();
305
306 while (list_tmp)
307 {
308 gint transaction_number;
309
310 transaction_number = gsb_data_transaction_get_transaction_number (list_tmp->data);
311 if (gsb_data_transaction_get_reconcile_number (transaction_number) == reconcile_number)
312 {
313 gsb_data_transaction_set_reconcile_number (transaction_number, 0);
314 gsb_data_transaction_set_marked_transaction (transaction_number, OPERATION_POINTEE);
315 gsb_transactions_list_update_transaction (transaction_number);
316 }
317 list_tmp = list_tmp->next;
318 }
319
320 return TRUE;
321 }
322
323 /**
324 * set a new number for the reconcile
325 * normally used only while loading the file because
326 * the number are given automaticly
327 *
328 * \param reconcile_number the number of the reconcile
329 * \param new_no_reconcile the new number of the reconcile
330 *
331 * \return the new number or 0 if the reconcile doen't exist
332 **/
gsb_data_reconcile_set_new_number(gint reconcile_number,gint new_no_reconcile)333 gint gsb_data_reconcile_set_new_number (gint reconcile_number,
334 gint new_no_reconcile)
335 {
336 ReconcileStruct *reconcile;
337
338 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
339
340 if (!reconcile)
341 return 0;
342
343 reconcile->reconcile_number = new_no_reconcile;
344 return new_no_reconcile;
345 }
346
347 /**
348 * return the name of the reconcile
349 *
350 * \param reconcile_number the number of the reconcile
351 *
352 * \return the name of the reconcile or NULL if problem
353 **/
gsb_data_reconcile_get_name(gint reconcile_number)354 const gchar *gsb_data_reconcile_get_name (gint reconcile_number)
355 {
356 ReconcileStruct *reconcile;
357
358 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
359
360 if (!reconcile)
361 return NULL;
362
363 return reconcile->reconcile_name;
364 }
365
366 /**
367 * set the name of the reconcile
368 * the value is dupplicate in memory (so parameter can be freed after)
369 *
370 * \param reconcile_number the number of the reconcile
371 * \param name the name of the reconcile
372 *
373 * \return TRUE if ok or FALSE if problem
374 **/
gsb_data_reconcile_set_name(gint reconcile_number,const gchar * name)375 gboolean gsb_data_reconcile_set_name (gint reconcile_number,
376 const gchar *name)
377 {
378 ReconcileStruct *reconcile;
379
380 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
381
382 if (!reconcile)
383 return FALSE;
384
385 /* we free the last name */
386 if (reconcile->reconcile_name)
387 g_free (reconcile->reconcile_name);
388
389 /* and copy the new one */
390 reconcile->reconcile_name = my_strdup (name);
391
392 return TRUE;
393 }
394
395 /**
396 * return the number of the reconcile which has the name in param
397 * create it if necessary
398 *
399 * \param name the name of the reconcile
400 *
401 * \return the number of the reconcile or 0 if doesn't exist
402 **/
gsb_data_reconcile_get_number_by_name(const gchar * name)403 gint gsb_data_reconcile_get_number_by_name (const gchar *name)
404 {
405 GList *list_tmp;
406
407 if (!name || strlen (name) == 0)
408 return FALSE;
409
410 list_tmp = reconcile_list;
411
412 while (list_tmp)
413 {
414 ReconcileStruct *reconcile;
415
416 reconcile = list_tmp->data;
417 if (reconcile->reconcile_name
418 && strlen (reconcile->reconcile_name) == 0
419 && strcmp (reconcile->reconcile_name, name) == 0)
420 {
421 return (reconcile->reconcile_number);
422 }
423
424 list_tmp = list_tmp->next;
425 }
426
427 return FALSE;
428 }
429
430 /**
431 * return the account number of the reconcile
432 *
433 * \param account number the number of the reconcile
434 *
435 * \return the account number of the reconcile or -1 if problem
436 **/
gsb_data_reconcile_get_account(gint reconcile_number)437 gint gsb_data_reconcile_get_account (gint reconcile_number)
438 {
439 ReconcileStruct *reconcile;
440
441 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
442
443 if (!reconcile)
444 return -1;
445
446 return reconcile->account_number;
447 }
448
449 /**
450 * set the account number of the reconcile
451 *
452 * \param reconcile_number the number of the reconcile
453 * \param account_number the account number of the reconcile
454 *
455 * \return TRUE if ok or FALSE if problem
456 **/
gsb_data_reconcile_set_account(gint reconcile_number,gint account_number)457 gboolean gsb_data_reconcile_set_account (gint reconcile_number,
458 gint account_number)
459 {
460 ReconcileStruct *reconcile;
461
462 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
463
464 if (!reconcile)
465 return FALSE;
466
467 /* and copy the new one */
468 reconcile->account_number = account_number;
469
470 return TRUE;
471 }
472
473 /**
474 * return the init_date of the reconcile
475 *
476 * \param reconcile_number the number of the reconcile
477 *
478 * \return the init_date of the reconcile or NULL if problem
479 **/
gsb_data_reconcile_get_init_date(gint reconcile_number)480 const GDate *gsb_data_reconcile_get_init_date (gint reconcile_number)
481 {
482 ReconcileStruct *reconcile;
483
484 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
485
486 if (!reconcile)
487 return NULL;
488
489 return reconcile->reconcile_init_date;
490 }
491
492 /**
493 * set the init_date of the reconcile
494 * the value is dupplicate in memory (so parameter can be freed after)
495 *
496 * \param reconcile_number the number of the reconcile
497 * \param date the init_date of the reconcile
498 *
499 * \return TRUE if ok or FALSE if problem
500 **/
gsb_data_reconcile_set_init_date(gint reconcile_number,const GDate * date)501 gboolean gsb_data_reconcile_set_init_date (gint reconcile_number,
502 const GDate *date)
503 {
504 ReconcileStruct *reconcile;
505
506 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
507
508 if (!reconcile)
509 return FALSE;
510
511 /* we free the last date */
512 if (reconcile->reconcile_init_date)
513 g_date_free (reconcile->reconcile_init_date);
514
515 /* and copy the new one */
516 reconcile->reconcile_init_date = gsb_date_copy (date);
517
518 return TRUE;
519 }
520
521 /**
522 * return the final_date of the reconcile
523 *
524 * \param reconcile_number the number of the reconcile
525 *
526 * \return the final_date of the reconcile or NULL if problem
527 **/
gsb_data_reconcile_get_final_date(gint reconcile_number)528 const GDate *gsb_data_reconcile_get_final_date (gint reconcile_number)
529 {
530 ReconcileStruct *reconcile;
531
532 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
533
534 if (!reconcile)
535 return NULL;
536
537 return reconcile->reconcile_final_date;
538 }
539
540 /**
541 * set the final_date of the reconcile
542 * the value is dupplicate in memory (so parameter can be freed after)
543 *
544 * \param reconcile_number the number of the reconcile
545 * \param date the final_date of the reconcile
546 *
547 * \return TRUE if ok or FALSE if problem
548 **/
gsb_data_reconcile_set_final_date(gint reconcile_number,const GDate * date)549 gboolean gsb_data_reconcile_set_final_date (gint reconcile_number,
550 const GDate *date)
551 {
552 ReconcileStruct *reconcile;
553
554 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
555
556 if (!reconcile)
557 return FALSE;
558
559 /* we free the last date */
560 if (reconcile->reconcile_final_date)
561 g_date_free (reconcile->reconcile_final_date);
562
563 /* and copy the new one */
564 reconcile->reconcile_final_date = gsb_date_copy (date);
565
566 /* retrie la liste */
567 reconcile_list = g_list_sort (reconcile_list, (GCompareFunc) gsb_data_reconcile_cmp_int);
568
569 return TRUE;
570 }
571
572 /**
573 * return the init_amount of the reconcile
574 *
575 * \param reconcile_number the number of the reconcile
576 *
577 * \return the init_amount of the reconcile or null_real if problem
578 **/
gsb_data_reconcile_get_init_balance(gint reconcile_number)579 GsbReal gsb_data_reconcile_get_init_balance (gint reconcile_number)
580 {
581 ReconcileStruct *reconcile;
582
583 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
584
585 if (!reconcile)
586 return null_real;
587
588 return reconcile->reconcile_init_balance;
589 }
590
591 /**
592 * set the init_amount of the reconcile
593 *
594 * \param reconcile_number the number of the reconcile
595 * \param amount the init_amount of the reconcile
596 *
597 * \return TRUE if ok or FALSE if problem
598 **/
gsb_data_reconcile_set_init_balance(gint reconcile_number,GsbReal amount)599 gboolean gsb_data_reconcile_set_init_balance (gint reconcile_number,
600 GsbReal amount)
601 {
602 ReconcileStruct *reconcile;
603
604 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
605
606 if (!reconcile)
607 return FALSE;
608
609 reconcile->reconcile_init_balance = amount;
610
611 return TRUE;
612 }
613
614 /**
615 * return the final_amount of the reconcile
616 *
617 * \param reconcile_number the number of the reconcile
618 *
619 * \return the final balance of the reconcile or null_real if problem
620 **/
gsb_data_reconcile_get_final_balance(gint reconcile_number)621 GsbReal gsb_data_reconcile_get_final_balance (gint reconcile_number)
622 {
623 ReconcileStruct *reconcile;
624
625 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
626
627 if (!reconcile)
628 return null_real;
629
630 return reconcile->reconcile_final_balance;
631 }
632
633 /**
634 * set the final_amount of the reconcile
635 *
636 * \param reconcile_number the number of the reconcile
637 * \param amount the final_amount of the reconcile
638 *
639 * \return TRUE if ok or FALSE if problem
640 **/
gsb_data_reconcile_set_final_balance(gint reconcile_number,GsbReal amount)641 gboolean gsb_data_reconcile_set_final_balance (gint reconcile_number,
642 GsbReal amount)
643 {
644 ReconcileStruct *reconcile;
645
646 reconcile = gsb_data_reconcile_get_structure (reconcile_number);
647
648 if (!reconcile)
649 return FALSE;
650
651 reconcile->reconcile_final_balance = amount;
652
653 return TRUE;
654 }
655
656 /**
657 * find the last reconcile number for the given account
658 *
659 * \param account_number
660 *
661 * \return the last reconcile number for that account, 0 if none found
662 **/
gsb_data_reconcile_get_account_last_number(gint account_number)663 gint gsb_data_reconcile_get_account_last_number (gint account_number)
664 {
665 GList *rec_list;
666 GList *tmp_list;
667 gint result = 0;
668
669 rec_list = gsb_data_reconcile_get_sort_reconcile_list (account_number);
670 tmp_list = g_list_last (rec_list);
671 if (tmp_list)
672 result = GPOINTER_TO_INT (tmp_list->data);
673
674 g_list_free (rec_list);
675
676 return result;
677 }
678
679 /**
680 * try to find a reconcile which contains the date given in param
681 * for the given account
682 *
683 * \param date
684 * \param account_number
685 *
686 * \return the number of the found reconcile or 0 if not found
687 **/
gsb_data_reconcile_get_number_by_date(const GDate * date,gint account_number)688 gint gsb_data_reconcile_get_number_by_date (const GDate *date,
689 gint account_number)
690 {
691 GList *tmp_list;
692
693 if (!date || !g_date_valid (date))
694 return 0;
695
696 /* check all the reconciles */
697 tmp_list = reconcile_list;
698 while (tmp_list)
699 {
700 ReconcileStruct *reconcile;
701
702 reconcile = tmp_list->data;
703
704 if (reconcile->account_number == account_number
705 && g_date_compare (reconcile->reconcile_init_date, date) <= 0
706 && g_date_compare (date, reconcile->reconcile_final_date) <= 0)
707 {
708 return reconcile->reconcile_number;
709 }
710 tmp_list = tmp_list->next;
711 }
712 return 0;
713 }
714
715 /**
716 * renvoie la liste des rapprochements triée par date pour un compte donné
717 *
718 * \param account_number
719 *
720 * \return the reconcile list for that account
721 **/
gsb_data_reconcile_get_sort_reconcile_list(gint account_number)722 GList *gsb_data_reconcile_get_sort_reconcile_list (gint account_number)
723 {
724 GList *tmp_list;
725 GList *rec_list = NULL;
726 GList *new_list = NULL;
727 ReconcileStruct *reconcile;
728
729 /* first we localize the GList struct of that reconcile */
730 tmp_list = reconcile_list;
731 while (tmp_list)
732 {
733 reconcile = tmp_list->data;
734
735 if (reconcile->account_number == account_number)
736 {
737 rec_list = g_list_insert_sorted (rec_list,
738 reconcile,
739 (GCompareFunc) gsb_data_reconcile_cmp_int);
740 }
741
742 tmp_list = tmp_list->next;
743 }
744
745 tmp_list = rec_list;
746 while (tmp_list)
747 {
748 reconcile = tmp_list->data;
749
750 new_list = g_list_append (new_list, GINT_TO_POINTER (reconcile->reconcile_number));
751 tmp_list = tmp_list->next;
752 }
753
754 g_list_free (rec_list);
755
756 return new_list;
757 }
758
759 /**
760 *
761 *
762 * \param
763 *
764 * \return
765 **/
gsb_data_reconcile_renum_account_number_0(gint new_account_number)766 void gsb_data_reconcile_renum_account_number_0 (gint new_account_number)
767 {
768 GList *tmp_list;
769
770 tmp_list = gsb_data_reconcile_get_reconcile_list ();
771 while (tmp_list)
772 {
773 ReconcileStruct *reconcile;
774
775 reconcile = tmp_list->data;
776 if (reconcile->account_number == 0)
777 {
778 reconcile->account_number = new_account_number;
779 }
780 tmp_list = tmp_list->next;
781 }
782 }
783
784 /**
785 *
786 *
787 * \param
788 *
789 * \return
790 **/
791 /* Local Variables: */
792 /* c-basic-offset: 4 */
793 /* End: */
794