void tax_table_delete_entry_cb (GtkButton *button, TaxTableWindow *ttw) { g_return_if_fail (ttw); if (!ttw->current_table || !ttw->current_entry) return; if (g_list_length (gncTaxTableGetEntries (ttw->current_table)) <= 1) { char *message = _("You cannot remove the last entry from the tax table. " "Try deleting the tax table if you want to do that."); gnc_error_dialog (ttw->dialog, "%s", message); return; } if (gnc_verify_dialog (ttw->dialog, FALSE, "%s", _("Are you sure you want to delete this entry?"))) { /* Ok, let's remove it */ gnc_suspend_gui_refresh (); gncTaxTableBeginEdit (ttw->current_table); gncTaxTableRemoveEntry (ttw->current_table, ttw->current_entry); gncTaxTableEntryDestroy (ttw->current_entry); gncTaxTableChanged (ttw->current_table); gncTaxTableCommitEdit (ttw->current_table); ttw->current_entry = NULL; gnc_resume_gui_refresh (); } }
/* build a list of tax tables that are grandchildren or bogus (empty entry list). */ static void taxtable_scrub_cb (QofInstance * table_p, gpointer list_p) { GncTaxTable *table = GNC_TAXTABLE(table_p); GList **list = list_p; if (taxtable_is_grandchild(table) || gncTaxTableGetEntries(table) == NULL) *list = g_list_prepend(*list, table); }
bool GncSqlTaxTableBackend::commit (GncSqlBackend* sql_be, QofInstance* inst) { GncTaxTable* tt; const GncGUID* guid; E_DB_OPERATION op; gboolean is_infant; gboolean is_ok; g_return_val_if_fail (inst != NULL, FALSE); g_return_val_if_fail (GNC_IS_TAXTABLE (inst), FALSE); g_return_val_if_fail (sql_be != NULL, FALSE); tt = GNC_TAXTABLE (inst); is_infant = qof_instance_get_infant (inst); if (qof_instance_get_destroying (inst)) { op = OP_DB_DELETE; } else if (sql_be->pristine() || is_infant) { op = OP_DB_INSERT; } else { op = OP_DB_UPDATE; } is_ok = sql_be->do_db_operation(op, TT_TABLE_NAME, GNC_ID_TAXTABLE, tt, tt_col_table); if (is_ok) { // Now, commit or delete any slots and tax table entries guid = qof_instance_get_guid (inst); if (!qof_instance_get_destroying (inst)) { is_ok = gnc_sql_slots_save (sql_be, guid, is_infant, inst); if (is_ok) { is_ok = save_tt_entries (sql_be, guid, gncTaxTableGetEntries (tt)); } } else { is_ok = gnc_sql_slots_delete (sql_be, guid); if (is_ok) { is_ok = delete_all_tt_entries (sql_be, guid); } } } return is_ok; }
static xmlNodePtr taxtable_dom_tree_create (GncTaxTable *table) { xmlNodePtr ret, entries; GList *list; kvp_frame *kf; ret = xmlNewNode(NULL, BAD_CAST gnc_taxtable_string); xmlSetProp(ret, BAD_CAST "version", BAD_CAST taxtable_version_string); maybe_add_guid(ret, taxtable_guid_string, table); xmlAddChild(ret, text_to_dom_tree (taxtable_name_string, gncTaxTableGetName (table))); xmlAddChild(ret, int_to_dom_tree (taxtable_refcount_string, gncTaxTableGetRefcount (table))); xmlAddChild(ret, int_to_dom_tree (taxtable_invisible_string, gncTaxTableGetInvisible (table))); /* We should not be our own child */ if (gncTaxTableGetChild(table) != table) maybe_add_guid(ret, taxtable_child_string, gncTaxTableGetChild (table)); maybe_add_guid(ret, taxtable_parent_string, gncTaxTableGetParent (table)); entries = xmlNewChild (ret, NULL, BAD_CAST taxtable_entries_string, NULL); for (list = gncTaxTableGetEntries (table); list; list = list->next) { GncTaxTableEntry *entry = list->data; xmlAddChild(entries, ttentry_dom_tree_create (entry)); } kf = qof_instance_get_slots (QOF_INSTANCE(table)); if (kf) { xmlNodePtr kvpnode = kvp_frame_to_dom_tree(taxtable_slots_string, kf); if (kvpnode) { xmlAddChild(ret, kvpnode); } } return ret; }
static xmlNodePtr taxtable_dom_tree_create (GncTaxTable *table) { xmlNodePtr ret, entries; GList *list; ret = xmlNewNode(NULL, BAD_CAST gnc_taxtable_string); xmlSetProp(ret, BAD_CAST "version", BAD_CAST taxtable_version_string); maybe_add_guid(ret, taxtable_guid_string, table); xmlAddChild(ret, text_to_dom_tree (taxtable_name_string, gncTaxTableGetName (table))); xmlAddChild(ret, int_to_dom_tree (taxtable_refcount_string, gncTaxTableGetRefcount (table))); xmlAddChild(ret, int_to_dom_tree (taxtable_invisible_string, gncTaxTableGetInvisible (table))); /* We should not be our own child */ if (gncTaxTableGetChild(table) != table) maybe_add_guid(ret, taxtable_child_string, gncTaxTableGetChild (table)); maybe_add_guid(ret, taxtable_parent_string, gncTaxTableGetParent (table)); entries = xmlNewChild (ret, NULL, BAD_CAST taxtable_entries_string, NULL); for (list = gncTaxTableGetEntries (table); list; list = list->next) { GncTaxTableEntry *entry = static_cast<decltype(entry)>(list->data); xmlAddChild(entries, ttentry_dom_tree_create (entry)); } /* xmlAddChild won't do anything with a NULL, so tests are superfluous. */ xmlAddChild(ret, qof_instance_slots_to_dom_tree(taxtable_slots_string, QOF_INSTANCE(table))); return ret; }
/* * This is the logic of computing the total for an Entry, so you know * what values to put into various Splits or to display in the ledger. * In other words, we combine the quantity, unit-price, discount and * taxes together, depending on various flags. * * There are four potental ways to combine these numbers: * Discount: Pre-Tax Post-Tax * Tax : Included Not-Included * * The process is relatively simple: * * 1) compute the agregate price (price*qty) * 2) if taxincluded, then back-compute the agregate pre-tax price * 3) apply discount and taxes in the appropriate order * 4) return the requested results. * * step 2 can be done with agregate taxes; no need to compute them all * unless the caller asked for the tax_value. * * Note that the returned "value" is such that value + tax == "total * to pay," which means in the case of tax-included that the returned * "value" may be less than the agregate price, even without a * discount. If you want to display the tax-included value, you need * to add the value and taxes together. In other words, the value is * the amount the merchant gets; the taxes are the amount the gov't * gets, and the customer pays the sum or value + taxes. * * The SCU is the denominator to convert the value. * * The discount return value is just for entertainment -- you may want * to let a consumer know how much they saved. */ void gncEntryComputeValue (gnc_numeric qty, gnc_numeric price, const GncTaxTable *tax_table, gboolean tax_included, gnc_numeric discount, GncAmountType discount_type, GncDiscountHow discount_how, int SCU, gnc_numeric *value, gnc_numeric *discount_value, GList **tax_value) { gnc_numeric aggregate; gnc_numeric pretax; gnc_numeric result; gnc_numeric tax; gnc_numeric percent = gnc_numeric_create (100, 1); gnc_numeric tpercent = gnc_numeric_zero (); gnc_numeric tvalue = gnc_numeric_zero (); GList * entries = gncTaxTableGetEntries (tax_table); GList * node; /* Step 1: compute the aggregate price */ aggregate = gnc_numeric_mul (qty, price, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); /* Step 2: compute the pre-tax aggregate */ /* First, compute the aggregate tpercent and tvalue numbers */ for (node = entries; node; node = node->next) { GncTaxTableEntry *entry = node->data; gnc_numeric amount = gncTaxTableEntryGetAmount (entry); switch (gncTaxTableEntryGetType (entry)) { case GNC_AMT_TYPE_VALUE: tvalue = gnc_numeric_add (tvalue, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); break; case GNC_AMT_TYPE_PERCENT: tpercent = gnc_numeric_add (tpercent, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); break; default: g_warning ("Unknown tax type: %d", gncTaxTableEntryGetType (entry)); } } /* now we need to convert from 5% -> .05 */ tpercent = gnc_numeric_div (tpercent, percent, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); /* Next, actually compute the pre-tax aggregate value based on the * taxincluded flag. */ if (tax_table && tax_included) { /* Back-compute the pre-tax aggregate value. * We know that aggregate = pretax + pretax*tpercent + tvalue, so * pretax = (aggregate-tvalue)/(1+tpercent) */ pretax = gnc_numeric_sub (aggregate, tvalue, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); pretax = gnc_numeric_div (pretax, gnc_numeric_add (tpercent, gnc_numeric_create (1, 1), GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD), GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); } else { pretax = aggregate; } /* Step 3: apply discount and taxes in the appropriate order */ /* * There are two ways to apply discounts and taxes. In one way, you * always compute the discount off the pretax number, and compute * the taxes off of either the pretax value or "pretax-discount" * value. In the other way, you always compute the tax on "pretax", * and compute the discount on either "pretax" or "pretax+taxes". * * I don't know which is the "correct" way. */ /* * Type: discount tax * PRETAX pretax pretax-discount * SAMETIME pretax pretax * POSTTAX pretax+tax pretax */ switch (discount_how) { case GNC_DISC_PRETAX: case GNC_DISC_SAMETIME: /* compute the discount from pretax */ if (discount_type == GNC_AMT_TYPE_PERCENT) { discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); discount = gnc_numeric_mul (pretax, discount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); } result = gnc_numeric_sub (pretax, discount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); /* Figure out when to apply the tax, pretax or pretax-discount */ if (discount_how == GNC_DISC_PRETAX) pretax = result; break; case GNC_DISC_POSTTAX: /* compute discount on pretax+taxes */ if (discount_type == GNC_AMT_TYPE_PERCENT) { gnc_numeric after_tax; tax = gnc_numeric_mul (pretax, tpercent, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); after_tax = gnc_numeric_add (pretax, tax, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); after_tax = gnc_numeric_add (after_tax, tvalue, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); discount = gnc_numeric_mul (after_tax, discount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); } result = gnc_numeric_sub (pretax, discount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); break; default: g_warning ("unknown DiscountHow value: %d", discount_how); } /* Step 4: return the requested results. */ /* result == amount merchant gets * discount == amount of discount * need to compute taxes (based on 'pretax') if the caller wants it. */ if (discount_value != NULL) { if (SCU) discount = gnc_numeric_convert(discount, SCU, GNC_HOW_RND_ROUND); *discount_value = discount; } if (value != NULL) { if (SCU) result = gnc_numeric_convert(result, SCU, GNC_HOW_RND_ROUND); *value = result; } /* Now... Compute the list of tax values (if the caller wants it) */ if (tax_value != NULL) { GList * taxes = NULL; for (node = entries; node; node = node->next) { GncTaxTableEntry *entry = node->data; Account *acc = gncTaxTableEntryGetAccount (entry); gnc_numeric amount = gncTaxTableEntryGetAmount (entry); g_return_if_fail (acc); switch (gncTaxTableEntryGetType (entry)) { case GNC_AMT_TYPE_VALUE: if (SCU) amount = gnc_numeric_convert(amount, SCU, GNC_HOW_RND_ROUND); taxes = gncAccountValueAdd (taxes, acc, amount); break; case GNC_AMT_TYPE_PERCENT: amount = gnc_numeric_div (amount, percent, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); tax = gnc_numeric_mul (pretax, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); if (SCU) tax = gnc_numeric_convert(tax, SCU, GNC_HOW_RND_ROUND); taxes = gncAccountValueAdd (taxes, acc, tax); break; default: break; } } *tax_value = taxes; } return; }
static void tax_table_entries_refresh (TaxTableWindow *ttw) { GList *list, *node; GtkTreeView *view; GtkListStore *store; GtkTreeIter iter; GtkTreePath *path; GtkTreeSelection *selection; GtkTreeRowReference *reference = NULL; GncTaxTableEntry *selected_entry; g_return_if_fail (ttw); view = GTK_TREE_VIEW (ttw->entries_view); store = GTK_LIST_STORE(gtk_tree_view_get_model(view)); /* Clear the list */ selected_entry = ttw->current_entry; gtk_list_store_clear (store); if (ttw->current_table == NULL) return; /* Add the items to the list */ list = gncTaxTableGetEntries (ttw->current_table); if (list) list = g_list_reverse (g_list_copy (list)); for (node = list ; node; node = node->next) { char *row_text[3]; GncTaxTableEntry *entry = node->data; Account *acc = gncTaxTableEntryGetAccount (entry); gnc_numeric amount = gncTaxTableEntryGetAmount (entry); row_text[0] = gnc_account_get_full_name (acc); switch (gncTaxTableEntryGetType (entry)) { case GNC_AMT_TYPE_PERCENT: row_text[1] = g_strdup_printf ("%s%%", xaccPrintAmount (amount, gnc_default_print_info (FALSE))); break; default: row_text[1] = g_strdup_printf ("%s", xaccPrintAmount (amount, gnc_default_print_info (TRUE))); break; } gtk_list_store_prepend(store, &iter); gtk_list_store_set(store, &iter, TAX_ENTRY_COL_NAME, row_text[0], TAX_ENTRY_COL_POINTER, entry, TAX_ENTRY_COL_AMOUNT, row_text[1], -1); if (entry == selected_entry) { path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter); reference = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), path); gtk_tree_path_free(path); } g_free (row_text[0]); g_free (row_text[1]); } if (reference) { path = gtk_tree_row_reference_get_path(reference); gtk_tree_row_reference_free(reference); if (path) { selection = gtk_tree_view_get_selection(view); gtk_tree_selection_select_path(selection, path); gtk_tree_view_scroll_to_cell(view, path, NULL, TRUE, 0.5, 0.0); gtk_tree_path_free(path); } } }