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