GnuCash  5.6-150-g038405b370+
gnc-locale-tax.c
1 /*********************************************************************
2  * gnc-locale-tax.c
3  * hack to load the proper guile based tax system
4  *
5  * Copyright (c) 2019 Geert Janssens <geert@kobaltwit.be>
6  *********************************************************************/
7 /********************************************************************\
8  * This program is free software; you can redistribute it and/or *
9  * modify it under the terms of the GNU General Public License as *
10  * published by the Free Software Foundation; either version 2 of *
11  * the License, or (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License*
19  * along with this program; if not, contact: *
20  * *
21  * Free Software Foundation Voice: +1-617-542-5942 *
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
23  * Boston, MA 02110-1301, USA gnu@gnu.org *
24  * *
25 \********************************************************************/
26 
27 
28 #include <config.h>
29 #include <string.h>
30 #include <locale.h>
31 #include <libguile.h>
32 #include <glib.h>
33 #include <glib/gi18n.h>
34 #include <Account.h>
35 #include <gnc-ui-util.h>
36 #include <guile-mappings.h>
37 #include <gnc-guile-utils.h>
38 #include "gnc-locale-tax.h"
39 
40 
41 
42 void
43 gnc_locale_tax_init(void)
44 {
45  /* This is a very simple hack that loads the (new, special) German
46  tax definition file in a German locale, or (default) loads the
47  US tax file. */
48 # ifdef G_OS_WIN32
49  gchar *thislocale = g_win32_getlocale();
50  gboolean is_de_DE = (strncmp(thislocale, "de_DE", 5) == 0);
51  g_free(thislocale);
52 # else /* !G_OS_WIN32 */
53  const char *thislocale = setlocale(LC_ALL, NULL);
54  gboolean is_de_DE = (strncmp(thislocale, "de_DE", 5) == 0);
55 # endif /* G_OS_WIN32 */
56  if (is_de_DE)
57  scm_c_use_module("gnucash locale de_DE tax");
58  else
59  scm_c_use_module("gnucash locale us tax");
60 }
61 
62 /* Caller is responsible for g_free'ing returned memory */
63 char *
64 gnc_ui_account_get_tax_info_string (const Account *account)
65 {
66  static SCM get_form = SCM_UNDEFINED;
67  static SCM get_desc = SCM_UNDEFINED;
68 
69  gboolean tax_related = FALSE;
70  const char *code;
71 
72  if (!account)
73  return NULL;
74 
75  tax_related = xaccAccountGetTaxRelated (account);
76  code = xaccAccountGetTaxUSCode (account);
77 
78  if (!code)
79  {
80  if (!tax_related)
81  return NULL;
82  /* tax_related && !code */
83  else
84  /* Translators: This and the following strings appear on
85  the account tab if the Tax Info column is displayed,
86  i.e. if the user wants to record the tax form number
87  and location on that tax form which corresponds to this
88  gnucash account. For the US Income Tax support in
89  gnucash, each tax code that can be assigned to an
90  account generally corresponds to a specific line number
91  on a paper form and each form has a unique
92  identification (e.g., Form 1040, Schedule A). */
93  return g_strdup (_("Tax-related but has no tax code"));
94  }
95  else /* with tax code */
96  {
97  const gchar *tax_type;
98  GNCAccountType atype;
99  SCM tax_entity_type;
100  SCM category;
101  gchar *num_code = NULL;
102  const gchar *prefix = "N";
103  gchar *return_string = NULL;
104 
105  tax_type = gnc_get_current_book_tax_type ();
106  if (tax_type == NULL || (g_strcmp0 (tax_type, "") == 0))
107  return g_strdup (_("Tax entity type not specified"));
108 
109  atype = xaccAccountGetType (account);
110  tax_entity_type = scm_from_utf8_string (tax_type);
111 
112  if (get_form == SCM_UNDEFINED)
113  {
114  /* load the tax info */
115  gnc_locale_tax_init ();
116 
117  get_form = scm_c_eval_string
118  ("(false-if-exception gnc:txf-get-form)");
119  get_desc = scm_c_eval_string
120  ("(false-if-exception gnc:txf-get-description)");
121  }
122 
123  g_return_val_if_fail (scm_is_procedure (get_form), NULL);
124  g_return_val_if_fail (scm_is_procedure (get_desc), NULL);
125 
126  category = scm_c_eval_string (atype == ACCT_TYPE_INCOME ?
127  "txf-income-categories" :
128  (atype == ACCT_TYPE_EXPENSE ?
129  "txf-expense-categories" :
130  (((atype == ACCT_TYPE_BANK) ||
131  (atype == ACCT_TYPE_CASH) ||
132  (atype == ACCT_TYPE_ASSET) ||
133  (atype == ACCT_TYPE_STOCK) ||
134  (atype == ACCT_TYPE_MUTUAL) ||
135  (atype == ACCT_TYPE_RECEIVABLE)) ?
136  "txf-asset-categories" :
137  (((atype == ACCT_TYPE_CREDIT) ||
138  (atype == ACCT_TYPE_LIABILITY) ||
139  (atype == ACCT_TYPE_EQUITY) ||
140  (atype == ACCT_TYPE_PAYABLE)) ?
141  "txf-liab-eq-categories" : ""))));
142 
143  if (g_str_has_prefix (code, prefix))
144  {
145  const gchar *num_code_tmp;
146  num_code_tmp = g_strdup (code);
147  num_code_tmp++; /* to lose the leading N */
148  num_code = g_strdup (num_code_tmp);
149  num_code_tmp--;
150  g_free ((gpointer *) num_code_tmp);
151  }
152  else
153  {
154  num_code = g_strdup (code);
155  }
156 
157  if (category == SCM_UNDEFINED)
158  {
159  if (tax_related)
160  return_string = g_strdup_printf
161  (_("Tax type %s: invalid code %s for account type"),
162  tax_type, num_code);
163  else
164  return_string = g_strdup_printf
165  (_("Not tax-related; tax type %s: invalid code %s for account type"),
166  tax_type, num_code);
167  }
168  else
169  {
170  SCM code_scm;
171  SCM form_scm;
172  code_scm = scm_from_locale_symbol (code);
173  form_scm = scm_call_3 (get_form, category, code_scm, tax_entity_type);
174  if (!scm_is_string (form_scm))
175  {
176  if (tax_related)
177  return_string = g_strdup_printf
178  (_("Invalid code %s for tax type %s"),
179  num_code, tax_type);
180  else
181  return_string = g_strdup_printf
182  (_("Not tax-related; invalid code %s for tax type %s"),
183  num_code, tax_type);
184  }
185  else
186  {
187  gchar *form = NULL;
188 
189  /* Note: using scm_to_utf8_stringn directly here instead
190  of our wrapper gnc_scm_to_utf8_string. 'form' should
191  be freed with 'free' instead of 'g_free'. This will
192  be taken care of automatically during scm_dynwind_end,
193  because we inform guile of this memory allocation via
194  scm_dynwind_free a little further. */
195  form = scm_to_utf8_stringn (form_scm, NULL);
196  if (!form)
197  {
198  if (tax_related)
199  return_string = g_strdup_printf
200  (_("No form: code %s, tax type %s"), num_code,
201  tax_type);
202  else
203  return_string = g_strdup_printf
204  (_("Not tax-related; no form: code %s, tax type %s"),
205  num_code, tax_type);
206  }
207  else
208  {
209  SCM desc_scm;
210 
211  /* Create a dynwind context because we will be calling (scm) functions
212  that potentially exit non-locally */
213  scm_dynwind_begin (0);
214  scm_dynwind_free (form);
215  desc_scm = scm_call_3 (get_desc, category, code_scm,
216  tax_entity_type);
217  if (!scm_is_string (desc_scm))
218  {
219  if (tax_related)
220  return_string = g_strdup_printf
221  (_("No description: form %s, code %s, tax type %s"),
222  form, num_code, tax_type);
223  else
224  return_string = g_strdup_printf
225  (_("Not tax-related; no description: form %s, code %s, tax type %s"),
226  form, num_code, tax_type);
227  }
228  else
229  {
230  gchar *desc = NULL;
231  desc = gnc_scm_to_utf8_string (desc_scm);
232  if (!desc)
233  {
234  if (tax_related)
235  return_string = g_strdup_printf
236  (_("No description: form %s, code %s, tax type %s"),
237  form, num_code, tax_type);
238  else
239  return_string = g_strdup_printf
240  (_("Not tax-related; no description: form %s, code %s, tax type %s"),
241  form, num_code, tax_type);
242  }
243  else
244  {
245  gint64 copy_number;
246  gchar *copy_txt = NULL;
247  copy_number = xaccAccountGetTaxUSCopyNumber (account);
248  copy_txt = (copy_number == 1) ?
249  g_strdup ("") :
250  g_strdup_printf ("(%d)",
251  (gint) copy_number);
252  if (tax_related)
253  {
254  if (g_strcmp0 (form, "") == 0)
255  return_string = g_strdup_printf ("%s", desc);
256  else
257  return_string = g_strdup_printf ("%s%s: %s",
258  form, copy_txt, desc);
259  }
260  else
261  {
262  return_string = g_strdup_printf
263  (_("Not tax-related; %s%s: %s (code %s, tax type %s)"),
264  form, copy_txt, desc, num_code, tax_type);
265  }
266  g_free (copy_txt);
267  }
268  g_free (desc);
269  }
270  scm_dynwind_end ();
271  }
272  }
273  }
274  g_free (num_code);
275  return return_string;
276  }
277 }
278 
279 /* Caller is responsible for g_free'ing returned memory */
280 char *
281 gnc_ui_account_get_tax_info_sub_acct_string (const Account *account)
282 {
283  GList *descendant, *account_descendants;
284 
285  if (!account)
286  return NULL;
287 
288  account_descendants = gnc_account_get_descendants (account);
289  if (account_descendants)
290  {
291  gint sub_acct_tax_number = 0;
292  for (descendant = account_descendants; descendant;
293  descendant = g_list_next(descendant))
294  {
295  if (xaccAccountGetTaxRelated (descendant->data))
296  sub_acct_tax_number++;
297  }
298  g_list_free (account_descendants);
299  g_list_free (descendant);
300  /* Translators: This and the following strings appear on
301  the account tab if the Tax Info column is displayed,
302  i.e. if the user wants to record the tax form number
303  and location on that tax form which corresponds to this
304  gnucash account. For the US Income Tax support in
305  gnucash, each tax code that can be assigned to an
306  account generally corresponds to a specific line number
307  on a paper form and each form has a unique
308  identification (e.g., Form 1040, Schedule A). */
309  return (sub_acct_tax_number == 0) ? NULL :
310  g_strdup_printf (_("(Tax-related subaccounts: %d)"),
311  sub_acct_tax_number);
312  }
313  else
314  return NULL;
315 }
gint64 xaccAccountGetTaxUSCopyNumber(const Account *acc)
Returns copy_number stored in KVP; if KVP doesn&#39;t exist or copy_number is zero, returns 1...
Definition: Account.cpp:4026
utility functions for the GnuCash UI
Expense accounts are used to denote expenses.
Definition: Account.h:143
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3237
STRUCTS.
Mutual Fund accounts will typically be shown in registers which show three columns: price...
Definition: Account.h:125
The cash account type is used to denote a shoe-box or pillowcase stuffed with * cash.
Definition: Account.h:110
Stock accounts will typically be shown in registers which show three columns: price, number of shares, and value.
Definition: Account.h:122
Account handling public routines.
Income accounts are used to denote income.
Definition: Account.h:140
The bank account type denotes a savings or checking account held at a bank.
Definition: Account.h:107
A/P account type.
Definition: Account.h:151
const char * xaccAccountGetTaxUSCode(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:4002
gboolean xaccAccountGetTaxRelated(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:3990
asset (and liability) accounts indicate generic, generalized accounts that are none of the above...
Definition: Account.h:116
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed...
Definition: Account.h:101
GList * gnc_account_get_descendants(const Account *account)
This routine returns a flat list of all of the accounts that are descendants of the specified account...
Definition: Account.cpp:3014
liability (and asset) accounts indicate generic, generalized accounts that are none of the above...
Definition: Account.h:119
A/R account type.
Definition: Account.h:149
Equity account is used to balance the balance sheet.
Definition: Account.h:146
The Credit card account is used to denote credit (e.g.
Definition: Account.h:113