taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

078-taxes.rst (13205B)


      1 DD 78: Taxes
      2 ############
      3 
      4 :Design status: Accepted
      5 :Implementation status: Partial
      6 :DD shepherd: TBD
      7 :Historical contributors: Christian Grothoff
      8 :First published: 2025-12-22
      9 :Last substantive change: 2025-12-26
     10 :Implementation evidence: ``merchant`` (2025-12-27; 2025-12-28; 2025-12-29) implements the product-group and money-pot foundation; tax rules remain future work
     11 :Normative references: ``core/api-merchant.rst`` (product groups, money pots, and upcoming ``vTAXES``)
     12 
     13 Summary
     14 =======
     15 
     16 We've received various requests for the merchant backend to provide
     17 transaction reports for accountants. While not always stated explicitly, we
     18 believe this is largely also related to tax reporting. This document explains
     19 the plan for tax calculation and tax data; periodic report delivery is covered
     20 by DD 79.
     21 
     22 Motivation
     23 ==========
     24 
     25 Making tax-reporting easy for merchants will lower the barrier for them to
     26 adopt GNU Taler.  Furthermore, customers will often require receipts which
     27 state the specific tax amounts that were paid, so including tax information in
     28 digital receipts (and thus the Taler contracts) is important.  The current
     29 situation where taxes are specified per-product is not great, as a merchant
     30 would have to update all products if a tax-percentage were to change, and also
     31 has to re-calculate the tax every time a product price changes.
     32 
     33 
     34 Requirements
     35 ============
     36 
     37 * Deal with the complexity of tax calculations across different jurisdictions.
     38   Sure, we may not cover all cases globally, but we should at least cover the
     39   most common scenarios.  This likely includes different ways how taxes
     40   should be computed in terms of rounding, and computing taxes given
     41   prices in gross or net amounts.
     42 * Make it as easy as possible for the merchant to manage taxes.  If possible,
     43   have some backend-wide defaults so that merchants do not have to enter
     44   common taxes that apply across the currency domain.
     45 * Ensure customers get correct tax receipts as part of their contracts.
     46 * Incorporate the tax data when informing the merchant about their transaction
     47   history, including showing which taxes applied to which purchases so that
     48   merchants can easily account for applicable taxes.
     49 * Treat *donations* and *gifts* as a special-cases as again special tax
     50   rules likely apply.
     51 * A single product may have multiple applicable taxes (say VAT and luxury
     52   tax).
     53 * A single order may contain multiple products (some with known tax
     54   rules and others without) and thus a mix of applicable taxes.
     55 * A merchant may need to override or adapt the tax details for each
     56   order, for example because reverse VAT rules may shift the responsibility
     57   to pay taxes to the buyer.
     58 
     59 
     60 Proposed Solution
     61 =================
     62 
     63 We borrow ideas from ERPnext.
     64 
     65 Phase 1: Products groups
     66 ------------------------
     67 
     68 This is inspired by ERPnext's "item groups".
     69 
     70 A **product group** allows multiple products to be treated in the
     71 same way for accounting and tax purposes, avoiding the need to
     72 configure each product individually.
     73 
     74 There can only be one group per product, all products that are not explicitly
     75 in a group should be in some ``__default__`` group that always exists. The
     76 product groups will be used for sales statistics (revenue per group) and will
     77 be the basis for associating taxes with products in the next phase(s).
     78 
     79 Unlike categories, product group membership is mutually exclusive and not used
     80 for the point-of-sale app display. Re-using categories would confuse a feature
     81 for taxes/accounting with a feature for user-interfaces of sales people.
     82 
     83 * Add a ``product_group`` table with:
     84 
     85      (0) product group serial number
     86      (1) instance ID (foreign key)
     87      (2) product group name (unique with instance ID)
     88      (3) product group description
     89 
     90 * Expand ``inventory_products`` table with:
     91 
     92      (1) product group serial number (foreign key), allow NULL for default
     93      (2) price_is_net boolean flag to indicate if the given price is the net
     94          price and all taxes should be added on top of it, or if it is a
     95          fixed retail price and the merchant covers all applicable taxes,
     96          at the expense of profits if taxes vary (for example, to preserve
     97          the price structure even if taxes vary between dine-in and take-out).
     98 
     99 
    100 Phase 2: Money pots
    101 -------------------
    102 
    103 This is inspired by ERPnext's "accounts".
    104 
    105 A **money pot** allow users aggregate amounts over time periods for accounting.
    106 
    107 Money pots can be for different types of taxes, but also for tips or to
    108 separate out different kinds of internal accounts as well as fees paid to the
    109 exchange.
    110 
    111 When an order is created, the total amount paid by the customer will be split
    112 into the various money pots based on rules that can be given per product,
    113 product group or taxes, and also later overriden explicitly in the contract
    114 terms.
    115 
    116 The increments to the various pots will also be shown in the various accounting
    117 statistics.
    118 
    119 * Add a ``money_pot`` table with:
    120 
    121      (0) money pot serial number
    122      (1) instance ID (foreign key)
    123      (2) money pot name (unique with instance ID)
    124      (3) money pot description
    125      (4) money pot total amount
    126 
    127 * Code should update statistics whenever the money pot
    128   total amount is incremented.
    129 
    130 
    131 
    132 Phase 3: Tax Class
    133 ------------------
    134 
    135 This is inspired by ERPnext's "item tax templates".
    136 
    137 A **tax class** specifies a possible tax and how it is to be calculated for a
    138 given product or order.
    139 
    140 * Add a ``tax_class`` table with:
    141 
    142     (0) tax class serial number
    143     (1) instance ID (foreign key)
    144     (2) tax class name (unique with instance ID)
    145     (3) tax rate (percentage), for taxes charged per value
    146     (4) charge amount (multiplied with quantity of the product,
    147         for example for tourist overnight tax per night,
    148         for taxes charged per unit and not per value)
    149     (5) tax description
    150     (6) i18n description
    151     (7) calculation mode (net total, cummulative)
    152     (8) rounding mode (up, down, nearest)
    153     (9) rounding unit (amount)
    154     (10) money pot (where to accumulate taxes paid under this tax class).
    155          to track known tax rules.
    156          Unique should be "instance+tax class name".
    157 
    158 * When "rounding up" is used, round up from net to gross, but round
    159   down from gross to net. Similarly, when "rounding down" is used,
    160   round down from net to gross, but round up from gross to net.
    161   Finally, "round-to-nearest" implies rounding in the same way for
    162   both conversion directions, and rounding up from the exact
    163   mid-point between multiples of the rounding unit.
    164 
    165 * When cummulative calculation is used, the order in which tax classes
    166   are applied starts to matter. This will become important when defining
    167   tax rules later.
    168 
    169 * Orders can specify that a particular tax class and amount is to
    170   be applied to specific products or to the entire order,
    171   but not both. In this case, the backend adds the exact
    172   amounts to the contract terms and the respective pot-statistics.
    173 
    174 * Orders can specify that only a particular tax class is to be applied
    175   to a product or the entire order, but without giving the tax amount.
    176   In this case, the backend computes the applicable
    177   tax and adds the exact amounts to the contract terms and the
    178   respective pot-statistics. It is also possible that for some products
    179   in the order the frontend calculated the exact amount, while for
    180   others the calculation is left to the backend.
    181 
    182 * When generating the contract terms, append the tax class details
    183   of applicable taxes (rates, descriptions) from the database
    184   to the contract.
    185 
    186 * Allow the client to define and use additional custom tax classes
    187   per order.
    188 
    189 * Add new configuration sections "[taxes-$ID]" that specify common tax
    190   classes (name and description as string) and rates (floating point)
    191   and per-quantity charges (amount) with calculation and rounding mode
    192   that should be automatically provided to all instances. When creating
    193   a new instance, populate the tax class table with these values.  Add a
    194   command-line tool to add all configured taxes to all existing
    195   instances (for example, to update default taxes for the next year).
    196 
    197 * When an order is paid, make sure to add the tax totals to each
    198   of the money pots.
    199 
    200 * For tipping, specifying a "tax" ``tip-$STAFF`` with a custom amount can
    201   thus be easily assigned to the tip money pot of ``$STAFF``.
    202 
    203 Phase 4: Tax Rules
    204 ------------------
    205 
    206 This is inspired by ERPnext's "tax rules".
    207 
    208 A **tax rule** specifies whether a tax class applies to a particular
    209 product, group of products, or order.
    210 
    211 * There should be an optional ``__fallback__`` tax rule that is applied to all
    212   orders and products that do not match a specific rule.
    213 
    214 * Except for the ``__fallback__`` tax rule, it is possible that multiple
    215   tax rules apply, in which case they *all* apply at the same time.
    216   Only the "fallback" rule only applies if no other rules apply.
    217 
    218 * Add a table "tax_rules" with
    219 
    220   (0) tax rule serial number
    221   (1) instance ID (foreign key)
    222   (2) tax rule name (unique with instance ID), ``__fallback__`` is reserved
    223       for the fallback rule
    224   (3) tax class serial number (foreign key)
    225   (4) filter: array of product group serial IDs, NULL for all, [] for none
    226   (5) filter: array of product ID serial IDs, NULL for all, [] for none
    227   (6) filter: total_only (boolean), true if the tax rule only applies to the
    228       final total of the order, and not individual products; if total_only
    229       is true, then the product and product group arrays MUST both be empty
    230 
    231   In the future, we *may* want to expand this to add per-order filters,
    232   like on the shipping address; however, for now we will limit the
    233   filters to make this more implementable.
    234 
    235 * Orders can specify an *array* of tax rules (by tax rule name)
    236   to apply to each product or the entire order (depending on the
    237   filter of the tax rule). In this case, the tax rules are applied
    238   in the sequence specified in the array to compute which
    239   tax classes to apply to each product or the entire order.
    240   Tax rules must not be specified when an order already specifies
    241   a tax class for the entire order.
    242 
    243 * However, it is possible to specify tax classes for some products
    244   and then tax rules would still apply for other products
    245   or the entire order. But if a product in the order is specified
    246   as having an explicit tax class, the order-wide product-specific
    247   tax rules will no longer apply to it.  Order-wide tax rules
    248   on the order total would still be applied.
    249 
    250 * If a tax rule is specified for an order but it does not
    251   apply to the order or a product in it, the rule is simply
    252   ignored.
    253 
    254 
    255 
    256 Phase 5: Tax Regimes
    257 --------------------
    258 
    259 This is inspired by ERPnext's "tax categories".
    260 
    261 A **tax regime** determines which set of tax rules to apply in
    262 which order (with cummulative taxes, the order may matter).
    263 The idea here is that for some customers or transactions completely
    264 different sets of rules may apply, but still the sets of rules
    265 are frequently the same.
    266 
    267 * There should be a "default" tax regime that is applied to all
    268   orders where the client did not specify a tax regime.
    269   Basically, not specified implies ``__default__``. However, if
    270   a default tax regime is not configured, this is not an error
    271   and simply no taxes are applied.
    272 
    273 * Add a table "tax_regime" with
    274 
    275   (0) tax regime serial number
    276   (1) instance ID (foreign key)
    277   (2) tax regime name (unique with instance ID), ``__default__`` is reserved
    278       for the default regime
    279   (3) array of applicable tax rules
    280 
    281 * Orders can specify a tax regime instead of an array of
    282   tax rules. In this case, the array of tax rules is simply
    283   obtained from the tax regime.
    284 
    285 * Orders that specify a tax regime must not also specify an
    286   array of tax rules.
    287 
    288 
    289 Test Plan
    290 =========
    291 
    292 * Unit tests for the rounding functions.
    293 * Shell-script tests for the CRUD API on taxes and automatic
    294   import of tax classes from the configuration.
    295 * Shell-script tests to check tax calculations in created orders
    296   and to test statistics on taxes paid.
    297 * Manual tests for SPA.
    298 * Manual tests on PDF report generation.
    299 * Manual tests on rendering taxes in wallets.
    300 
    301 
    302 Definition of Done
    303 ==================
    304 
    305 The product-group and money-pot foundation has landed.  The tax protocol is
    306 still listed as upcoming, so the tax-specific items below remain incomplete.
    307 
    308 * [ ] Specification promoted from upcoming to current
    309 * [ ] Database updated with tax definitions
    310 * [ ] Merchant backend updated:
    311 
    312   * CRUD API for tax definitions
    313   * INI-based tax class importer
    314   * CRUD API update for product management
    315   * Order creation update
    316   * Statistics update on order paid
    317 
    318 * [ ] Merchant backend SPA updated:
    319 
    320   * CRUD for tax class definitions
    321   * CRUD for associating tax classes with products
    322   * Order creation with tax-class override (at least for the entire order,
    323     not necessarily per-product)
    324   * Statistics page rendering tax statistics
    325 
    326 * [ ] Wallets updated to render taxes (upon request, in detailed view
    327   on payment or from order history)
    328 
    329 
    330 Alternatives
    331 ============
    332 
    333 Communism? Crypto-anarchy?
    334 
    335 
    336 Drawbacks
    337 =========
    338 
    339 * Quite a bit of extra complexity
    340 
    341 
    342 Discussion / Q&A
    343 ================
    344 
    345 (This should be filled in with results from discussions on mailing lists / personal communication.)