Initial commit: L10N_Europe packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:52 +02:00
commit 9803722600
2377 changed files with 380711 additions and 0 deletions

View file

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
from . import report
from . import wizard
from odoo import api, SUPERUSER_ID
def load_translations(env):
env.ref('l10n_ch.l10nch_chart_template').process_coa_translations()
def init_settings(env):
'''If the company is localized in Switzerland, activate the cash rounding by default.
'''
# The cash rounding is activated by default only if the company is localized in Switzerland or Liechtenstein.
for company in env['res.company'].search([('partner_id.country_id.code', 'in', ["CH", "LI"])]):
res_config_id = env['res.config.settings'].create({
'company_id': company.id,
'group_cash_rounding': True
})
# We need to call execute, otherwise the "implied_group" in fields are not processed.
res_config_id.execute()
def post_init(cr, registry):
env = api.Environment(cr, SUPERUSER_ID, {})
load_translations(env)
init_settings(env)

View file

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
# Main contributor: Nicolas Bessi. Camptocamp SA
# Financial contributors: Hasa SA, Open Net SA,
# Prisme Solutions Informatique SA, Quod SA
# Translation contributors: brain-tec AG, Agile Business Group
{
'name': "Switzerland - Accounting",
'description': """
Swiss localization
==================
This module defines a chart of account for Switzerland (Swiss PME/KMU 2015), taxes and enables the generation of ISR and QR-bill when you print an invoice or send it by mail.
An ISR will be generated if you specify the information it needs :
- The bank account you expect to be paid on must be set, and have a valid postal reference.
- Your invoice must have been set assigned a bank account to receive its payment
(this can be done manually, but a default value is automatically set if you have defined a bank account).
- You must have set the postal references of your bank.
- Your invoice must be in EUR or CHF (as ISRs do not accept other currencies)
A QR-bill will be generated if:
- The partner set on your invoice has a complete address (street, city, postal code and country) in Switzerland
- The option to generate the Swiss QR-code is selected on the invoice (done by default)
- A correct account number/QR IBAN is set on your bank journal
- (when using a QR-IBAN): the payment reference of the invoice is a QR-reference
The generation of the ISR and QR-bill is automatic if you meet the previous criteria.
Here is how it works:
- Printing the invoice will trigger the download of three files: the invoice, its ISR and its QR-bill
- Clicking the 'Send by mail' button will attach three files to your draft mail : the invoice, the ISR and the QR-bill.
""",
'version': '11.2',
'category': 'Accounting/Localizations/Account Charts',
'depends': ['account', 'l10n_multilang', 'base_iban', 'l10n_din5008'],
'data': [
'security/ir.model.access.csv',
'data/l10n_ch_chart_data.xml',
'data/account.account.template.csv',
'data/l10n_ch_chart_post_data.xml',
'data/account_tax_group_data.xml',
'data/account_tax_report_data.xml',
'data/account_vat2011_data.xml',
'data/account_tax_template_data_2024.xml',
'data/account_fiscal_position_data.xml',
'data/account_fiscal_position_data_2024.xml',
'data/account_chart_template_data.xml',
'report/isr_report.xml',
'report/swissqr_report.xml',
'views/res_bank_view.xml',
'views/account_invoice_view.xml',
'views/account_invoice.xml',
'views/res_config_settings_views.xml',
'views/setup_wizard_views.xml',
'views/qr_invoice_wizard_view.xml'
],
'demo': [
'demo/account_cash_rounding.xml',
'demo/demo_company.xml',
'demo/res_partner_demo.xml',
],
'post_init_hook': 'post_init',
'assets': {
'web.report_assets_common': [
'l10n_ch/static/src/scss/**/*',
],
},
'license': 'LGPL-3',
}

View file

@ -0,0 +1,171 @@
"id","name","code","account_type","chart_template_id/id","reconcile"
"ch_coa_1060","Securities (with stock exchange price)","1060","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1069","Accumulated depreciation on securities","1069","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1091","Transfer account: Salaries","1091","asset_current","l10n_ch.l10nch_chart_template","True"
"ch_coa_1099","Transfer account: miscellaneous","1099","asset_current","l10n_ch.l10nch_chart_template","True"
"ch_coa_1100","Accounts receivable from goods and services (Debtors)","1100","asset_receivable","l10n_ch.l10nch_chart_template","True"
"ch_coa_1101","Receivable (PoS)","1101","asset_receivable","l10n_ch.l10nch_chart_template","True"
"ch_coa_1109","Del credere (Acc. depr. on debtors)","1109","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1140","Advances and loans","1140","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1149","Advances and loans adjustments","1149","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1170","Input Tax (VAT) receivable on material, goods, services, energy","1170","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1171","Input Tax (VAT) receivable on investments, other operating expenses","1171","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1176","Withholding Tax (WT) receivable","1176","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1180","Receivables from social insurances and social security institutions","1180","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1189","Withholding tax","1189","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1190","Other short-term receivables","1190","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1199","Accumulated depreciation on short-terms receivables","1199","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1200","Goods / Merchandise (Trade)","1200","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1207","Accumulated depreciation on Goods / Merchandise (Trade)","1207","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1208","Downpayment on Goods / Merchandise (Trade)","1208","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1209","Correction on Goods / Merchandise (Trade)","1209","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1210","Raw materials","1210","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1217","Accumulated depreciation on raw material","1217","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1218","Downpayment on raw material","1218","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1219","Correction on raw material","1219","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1220","Auxiliary material","1220","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1230","Consumables","1230","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1250","Consignments Goods ","1250","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1260","Finished products","1260","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1267","Accumulated depreciation on Finished products","1267","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1269","Correction on Finished products","1269","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1270","Products in process / Unfinished products","1270","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1277","Accumulated depreciation on Products in process / Unfinished products","1277","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1279","Correction on Products in process / Unfinished products","1279","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1280","Work in progress","1280","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1287","Accumulated depreciation on work in progress","1287","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1289","Correction on work in progress","1289","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1300","Accrued revenue and deferred expense (Accounts paid in advance)","1300","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1301","Deferred expense (Accounts paid in advance)","1301","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1400","Long-term securities","1400","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1409","Accumulated depreciation on long-term securities","1409","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1440","Loan (Asset)","1440","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1441","Mortgages","1441","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1449","Accumulated depreciation on long term receivables","1449","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1480","Participations","1480","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1489","Accumulated depreciation on participations","1489","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1500","Machinery","1500","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1509","Accumulated depreciation on machinery","1509","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1510","Equipment","1510","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1519","Accumulated depreciation on equipment","1519","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1520","Office Equipment (including Information & Communication Technology)","1520","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1529","Accumulated depreciation on office equipment (incl. ICT)","1529","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1530","Vehicles","1530","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1539","Accumulated depreciation on vehicles","1539","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1540","Tools","1540","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1549","Accumulated depreciation on tools","1549","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1550","Warehouse","1550","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1559","Accumulated depreciation on warehouse","1559","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1570","Equipments and Facilities","1570","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1579","Accumulated depreciation on Equipments and Facilities","1579","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1590","Other movable tangible assets","1590","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1599","Accumulated depreciation on Other movable tangible assets","1599","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1600","Real Estate","1600","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1609","Accumulated depreciation on real estate","1609","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1700","Patents, Licences","1700","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1709","Accumulated depreciation on Patents, Licences","1709","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1770","Goodwill","1770","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1779","Accumulated depreciation on goodwill","1779","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1850","Non-paid-in share capital","1850","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2000","Accounts payable from goods and services (Creditors)","2000","liability_payable","l10n_ch.l10nch_chart_template","True"
"ch_coa_2030","Prepayments received","2030","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2100","Bank Overdraft (Bank)","2100","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2120","Leasing bondings","2120","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2140","Other interest-bearing short terms liabilities","2140","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2160","Dettes envers l'actionnaire","2160","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2200","Sales Tax (VAT) owed","2200","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2201","VAT payable","2201","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2206","Withholding Tax (WT) owed","2206","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2208","Direct Taxes","2208","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2210","Others short term liabilities","2210","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2261","Dividend payouts resolved (Dividends)","2261","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2270","Social insurances owed","2270","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2279","Withholding taxes","2279","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2300","Deferred revenue and accrued expenses (Accounts received in advance)","2300","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2301","Deferred revenue (Accounts Received in Advance)","2301","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2330","Short-term provisions","2330","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2400","Bank debts","2400","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2420","Finance lease commitments","2420","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2430","Debentures","2430","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2450","Loans","2450","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2451","Mortgages","2451","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2500","Other long term liabilities","2500","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2600","Long-term provisions","2600","liability_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_2800","Share capital","2800","equity","l10n_ch.l10nch_chart_template","False"
"ch_coa_2900","Legal capital reserves","2900","equity","l10n_ch.l10nch_chart_template","False"
"ch_coa_2940","Valuation Reserves","2940","equity","l10n_ch.l10nch_chart_template","False"
"ch_coa_2950","Legal retained earnings (Reserves)","2950","equity","l10n_ch.l10nch_chart_template","False"
"ch_coa_2960","Voluntary retained earnings","2960","equity","l10n_ch.l10nch_chart_template","False"
"ch_coa_2970","Profits brought forward / Losses brought forward","2970","equity","l10n_ch.l10nch_chart_template","False"
"ch_coa_2979","Annual profit or annual loss","2979","equity","l10n_ch.l10nch_chart_template","False"
"ch_coa_2980","Treasury stock, shares, participation rights (negative item) ","2980","equity","l10n_ch.l10nch_chart_template","False"
"ch_coa_3000","Sales of products (Manufacturing)","3000","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3009","Deductions on sales","3009","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3200","Sales of goods (Trade)","3200","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3400","Revenues from services","3400","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3600","Other revenues","3600","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3700","Own services","3700","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3710","Own consumption","3710","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3800","Financial discount","3800","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3801","Discounts and price reduction","3801","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3802","Rebates","3802","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3803","Third-party commissions","3803","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3804","Collection fees","3804","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3805","Losses from bad debts","3805","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3806","Exchange rate differences","3806","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3807","Shipping & Returns","3807","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3900","Changes in inventories of unfinished and finished products","3900","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3901","Change in inventories of finished goods","3901","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_3940","Change in the value of unbilled services","3940","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_4000","Cost of raw materials (Manufacturing)","4000","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4008","Inventory changes","4008","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4009","Deductions obtained on purchases","4009","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4070","Purchase Loans","4070","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4071","Customs duties on importation","4071","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4072","Transport costs at purchase","4072","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4080","Inventory changes","4080","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4086","Loss of material","4086","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4200","Cost of materials (Trade)","4200","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4400","Cost of purchased services","4400","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4500","Electricity","4500","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4510","Gas","4510","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4520","Fuel oil","4520","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4521","Coal, briquettes, wood","4521","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4530","Petrol","4530","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4540","Water","4540","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4800","Change in inventories of goods","4800","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4801","Change in raw material inventories","4801","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4900","Financial Discounts","4900","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4901","Discounts and price reductions","4901","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4991","Cash Difference Loss","4991","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4992","Cash Difference Gain","4992","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_4092","Rebates","4902","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4903","Commissions on purchases","4903","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_4906","Exchange rate differences","4906","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_5000","Wages and salaries","5000","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_5700","Social benefits","5700","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_5800","Other staff cost","5800","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_5900","Temporary staff expenditures","5900","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6000","Rent","6000","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6100","Maintenance & repair expenses","6100","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6105","Leasing movable tangible fixed assets","6105","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6200","Vehicle expenses","6200","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6260","Vehicules leasing and renting","6260","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6300","Insurance premiums","6300","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6400","Energy expenses & disposal expenses","6400","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6500","Administration expenses","6500","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6570","IT leasing","6570","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6600","Promotion and advertising expenses","6600","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6700","Other operating expenses","6700","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6800","Depreciations","6800","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6900","Financial expenses (Interest expenses, Securities expenses, Participations expenses)","6900","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_6950","Financial revenues (Interest revenues, Securities revenues, Participations revenues)","6950","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_7000","Non-core business revenues","7000","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_7010","Non-core business expenses","7010","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_7500","Revenues from operational real estate","7500","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_7510","Expenses from operational real estate","7510","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_8000","Non-operational expenses","8000","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_8100","Non-operational revenues","8100","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_8500","Extraordinary expenses","8500","expense","l10n_ch.l10nch_chart_template","False"
"ch_coa_8510","Extraordinary revenues","8510","income","l10n_ch.l10nch_chart_template","False"
"ch_coa_8900","Direct Taxes","8900","expense","l10n_ch.l10nch_chart_template","False"
1 id name code account_type chart_template_id/id reconcile
2 ch_coa_1060 Securities (with stock exchange price) 1060 asset_current l10n_ch.l10nch_chart_template False
3 ch_coa_1069 Accumulated depreciation on securities 1069 asset_current l10n_ch.l10nch_chart_template False
4 ch_coa_1091 Transfer account: Salaries 1091 asset_current l10n_ch.l10nch_chart_template True
5 ch_coa_1099 Transfer account: miscellaneous 1099 asset_current l10n_ch.l10nch_chart_template True
6 ch_coa_1100 Accounts receivable from goods and services (Debtors) 1100 asset_receivable l10n_ch.l10nch_chart_template True
7 ch_coa_1101 Receivable (PoS) 1101 asset_receivable l10n_ch.l10nch_chart_template True
8 ch_coa_1109 Del credere (Acc. depr. on debtors) 1109 asset_current l10n_ch.l10nch_chart_template False
9 ch_coa_1140 Advances and loans 1140 asset_current l10n_ch.l10nch_chart_template False
10 ch_coa_1149 Advances and loans adjustments 1149 asset_current l10n_ch.l10nch_chart_template False
11 ch_coa_1170 Input Tax (VAT) receivable on material, goods, services, energy 1170 asset_current l10n_ch.l10nch_chart_template False
12 ch_coa_1171 Input Tax (VAT) receivable on investments, other operating expenses 1171 asset_current l10n_ch.l10nch_chart_template False
13 ch_coa_1176 Withholding Tax (WT) receivable 1176 asset_current l10n_ch.l10nch_chart_template False
14 ch_coa_1180 Receivables from social insurances and social security institutions 1180 asset_current l10n_ch.l10nch_chart_template False
15 ch_coa_1189 Withholding tax 1189 asset_current l10n_ch.l10nch_chart_template False
16 ch_coa_1190 Other short-term receivables 1190 asset_current l10n_ch.l10nch_chart_template False
17 ch_coa_1199 Accumulated depreciation on short-terms receivables 1199 asset_current l10n_ch.l10nch_chart_template False
18 ch_coa_1200 Goods / Merchandise (Trade) 1200 asset_current l10n_ch.l10nch_chart_template False
19 ch_coa_1207 Accumulated depreciation on Goods / Merchandise (Trade) 1207 asset_current l10n_ch.l10nch_chart_template False
20 ch_coa_1208 Downpayment on Goods / Merchandise (Trade) 1208 asset_current l10n_ch.l10nch_chart_template False
21 ch_coa_1209 Correction on Goods / Merchandise (Trade) 1209 asset_current l10n_ch.l10nch_chart_template False
22 ch_coa_1210 Raw materials 1210 asset_current l10n_ch.l10nch_chart_template False
23 ch_coa_1217 Accumulated depreciation on raw material 1217 asset_current l10n_ch.l10nch_chart_template False
24 ch_coa_1218 Downpayment on raw material 1218 asset_current l10n_ch.l10nch_chart_template False
25 ch_coa_1219 Correction on raw material 1219 asset_current l10n_ch.l10nch_chart_template False
26 ch_coa_1220 Auxiliary material 1220 asset_current l10n_ch.l10nch_chart_template False
27 ch_coa_1230 Consumables 1230 asset_current l10n_ch.l10nch_chart_template False
28 ch_coa_1250 Consignments Goods 1250 asset_current l10n_ch.l10nch_chart_template False
29 ch_coa_1260 Finished products 1260 asset_current l10n_ch.l10nch_chart_template False
30 ch_coa_1267 Accumulated depreciation on Finished products 1267 asset_current l10n_ch.l10nch_chart_template False
31 ch_coa_1269 Correction on Finished products 1269 asset_current l10n_ch.l10nch_chart_template False
32 ch_coa_1270 Products in process / Unfinished products 1270 asset_current l10n_ch.l10nch_chart_template False
33 ch_coa_1277 Accumulated depreciation on Products in process / Unfinished products 1277 asset_current l10n_ch.l10nch_chart_template False
34 ch_coa_1279 Correction on Products in process / Unfinished products 1279 asset_current l10n_ch.l10nch_chart_template False
35 ch_coa_1280 Work in progress 1280 asset_current l10n_ch.l10nch_chart_template False
36 ch_coa_1287 Accumulated depreciation on work in progress 1287 asset_current l10n_ch.l10nch_chart_template False
37 ch_coa_1289 Correction on work in progress 1289 asset_current l10n_ch.l10nch_chart_template False
38 ch_coa_1300 Accrued revenue and deferred expense (Accounts paid in advance) 1300 asset_current l10n_ch.l10nch_chart_template False
39 ch_coa_1301 Deferred expense (Accounts paid in advance) 1301 asset_current l10n_ch.l10nch_chart_template False
40 ch_coa_1400 Long-term securities 1400 asset_current l10n_ch.l10nch_chart_template False
41 ch_coa_1409 Accumulated depreciation on long-term securities 1409 asset_current l10n_ch.l10nch_chart_template False
42 ch_coa_1440 Loan (Asset) 1440 asset_current l10n_ch.l10nch_chart_template False
43 ch_coa_1441 Mortgages 1441 asset_current l10n_ch.l10nch_chart_template False
44 ch_coa_1449 Accumulated depreciation on long term receivables 1449 asset_current l10n_ch.l10nch_chart_template False
45 ch_coa_1480 Participations 1480 asset_current l10n_ch.l10nch_chart_template False
46 ch_coa_1489 Accumulated depreciation on participations 1489 asset_current l10n_ch.l10nch_chart_template False
47 ch_coa_1500 Machinery 1500 asset_current l10n_ch.l10nch_chart_template False
48 ch_coa_1509 Accumulated depreciation on machinery 1509 asset_current l10n_ch.l10nch_chart_template False
49 ch_coa_1510 Equipment 1510 asset_current l10n_ch.l10nch_chart_template False
50 ch_coa_1519 Accumulated depreciation on equipment 1519 asset_current l10n_ch.l10nch_chart_template False
51 ch_coa_1520 Office Equipment (including Information & Communication Technology) 1520 asset_current l10n_ch.l10nch_chart_template False
52 ch_coa_1529 Accumulated depreciation on office equipment (incl. ICT) 1529 asset_current l10n_ch.l10nch_chart_template False
53 ch_coa_1530 Vehicles 1530 asset_current l10n_ch.l10nch_chart_template False
54 ch_coa_1539 Accumulated depreciation on vehicles 1539 asset_current l10n_ch.l10nch_chart_template False
55 ch_coa_1540 Tools 1540 asset_current l10n_ch.l10nch_chart_template False
56 ch_coa_1549 Accumulated depreciation on tools 1549 asset_current l10n_ch.l10nch_chart_template False
57 ch_coa_1550 Warehouse 1550 asset_current l10n_ch.l10nch_chart_template False
58 ch_coa_1559 Accumulated depreciation on warehouse 1559 asset_current l10n_ch.l10nch_chart_template False
59 ch_coa_1570 Equipments and Facilities 1570 asset_current l10n_ch.l10nch_chart_template False
60 ch_coa_1579 Accumulated depreciation on Equipments and Facilities 1579 asset_current l10n_ch.l10nch_chart_template False
61 ch_coa_1590 Other movable tangible assets 1590 asset_current l10n_ch.l10nch_chart_template False
62 ch_coa_1599 Accumulated depreciation on Other movable tangible assets 1599 asset_current l10n_ch.l10nch_chart_template False
63 ch_coa_1600 Real Estate 1600 asset_current l10n_ch.l10nch_chart_template False
64 ch_coa_1609 Accumulated depreciation on real estate 1609 asset_current l10n_ch.l10nch_chart_template False
65 ch_coa_1700 Patents, Licences 1700 asset_current l10n_ch.l10nch_chart_template False
66 ch_coa_1709 Accumulated depreciation on Patents, Licences 1709 asset_current l10n_ch.l10nch_chart_template False
67 ch_coa_1770 Goodwill 1770 asset_current l10n_ch.l10nch_chart_template False
68 ch_coa_1779 Accumulated depreciation on goodwill 1779 asset_current l10n_ch.l10nch_chart_template False
69 ch_coa_1850 Non-paid-in share capital 1850 asset_current l10n_ch.l10nch_chart_template False
70 ch_coa_2000 Accounts payable from goods and services (Creditors) 2000 liability_payable l10n_ch.l10nch_chart_template True
71 ch_coa_2030 Prepayments received 2030 liability_current l10n_ch.l10nch_chart_template False
72 ch_coa_2100 Bank Overdraft (Bank) 2100 liability_current l10n_ch.l10nch_chart_template False
73 ch_coa_2120 Leasing bondings 2120 liability_current l10n_ch.l10nch_chart_template False
74 ch_coa_2140 Other interest-bearing short terms liabilities 2140 liability_current l10n_ch.l10nch_chart_template False
75 ch_coa_2160 Dettes envers l'actionnaire 2160 liability_current l10n_ch.l10nch_chart_template False
76 ch_coa_2200 Sales Tax (VAT) owed 2200 liability_current l10n_ch.l10nch_chart_template False
77 ch_coa_2201 VAT payable 2201 liability_current l10n_ch.l10nch_chart_template False
78 ch_coa_2206 Withholding Tax (WT) owed 2206 liability_current l10n_ch.l10nch_chart_template False
79 ch_coa_2208 Direct Taxes 2208 liability_current l10n_ch.l10nch_chart_template False
80 ch_coa_2210 Others short term liabilities 2210 liability_current l10n_ch.l10nch_chart_template False
81 ch_coa_2261 Dividend payouts resolved (Dividends) 2261 liability_current l10n_ch.l10nch_chart_template False
82 ch_coa_2270 Social insurances owed 2270 liability_current l10n_ch.l10nch_chart_template False
83 ch_coa_2279 Withholding taxes 2279 liability_current l10n_ch.l10nch_chart_template False
84 ch_coa_2300 Deferred revenue and accrued expenses (Accounts received in advance) 2300 liability_current l10n_ch.l10nch_chart_template False
85 ch_coa_2301 Deferred revenue (Accounts Received in Advance) 2301 liability_current l10n_ch.l10nch_chart_template False
86 ch_coa_2330 Short-term provisions 2330 liability_current l10n_ch.l10nch_chart_template False
87 ch_coa_2400 Bank debts 2400 liability_current l10n_ch.l10nch_chart_template False
88 ch_coa_2420 Finance lease commitments 2420 liability_current l10n_ch.l10nch_chart_template False
89 ch_coa_2430 Debentures 2430 liability_current l10n_ch.l10nch_chart_template False
90 ch_coa_2450 Loans 2450 liability_current l10n_ch.l10nch_chart_template False
91 ch_coa_2451 Mortgages 2451 liability_current l10n_ch.l10nch_chart_template False
92 ch_coa_2500 Other long term liabilities 2500 liability_current l10n_ch.l10nch_chart_template False
93 ch_coa_2600 Long-term provisions 2600 liability_current l10n_ch.l10nch_chart_template False
94 ch_coa_2800 Share capital 2800 equity l10n_ch.l10nch_chart_template False
95 ch_coa_2900 Legal capital reserves 2900 equity l10n_ch.l10nch_chart_template False
96 ch_coa_2940 Valuation Reserves 2940 equity l10n_ch.l10nch_chart_template False
97 ch_coa_2950 Legal retained earnings (Reserves) 2950 equity l10n_ch.l10nch_chart_template False
98 ch_coa_2960 Voluntary retained earnings 2960 equity l10n_ch.l10nch_chart_template False
99 ch_coa_2970 Profits brought forward / Losses brought forward 2970 equity l10n_ch.l10nch_chart_template False
100 ch_coa_2979 Annual profit or annual loss 2979 equity l10n_ch.l10nch_chart_template False
101 ch_coa_2980 Treasury stock, shares, participation rights (negative item) 2980 equity l10n_ch.l10nch_chart_template False
102 ch_coa_3000 Sales of products (Manufacturing) 3000 income l10n_ch.l10nch_chart_template False
103 ch_coa_3009 Deductions on sales 3009 income l10n_ch.l10nch_chart_template False
104 ch_coa_3200 Sales of goods (Trade) 3200 income l10n_ch.l10nch_chart_template False
105 ch_coa_3400 Revenues from services 3400 income l10n_ch.l10nch_chart_template False
106 ch_coa_3600 Other revenues 3600 income l10n_ch.l10nch_chart_template False
107 ch_coa_3700 Own services 3700 income l10n_ch.l10nch_chart_template False
108 ch_coa_3710 Own consumption 3710 income l10n_ch.l10nch_chart_template False
109 ch_coa_3800 Financial discount 3800 income l10n_ch.l10nch_chart_template False
110 ch_coa_3801 Discounts and price reduction 3801 income l10n_ch.l10nch_chart_template False
111 ch_coa_3802 Rebates 3802 income l10n_ch.l10nch_chart_template False
112 ch_coa_3803 Third-party commissions 3803 income l10n_ch.l10nch_chart_template False
113 ch_coa_3804 Collection fees 3804 income l10n_ch.l10nch_chart_template False
114 ch_coa_3805 Losses from bad debts 3805 income l10n_ch.l10nch_chart_template False
115 ch_coa_3806 Exchange rate differences 3806 income l10n_ch.l10nch_chart_template False
116 ch_coa_3807 Shipping & Returns 3807 income l10n_ch.l10nch_chart_template False
117 ch_coa_3900 Changes in inventories of unfinished and finished products 3900 income l10n_ch.l10nch_chart_template False
118 ch_coa_3901 Change in inventories of finished goods 3901 income l10n_ch.l10nch_chart_template False
119 ch_coa_3940 Change in the value of unbilled services 3940 income l10n_ch.l10nch_chart_template False
120 ch_coa_4000 Cost of raw materials (Manufacturing) 4000 expense l10n_ch.l10nch_chart_template False
121 ch_coa_4008 Inventory changes 4008 expense l10n_ch.l10nch_chart_template False
122 ch_coa_4009 Deductions obtained on purchases 4009 expense l10n_ch.l10nch_chart_template False
123 ch_coa_4070 Purchase Loans 4070 expense l10n_ch.l10nch_chart_template False
124 ch_coa_4071 Customs duties on importation 4071 expense l10n_ch.l10nch_chart_template False
125 ch_coa_4072 Transport costs at purchase 4072 expense l10n_ch.l10nch_chart_template False
126 ch_coa_4080 Inventory changes 4080 expense l10n_ch.l10nch_chart_template False
127 ch_coa_4086 Loss of material 4086 expense l10n_ch.l10nch_chart_template False
128 ch_coa_4200 Cost of materials (Trade) 4200 expense l10n_ch.l10nch_chart_template False
129 ch_coa_4400 Cost of purchased services 4400 expense l10n_ch.l10nch_chart_template False
130 ch_coa_4500 Electricity 4500 expense l10n_ch.l10nch_chart_template False
131 ch_coa_4510 Gas 4510 expense l10n_ch.l10nch_chart_template False
132 ch_coa_4520 Fuel oil 4520 expense l10n_ch.l10nch_chart_template False
133 ch_coa_4521 Coal, briquettes, wood 4521 expense l10n_ch.l10nch_chart_template False
134 ch_coa_4530 Petrol 4530 expense l10n_ch.l10nch_chart_template False
135 ch_coa_4540 Water 4540 expense l10n_ch.l10nch_chart_template False
136 ch_coa_4800 Change in inventories of goods 4800 expense l10n_ch.l10nch_chart_template False
137 ch_coa_4801 Change in raw material inventories 4801 expense l10n_ch.l10nch_chart_template False
138 ch_coa_4900 Financial Discounts 4900 expense l10n_ch.l10nch_chart_template False
139 ch_coa_4901 Discounts and price reductions 4901 expense l10n_ch.l10nch_chart_template False
140 ch_coa_4991 Cash Difference Loss 4991 expense l10n_ch.l10nch_chart_template False
141 ch_coa_4992 Cash Difference Gain 4992 income l10n_ch.l10nch_chart_template False
142 ch_coa_4092 Rebates 4902 expense l10n_ch.l10nch_chart_template False
143 ch_coa_4903 Commissions on purchases 4903 expense l10n_ch.l10nch_chart_template False
144 ch_coa_4906 Exchange rate differences 4906 expense l10n_ch.l10nch_chart_template False
145 ch_coa_5000 Wages and salaries 5000 expense l10n_ch.l10nch_chart_template False
146 ch_coa_5700 Social benefits 5700 expense l10n_ch.l10nch_chart_template False
147 ch_coa_5800 Other staff cost 5800 expense l10n_ch.l10nch_chart_template False
148 ch_coa_5900 Temporary staff expenditures 5900 expense l10n_ch.l10nch_chart_template False
149 ch_coa_6000 Rent 6000 expense l10n_ch.l10nch_chart_template False
150 ch_coa_6100 Maintenance & repair expenses 6100 expense l10n_ch.l10nch_chart_template False
151 ch_coa_6105 Leasing movable tangible fixed assets 6105 expense l10n_ch.l10nch_chart_template False
152 ch_coa_6200 Vehicle expenses 6200 expense l10n_ch.l10nch_chart_template False
153 ch_coa_6260 Vehicules leasing and renting 6260 expense l10n_ch.l10nch_chart_template False
154 ch_coa_6300 Insurance premiums 6300 expense l10n_ch.l10nch_chart_template False
155 ch_coa_6400 Energy expenses & disposal expenses 6400 expense l10n_ch.l10nch_chart_template False
156 ch_coa_6500 Administration expenses 6500 expense l10n_ch.l10nch_chart_template False
157 ch_coa_6570 IT leasing 6570 expense l10n_ch.l10nch_chart_template False
158 ch_coa_6600 Promotion and advertising expenses 6600 expense l10n_ch.l10nch_chart_template False
159 ch_coa_6700 Other operating expenses 6700 expense l10n_ch.l10nch_chart_template False
160 ch_coa_6800 Depreciations 6800 expense l10n_ch.l10nch_chart_template False
161 ch_coa_6900 Financial expenses (Interest expenses, Securities expenses, Participations expenses) 6900 expense l10n_ch.l10nch_chart_template False
162 ch_coa_6950 Financial revenues (Interest revenues, Securities revenues, Participations revenues) 6950 expense l10n_ch.l10nch_chart_template False
163 ch_coa_7000 Non-core business revenues 7000 income l10n_ch.l10nch_chart_template False
164 ch_coa_7010 Non-core business expenses 7010 expense l10n_ch.l10nch_chart_template False
165 ch_coa_7500 Revenues from operational real estate 7500 income l10n_ch.l10nch_chart_template False
166 ch_coa_7510 Expenses from operational real estate 7510 expense l10n_ch.l10nch_chart_template False
167 ch_coa_8000 Non-operational expenses 8000 expense l10n_ch.l10nch_chart_template False
168 ch_coa_8100 Non-operational revenues 8100 income l10n_ch.l10nch_chart_template False
169 ch_coa_8500 Extraordinary expenses 8500 expense l10n_ch.l10nch_chart_template False
170 ch_coa_8510 Extraordinary revenues 8510 income l10n_ch.l10nch_chart_template False
171 ch_coa_8900 Direct Taxes 8900 expense l10n_ch.l10nch_chart_template False

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<function model="account.chart.template" name="try_loading">
<value eval="[ref('l10n_ch.l10nch_chart_template')]"/>
</function>
</data>
</odoo>

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Fiscal Position Templates -->
<record id="fiscal_position_template_1" model="account.fiscal.position.template">
<field name="name">Suisse national (+Liechtenstein)</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="auto_apply" eval="True"/>
<field name="country_group_id" ref="base.ch_and_li"/>
</record>
<record id="fiscal_position_template_import" model="account.fiscal.position.template">
<field name="sequence">1</field>
<field name="name">Import/Export</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="auto_apply" eval="True"/>
</record>
<!-- Fiscal Position Tax Templates (pre-2024 rates change) -->
<record id="fiscal_position_tax_template_3" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import" />
<field name="tax_src_id" ref="vat_25_purchase" />
<field name="tax_dest_id" ref="vat_O_import" />
</record>
<record id="fiscal_position_tax_template_4" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import" />
<field name="tax_src_id" ref="vat_25_invest" />
<field name="tax_dest_id" ref="vat_O_import" />
</record>
<record id="fiscal_position_tax_template_5" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import" />
<field name="tax_src_id" ref="vat_37_purchase" />
<field name="tax_dest_id" ref="vat_O_import" />
</record>
<record id="fiscal_position_tax_template_6" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import" />
<field name="tax_src_id" ref="vat_37_invest" />
<field name="tax_dest_id" ref="vat_O_import" />
</record>
<record id="fiscal_position_tax_template_9" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import" />
<field name="tax_src_id" ref="vat_77_purchase_reverse" />
<field name="tax_dest_id" ref="vat_O_import" />
</record>
<record id="fiscal_position_tax_template_10" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import" />
<field name="tax_src_id" ref="vat_77_invest" />
<field name="tax_dest_id" ref="vat_O_import" />
</record>
<record id="fiscal_position_tax_template_14" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import" />
<field name="tax_src_id" ref="vat_25" />
<field name="tax_dest_id" ref="vat_XO" />
</record>
<record id="fiscal_position_tax_template_15" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import" />
<field name="tax_src_id" ref="vat_37" />
<field name="tax_dest_id" ref="vat_XO" />
</record>
<record id="fiscal_position_tax_template_17" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import" />
<field name="tax_src_id" ref="vat_77" />
<field name="tax_dest_id" ref="vat_XO" />
</record>
</data>
</odoo>

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Fiscal Position Tax Templates (post-2024 rates change) -->
<record id="fiscal_position_tax_template_1_2024" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import"/>
<field name="tax_src_id" ref="vat_purchase_26"/>
<field name="tax_dest_id" ref="vat_O_import"/>
</record>
<record id="fiscal_position_tax_template_2_2024" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import"/>
<field name="tax_src_id" ref="vat_purchase_26_invest"/>
<field name="tax_dest_id" ref="vat_O_import"/>
</record>
<record id="fiscal_position_tax_template_3_2024" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import"/>
<field name="tax_src_id" ref="vat_purchase_38"/>
<field name="tax_dest_id" ref="vat_O_import"/>
</record>
<record id="fiscal_position_tax_template_4_2024" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import"/>
<field name="tax_src_id" ref="vat_purchase_38_invest"/>
<field name="tax_dest_id" ref="vat_O_import"/>
</record>
<record id="fiscal_position_tax_template_5_2024" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import"/>
<field name="tax_src_id" ref="vat_purchase_81_reverse"/>
<field name="tax_dest_id" ref="vat_O_import"/>
</record>
<record id="fiscal_position_tax_template_6_2024" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import"/>
<field name="tax_src_id" ref="vat_purchase_81_invest"/>
<field name="tax_dest_id" ref="vat_O_import"/>
</record>
<record id="fiscal_position_tax_template_7_2024" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import"/>
<field name="tax_src_id" ref="vat_sale_26"/>
<field name="tax_dest_id" ref="vat_XO"/>
</record>
<record id="fiscal_position_tax_template_8_2024" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import"/>
<field name="tax_src_id" ref="vat_sale_38"/>
<field name="tax_dest_id" ref="vat_XO"/>
</record>
<record id="fiscal_position_tax_template_9_2024" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import"/>
<field name="tax_src_id" ref="vat_sale_81"/>
<field name="tax_dest_id" ref="vat_XO"/>
</record>
</data>
</odoo>

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Account Tax Group (pre-2024 rates change) -->
<record id="tax_group_tva_0" model="account.tax.group">
<field name="name">VAT 0%</field>
<field name="country_id" ref="base.ch"/>
</record>
<record id="tax_group_tva_25" model="account.tax.group">
<field name="name">VAT 2.5%</field>
<field name="country_id" ref="base.ch"/>
</record>
<record id="tax_group_tva_37" model="account.tax.group">
<field name="name">VAT 3.7%</field>
<field name="country_id" ref="base.ch"/>
</record>
<record id="tax_group_tva_77" model="account.tax.group">
<field name="name">VAT 7.7%</field>
<field name="country_id" ref="base.ch"/>
</record>
<record id="tax_group_tva_100" model="account.tax.group">
<field name="name">VAT 100%</field>
<field name="country_id" ref="base.ch"/>
</record>
<!-- Account Tax Group (post-2024 rates change) -->
<record id="tax_group_vat_26" model="account.tax.group">
<field name="name">VAT 2.6%</field>
<field name="country_id" ref="base.ch"/>
</record>
<record id="tax_group_vat_38" model="account.tax.group">
<field name="name">VAT 3.8%</field>
<field name="country_id" ref="base.ch"/>
</record>
<record id="tax_group_vat_81" model="account.tax.group">
<field name="name">VAT 8.1%</field>
<field name="country_id" ref="base.ch"/>
</record>
</data>
</odoo>

View file

@ -0,0 +1,474 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="tax_report" model="account.report">
<field name="name">Tax Report</field>
<field name="root_report_id" ref="account.generic_tax_report"/>
<field name="country_id" ref="base.ch"/>
<field name="filter_fiscal_position" eval="True"/>
<field name="availability_condition">country</field>
<field name="column_ids">
<record id="tax_report_balance" model="account.report.column">
<field name="name">Balance</field>
<field name="expression_label">balance</field>
</record>
</field>
<field name="line_ids">
<record id="account_tax_report_line_chiffre_af" model="account.report.line">
<field name="name">I. TURNOVER</field>
<field name="sequence" eval="0"/> <!-- Sequence is force to avoid order problem when updating within the same version. -->
<field name="children_ids">
<record id="account_tax_report_line_chtax_200" model="account.report.line">
<field name="name">200 - Total amount of agreed or collected consideration incl. from supplies opted for taxation, transfer of supplies acc. to the notification procedure and supplies provided abroad (worldwide turnover)</field>
<field name="code">tax_ch_200</field>
<field name="aggregation_formula">tax_ch_302a.balance + tax_ch_303a.balance + tax_ch_312a.balance + tax_ch_313a.balance + tax_ch_342a.balance + tax_ch_343a.balance + tax_ch_205.balance + tax_ch_289.balance</field>
<field name="sequence" eval="1"/>
</record>
<record id="account_tax_report_line_chtax_205" model="account.report.line">
<field name="name">205 - Consideration reported in Ref. 200 from supplies exempt from the tax without credit (art. 21) where the option for their taxation according to art. 22 has been exercised</field>
<field name="code">tax_ch_205</field>
<field name="sequence" eval="2"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_205_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">205</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_220_289" model="account.report.line"> <!-- FIXME in master: the xml is as it is for historical reasons but it does represent box 220 only -->
<field name="name">220 - Supplies exempt from the tax (e.g. export, art. 23) and supplies provided to institutional and individual beneficiaries that are exempt from liability for tax (art. 107 para. 1 lit. a)</field>
<field name="code">tax_ch_220</field>
<field name="sequence" eval="3"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_220_289_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">220</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_221" model="account.report.line">
<field name="name">221 - Supplies provided abroad</field>
<field name="code">tax_ch_221</field>
<field name="sequence" eval="4"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_221_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">221</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_225" model="account.report.line">
<field name="name">225 - Transfer of supplies according to the notification procedure (art. 38, please submit Form 764)</field>
<field name="code">tax_ch_225</field>
<field name="sequence" eval="5"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_225_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">225</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_230" model="account.report.line">
<field name="name">230 - Supplies provided on Swiss territory exempt from the tax without credit (art. 21) and where the option for their taxation according to art. 22 has not been exercised</field>
<field name="code">tax_ch_230</field>
<field name="sequence" eval="6"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_230_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">230</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_235" model="account.report.line">
<field name="name">235 - Reduction of consideration (discounts, rebates etc.)</field>
<field name="code">tax_ch_235</field>
<field name="sequence" eval="7"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_235_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">235</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_280" model="account.report.line">
<field name="name">280 - Miscellaneous (e.g. land value, purchase prices in case of margin taxation)</field>
<field name="code">tax_ch_280</field>
<field name="sequence" eval="8"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_280_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">280</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_289" model="account.report.line">
<field name="name">289 - Deductions (Total Ref. 220 to 280)</field>
<field name="code">tax_ch_289</field>
<field name="aggregation_formula">tax_ch_220.balance + tax_ch_221.balance + tax_ch_225.balance + tax_ch_230.balance + tax_ch_235.balance + tax_ch_280.balance</field>
<field name="sequence" eval="9"/>
</record>
<record id="account_tax_report_line_chtax_299" model="account.report.line">
<field name="name">299 - Taxable turnover (Ref. 200 minus Ref. 289)</field>
<field name="aggregation_formula">tax_ch_200.balance - tax_ch_289.balance</field>
<field name="sequence" eval="10"/>
</record>
</field>
</record>
<record id="account_tax_report_line_calc_impot" model="account.report.line">
<field name="name">II - TAX CALCULATION</field>
<field name="sequence" eval="11"/>
<field name="children_ids">
<record id="account_tax_report_line_supplies_1" model="account.report.line">
<field name="name">Supplies CHF from 01.01.2024</field>
<field name="sequence" eval="12"/>
<field name="children_ids">
<record id="account_tax_report_line_chtax_303a" model="account.report.line">
<field name="name">303a - Standard rate (8,1%): Supplies CHF from 01.01.2024</field>
<field name="code">tax_ch_303a</field>
<field name="sequence" eval="13"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_303a_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">303a</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_313a" model="account.report.line">
<field name="name">313a - Reduced rate (2,6%): Supplies CHF from 01.01.2024</field>
<field name="code">tax_ch_313a</field>
<field name="sequence" eval="14"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_313a_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">313a</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_343a" model="account.report.line">
<field name="name">343a - Accommodation rate (3,8%): Supplies CHF from 01.01.2024</field>
<field name="code">tax_ch_343a</field>
<field name="sequence" eval="15"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_343a_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">343a</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_383a" model="account.report.line">
<field name="name">383a - Acquisition tax: Supplies CHF from 01.01.2024</field>
<field name="code">tax_ch_383a</field>
<field name="sequence" eval="16"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_383a_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">383a</field>
</record>
</field>
</record>
</field>
</record>
<record id="account_tax_report_line_supplies_2" model="account.report.line">
<field name="name">Supplies CHF to 31.12.2023</field>
<field name="sequence" eval="17"/>
<field name="children_ids">
<record id="account_tax_report_line_chtax_302a" model="account.report.line">
<field name="name">302a - Standard rate (7,7%): Supplies CHF to 31.12.2023</field>
<field name="code">tax_ch_302a</field>
<field name="sequence" eval="18"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_302a_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">302a</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_312a" model="account.report.line">
<field name="name">312a - Reduced rate (2,5%): Supplies CHF to 31.12.2023</field>
<field name="code">tax_ch_312a</field>
<field name="sequence" eval="19"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_312a_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">312a</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_342a" model="account.report.line">
<field name="name">342a - Accommodation rate (3,7%): Supplies CHF to 31.12.2023</field>
<field name="code">tax_ch_342a</field>
<field name="sequence" eval="20"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_342a_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">342a</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_382a" model="account.report.line">
<field name="name">382a - Acquisition tax: Supplies CHF to 31.12.2023</field>
<field name="code">tax_ch_382a</field>
<field name="sequence" eval="21"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_382a_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">382a</field>
</record>
</field>
</record>
</field>
</record>
<record id="account_tax_report_line_tax_amount_1" model="account.report.line">
<field name="name">Tax amount CHF / cent. from 01.01.2024</field>
<field name="sequence" eval="22"/>
<field name="children_ids">
<record id="account_tax_report_line_chtax_303b" model="account.report.line">
<field name="name">303b - Standard rate (8,1%): Tax amount CHF / cent. from 01.01.2024</field>
<field name="code">tax_ch_303b</field>
<field name="sequence" eval="23"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_303b_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">303b</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_313b" model="account.report.line">
<field name="name">313b - Reduced rate (2,6%): Tax amount CHF / cent. from 01.01.2024</field>
<field name="code">tax_ch_313b</field>
<field name="sequence" eval="24"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_313b_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">313b</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_343b" model="account.report.line">
<field name="name">343b - Accommodation rate (3,8%): Tax amount CHF / cent. from 01.01.2024</field>
<field name="code">tax_ch_343b</field>
<field name="sequence" eval="25"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_343b_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">343b</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_383b" model="account.report.line">
<field name="name">383b - Acquisition tax: Tax amount CHF / cent. from 01.01.2024</field>
<field name="code">tax_ch_383b</field>
<field name="sequence" eval="26"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_383b_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">383b</field>
</record>
</field>
</record>
</field>
</record>
<record id="account_tax_report_line_tax_amount_2" model="account.report.line">
<field name="name">Tax amount CHF / cent. to 31.12.2023</field>
<field name="sequence" eval="27"/>
<field name="children_ids">
<record id="account_tax_report_line_chtax_302b" model="account.report.line">
<field name="name">302b - Standard rate (7,7%): Tax amount CHF / cent. to 31.12.2023</field>
<field name="code">tax_ch_302b</field>
<field name="sequence" eval="28"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_302b_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">302b</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_312b" model="account.report.line">
<field name="name">312b - Reduced rate (2,5%): Tax amount CHF / cent. to 31.12.2023</field>
<field name="code">tax_ch_312b</field>
<field name="sequence" eval="29"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_312b_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">312b</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_342b" model="account.report.line">
<field name="name">342b - Accommodation rate (3,7%): Tax amount CHF / cent. to 31.12.2023</field>
<field name="code">tax_ch_342b</field>
<field name="sequence" eval="30"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_342b_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">342b</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_382b" model="account.report.line">
<field name="name">382b - Acquisition tax: Tax amount CHF / cent. to 31.12.2023</field>
<field name="code">tax_ch_382b</field>
<field name="sequence" eval="31"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_382b_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">382b</field>
</record>
</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_399" model="account.report.line">
<field name="name">399 - Total amount of tax due</field>
<field name="code">tax_ch_399</field>
<field name="aggregation_formula">tax_ch_302b.balance + tax_ch_303b.balance + tax_ch_312b.balance + tax_ch_313b.balance + tax_ch_342b.balance + tax_ch_343b.balance + tax_ch_382b.balance + tax_ch_383b.balance</field>
<field name="sequence" eval="32"/>
</record>
<record id="account_tax_report_line_chtax_400" model="account.report.line">
<field name="name">400 - Input tax on cost of materials and supplies of services</field>
<field name="code">tax_ch_400</field>
<field name="sequence" eval="33"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_400_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">400</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_405" model="account.report.line">
<field name="name">405 - Input tax on investments and other operating costs</field>
<field name="code">tax_ch_405</field>
<field name="sequence" eval="34"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_405_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">405</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_410" model="account.report.line">
<field name="name">410 - De-taxation (art. 32)</field>
<field name="code">tax_ch_410</field>
<field name="sequence" eval="35"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_410_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">410</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_415" model="account.report.line">
<field name="name">415 - Correction of the input tax deduction: mixed use (art. 30), own use (art. 31)</field>
<field name="code">tax_ch_415</field>
<field name="sequence" eval="36"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_415_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">415</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_420" model="account.report.line">
<field name="name">420 - Reduction of the input tax deduction: Flow of funds, which are not deemed to be consideration, such as subsidies, tourist charges (art. 33 para. 2)</field>
<field name="code">tax_ch_420</field>
<field name="sequence" eval="37"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_420_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">420</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_479" model="account.report.line">
<field name="name">479 - Total Ref. 400 to 420</field>
<field name="code">tax_ch_479</field>
<field name="aggregation_formula">tax_ch_400.balance + tax_ch_405.balance + tax_ch_410.balance - tax_ch_415.balance - tax_ch_420.balance</field>
<field name="sequence" eval="38"/>
</record>
<record id="account_tax_report_line_chtax_500" model="account.report.line">
<field name="name">500 - Amount payable</field>
<field name="sequence" eval="39"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_500_formula" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">aggregation</field>
<field name="formula">tax_ch_399.balance - tax_ch_479.balance</field>
<field name="subformula">if_above(CHF(0))</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_510" model="account.report.line">
<field name="name">510 - Credit in favour of the taxable person</field>
<field name="sequence" eval="40"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_510_formula" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">aggregation</field>
<field name="formula">tax_ch_479.balance - tax_ch_399.balance</field>
<field name="subformula">if_above(CHF(0))</field>
</record>
</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_autres_mouv" model="account.report.line">
<field name="name">III. OTHER CASH FLOWS</field>
<field name="aggregation_formula">tax_ch_900.balance + tax_ch_910.balance</field>
<field name="sequence" eval="41"/>
<field name="children_ids">
<record id="account_tax_report_line_chtax_900" model="account.report.line">
<field name="name">900 - Subsidies, tourist funds collected by tourist offices, contributions from cantonal water, sewage or waste funds (art. 18 para. 2 lit. a to c)</field>
<field name="code">tax_ch_900</field>
<field name="sequence" eval="42"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_900_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">900</field>
</record>
</field>
</record>
<record id="account_tax_report_line_chtax_910" model="account.report.line">
<field name="name">910 - Donations, dividends, payments of damages etc. (art. 18 para. 2 lit. d to l)</field>
<field name="code">tax_ch_910</field>
<field name="sequence" eval="43"/>
<field name="expression_ids">
<record id="account_tax_report_line_chtax_910_tag" model="account.report.expression">
<field name="label">balance</field>
<field name="engine">tax_tags</field>
<field name="formula">910</field>
</record>
</field>
</record>
</field>
</record>
</field>
</record>
</odoo>

View file

@ -0,0 +1,563 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Account Tax Templates (post-2024 rates change) -->
<record model="account.tax.template" id="vat_sale_26">
<field name="name">2.6% Sales</field>
<field name="description">2.6%</field>
<field name="amount" eval="2.6"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_vat_26"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_313a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_313b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_313a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_313b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_sale_26_incl">
<field name="name">2.6% Sales (incl.)</field>
<field name="description">2.6% incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="2.6"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_vat_26"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_313a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_313b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_313a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_313b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_26">
<field name="name">2.6% on goods and services</field>
<field name="description">2.6% purch.</field>
<field name="amount" eval="2.6"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_26"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_26_incl">
<field name="name">2.6% on goods and services (incl.)</field>
<field name="description">2.6% purch. Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="2.6"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_26"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_26_invest">
<field name="name">2.6% on invest. and others expenses</field>
<field name="description">2.6% invest.</field>
<field name="amount" eval="2.6"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_26"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_26_invest_incl">
<field name="name">2.6% on invest. and others expenses (incl.)</field>
<field name="description">2.6% invest. Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="2.6"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_26"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_sale_38">
<field name="name">3.8% Sales</field>
<field name="description">3.8%</field>
<field name="amount" eval="3.8"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_vat_38"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_343a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_343b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_343a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_343b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_sale_38_incl">
<field name="name">3.8% Sales (incl.)</field>
<field name="description">3.8% Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="3.8"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_vat_38"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_343a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_343b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_343a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_343b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_38">
<field name="name">3.8% on goods and services</field>
<field name="description">3.8% purch.</field>
<field name="amount" eval="3.8"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_38"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_38_incl">
<field name="name">3.8% on goods and services (incl.)</field>
<field name="description">3.8% purch. Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="3.8"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_38"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_38_invest">
<field name="name">3.8% on invest. and others expenses</field>
<field name="description">3.8% invest</field>
<field name="amount" eval="3.8"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_38"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_38_invest_incl">
<field name="name">3.8% on invest. and others expenses (incl.)</field>
<field name="description">3.8% invest Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="3.8"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_38"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_sale_81">
<field name="name">8.1% Sales</field>
<field name="description">8.1%</field>
<field name="amount" eval="8.1"/>
<field name="sequence" eval="0"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_vat_81"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_303a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_303b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_303a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_303b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_sale_81_incl">
<field name="name">8.1% Sales (incl.)</field>
<field name="description">8.1% Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="8.1"/>
<field name="sequence" eval="0"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_vat_81"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_303a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_303b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_303a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_303b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_81">
<field name="name">8.1% on goods and services</field>
<field name="description">8.1% purch.</field>
<field name="amount" eval="8.1"/>
<field name="amount_type">percent</field>
<field name="sequence" eval="0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_81"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_81_incl">
<field name="name">8.1% on goods and services (incl.)</field>
<field name="description">8.1% purch. Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="8.1"/>
<field name="amount_type">percent</field>
<field name="sequence" eval="0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_81"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_81_invest">
<field name="name">8.1% on invest. and others expenses</field>
<field name="description">8.1% invest.</field>
<field name="amount" eval="8.1"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_81"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_81_invest_incl">
<field name="name">8.1% on invest. and others expenses (incl.)</field>
<field name="description">8.1% invest. Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="8.1"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_81"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_purchase_81_return">
<field name="name">8.1% Purchase (reverse)</field>
<field name="description">8.1% purch. (reverse)</field>
<field name="amount" eval="-8.1"/>
<field name="amount_type">percent</field>
<field name="sequence" eval="0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">none</field>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_383a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_383b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_383a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_383b_tag')],
}),
]"/>
</record>
<!--# for reverse charge or VAT on Acquisition (group of taxes)-->
<record model="account.tax.template" id="vat_purchase_81_reverse">
<field name="name">8.1% on purchase of service abroad (reverse charge)</field>
<field name="description">8.1% rev</field>
<field name="amount_type">group</field>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_vat_81"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="children_tax_ids" eval="[(6, 0, [ref('vat_purchase_81'), ref('vat_purchase_81_return')])]"/>
</record>
</odoo>

View file

@ -0,0 +1,777 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- # TVA - Taxe sur la Valeur Ajoutée (pre-2024 rates change) -->
<record model="account.tax.template" id="vat_25">
<field name="name">2.5% Sales</field>
<field name="description">2.50%</field>
<field name="amount" eval="2.5"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_tva_25"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_312a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_312b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_312a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_312b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_25_incl">
<field name="name">2.5% Sales (incl.)</field>
<field name="description">2.5% Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="2.5"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_tva_25"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_312a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_312b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_312a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_312b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_25_purchase">
<field name="name">2.5% on goods and services</field>
<field name="description">2.5% purch.</field>
<field name="amount" eval="2.5"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_25"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_25_purchase_incl">
<field name="name">2.5% on goods and services (incl.)</field>
<field name="description">2.5% purch. Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="2.5"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_25"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_25_invest">
<field name="name">2.5% on invest. and others expenses</field>
<field name="description">2.5% invest.</field>
<field name="amount" eval="2.5"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_25"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_25_invest_incl">
<field name="name">2.5% on invest. and others expenses (incl.)</field>
<field name="description">2.5% invest. Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="2.5"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_25"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_37">
<field name="name">3.7% Sales</field>
<field name="description">3.70%</field>
<field name="amount" eval="3.7"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_tva_37"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_342a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_342b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_342a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_342b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_37_incl">
<field name="name">3.7% Sales (incl.)</field>
<field name="description">3.7% Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="3.7"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_tva_37"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_342a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_342b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_342a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_342b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_37_purchase">
<field name="name">3.7% on goods and services</field>
<field name="description">3.7% purch.</field>
<field name="amount" eval="3.7"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_37"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_37_purchase_incl">
<field name="name">3.7% on goods and services (incl.)</field>
<field name="description">3.7% purch. Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="3.7"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_37"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_37_invest">
<field name="name">3.7% on invest. and others expenses</field>
<field name="description">3.7% invest</field>
<field name="amount" eval="3.7"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_37"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_37_invest_incl">
<field name="name">3.7% on invest. and others expenses (incl.)</field>
<field name="description">3.7% invest Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="3.7"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_37"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_77">
<field name="name">7.7% Sales</field>
<field name="description">7.70%</field>
<field name="amount" eval="7.7"/>
<field name="sequence" eval="0"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_tva_77"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_302a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_302b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_302a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_302b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_77_incl">
<field name="name">7.7% Sales (incl.)</field>
<field name="description">7.7% Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="7.7"/>
<field name="sequence" eval="0"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_tva_77"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_302a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_302b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_302a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_2200'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_302b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_77_purchase_incl">
<field name="name">7.7% on goods and services (incl.)</field>
<field name="description">7.7% purch. Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="7.7"/>
<field name="amount_type">percent</field>
<field name="sequence" eval="0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_77"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_77_invest">
<field name="name">7.7% on invest. and others expenses</field>
<field name="description">7.7% invest.</field>
<field name="amount" eval="7.7"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_77"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_77_invest_incl">
<field name="name">7.7% on invest. and others expenses (incl.)</field>
<field name="description">7.7% invest. Incl.</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="7.7"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_77"/>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_XO">
<field name="name">0% Export</field>
<field name="amount" eval="0.00"/>
<field name="description">0%</field>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_tva_0"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_220_289_tag')],
}),
(0,0, {'repartition_type': 'tax'}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_220_289_tag')],
}),
(0,0, {'repartition_type': 'tax'}),
]"/>
</record>
<record model="account.tax.template" id="vat_O_exclude">
<field name="name">0% Excluded</field>
<field name="description">0% excl.</field>
<field name="amount" eval="0.00"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_tva_0"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_230_tag')],
}),
(0,0, {'repartition_type': 'tax'}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_230_tag')],
}),
(0,0, {'repartition_type': 'tax'}),
]"/>
</record>
<record model="account.tax.template" id="vat_O_import">
<field name="name">0% Import</field>
<field name="description">0% import.</field>
<field name="amount" eval="0.00"/>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_0"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {'repartition_type': 'tax'}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {'repartition_type': 'tax'}),
]"/>
</record>
<record model="account.tax.template" id="vat_100_import">
<field name="name">Customs VAT on goods and services</field>
<field name="description">100% imp.</field>
<field name="amount" eval="100"/>
<field name="amount_type">division</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_100"/>
<field name="price_include" eval="1"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_100_import_invest">
<field name="name">Customs VAT on invest. and others expenses</field>
<field name="description">100% imp.invest.</field>
<field name="amount" eval="100"/>
<field name="amount_type">division</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="tax_group_id" ref="tax_group_tva_100"/>
<field name="price_include" eval="1"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1171'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_405_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_77_purchase_return">
<field name="name">7.7% Purchase (reverse)</field>
<field name="description">7.7% purch. (return)</field>
<field name="amount" eval="-7.7"/>
<field name="amount_type">percent</field>
<field name="sequence" eval="0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="tax_group_id" ref="tax_group_tva_77"/>
<field name="type_tax_use">none</field>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_382a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_382b_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_382a_tag')],
}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_382b_tag')],
}),
]"/>
</record>
<record model="account.tax.template" id="vat_77_purchase">
<field name="name">7.7% on goods and services</field>
<field name="description">7.7% purch.</field>
<field name="amount" eval="7.7"/>
<field name="amount_type">percent</field>
<field name="sequence" eval="0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="tax_group_id" ref="tax_group_tva_77"/>
<field name="type_tax_use">purchase</field>
<field name="active" eval="False"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {'repartition_type': 'base'}),
(0,0, {
'repartition_type': 'tax',
'account_id': ref('ch_coa_1170'),
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_400_tag')],
}),
]"/>
</record>
<!--# for reverse charge or VAT on Acquisition (group of taxes)-->
<record model="account.tax.template" id="vat_77_purchase_reverse">
<field name="description">7.7% rev.</field>
<field name="name">7.7% on purchase of service abroad (reverse charge)</field>
<field name="amount_type">group</field>
<field name="type_tax_use">purchase</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="tax_group_id" ref="tax_group_tva_77"/>
<field name="active" eval="False"/>
<field name="children_tax_ids" eval="[(6, 0, [ref('vat_77_purchase_return'), ref('vat_77_purchase')])]"/>
</record>
<!-- Taxes for other movements -->
<record model="account.tax.template" id="vat_other_movements_900">
<field name="name">0% - Subsidies, tourist taxes</field>
<field name="amount" eval="0.00"/>
<field name="description">0% subventions</field>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_tva_0"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_900_tag')],
}),
(0,0, {'repartition_type': 'tax'}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_900_tag')],
}),
(0,0, {'repartition_type': 'tax'}),
]"/>
</record>
<record model="account.tax.template" id="vat_other_movements_910">
<field name="name">0% - Donations, dividends, compensation</field>
<field name="amount" eval="0.00"/>
<field name="description">0% dons</field>
<field name="amount_type">percent</field>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="tax_group_id" ref="tax_group_tva_0"/>
<field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'plus_report_expression_ids': [ref('account_tax_report_line_chtax_910_tag')],
}),
(0,0, {'repartition_type': 'tax'}),
]"/>
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
(0,0, {
'repartition_type': 'base',
'minus_report_expression_ids': [ref('account_tax_report_line_chtax_910_tag')],
}),
(0,0, {'repartition_type': 'tax'}),
]"/>
</record>
</odoo>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Account Tags -->
<record id="l10nch_chart_template" model="account.chart.template">
<field name="name">Plan comptable 2015 (Suisse)</field>
<field name="code_digits">4</field>
<field name="bank_account_code_prefix">102</field>
<field name="cash_account_code_prefix">100</field>
<field name="transfer_account_code_prefix">1090</field>
<field name="currency_id" ref="base.CHF"/>
<field name="country_id" ref="base.ch"/>
<field name="spoken_languages" eval="'it_IT;de_DE;de_CH;fr_FR;fr_CH'"/>
</record>
</data>
</odoo>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="l10nch_chart_template" model="account.chart.template">
<field name="property_account_receivable_id" ref="ch_coa_1100"/>
<field name="property_account_payable_id" ref="ch_coa_2000"/>
<field name="property_account_expense_categ_id" ref="ch_coa_4200"/>
<field name="property_account_income_categ_id" ref="ch_coa_3200"/>
<field name="income_currency_exchange_account_id" ref="ch_coa_3806"/>
<field name="expense_currency_exchange_account_id" ref="ch_coa_4906"/>
<field name="default_pos_receivable_account_id" ref="ch_coa_1101" />
<field name="account_journal_early_pay_discount_loss_account_id" ref="ch_coa_4901"/>
<field name="account_journal_early_pay_discount_gain_account_id" ref="ch_coa_3801"/>
<field name="property_tax_payable_account_id" ref="ch_coa_2201"/>
<field name="property_tax_receivable_account_id" ref="ch_coa_1176"/>
<field name="default_cash_difference_expense_account_id" ref="ch_coa_4991"/>
<field name="default_cash_difference_income_account_id" ref="ch_coa_4992"/>
</record>
</odoo>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="cash_rounding_5_centime" model="account.cash.rounding">
<field name="name">Coinage 0.05</field>
<field name="rounding">0.05</field>
<field name="strategy">add_invoice_line</field>
</record>
</data>
</odoo>

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="partner_demo_company_ch" model="res.partner">
<field name="name">CH Company</field>
<field name="vat">CHE-530781296TVA</field>
<field name="street">14 Meierskappelerstrasse</field>
<field name="city">Risch-Rotkreuz</field>
<field name="country_id" ref="base.ch"/>
<field name="zip">6343</field>
<field name="phone">+41 78 123 45 67</field>
<field name="email">info@company.chexample.com</field>
<field name="website">www.chexample.com</field>
</record>
<record id="partner_demo_company_bank_account" model="res.partner.bank">
<field name="acc_type">iban</field>
<field name="acc_number">CH4431999123000889012</field>
<field name="partner_id" ref="l10n_ch.partner_demo_company_ch"/>
</record>
<record id="demo_company_ch" model="res.company">
<field name="name">CH Company</field>
<field name="partner_id" ref="partner_demo_company_ch"/>
</record>
<function model="res.company" name="_onchange_country_id">
<value eval="[ref('demo_company_ch')]"/>
</function>
<function model="res.users" name="write">
<value eval="[ref('base.user_root'), ref('base.user_admin'), ref('base.user_demo')]"/>
<value eval="{'company_ids': [(4, ref('l10n_ch.demo_company_ch'))]}"/>
</function>
<function model="account.chart.template" name="try_loading">
<value eval="[ref('l10n_ch.l10nch_chart_template')]"/>
<value model="res.company" eval="obj().env.ref('l10n_ch.demo_company_ch')"/>
</function>
</odoo>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="res_partner_ch_qr" model="res.partner">
<field name="name">Easy Clean Lausanne</field>
<field eval="[Command.set([ref('base.res_partner_category_11')])]" name="category_id"/>
<field name="is_company">1</field>
<field name="city">Lausanne</field>
<field name="zip">1004</field>
<field name="country_id" ref="base.ch"/>
<field name="street">Rte de Prilly 18, 1004 Lausanne, Suisse</field>
<field name="email">info@easycleanlausanne.ch</field>
<field name="phone">+41 21 796 73 24</field>
<field name="website">http://www.easycleanlausanne.ch</field>
<field name='vat'>CHE-123.456.788 TVA</field>
</record>
<record id="bank_iban_main_partner_ch" model="res.partner.bank">
<field name="acc_type">iban</field>
<field name="acc_number">CH11 3000 5228 1308 3501 F</field>
<field name="partner_id" ref="l10n_ch.res_partner_ch_qr"/>
</record>
</odoo>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
def migrate(cr, version):
""" From 12.0, to saas-13.3, l10n_ch_swissqr_template
used to inherit from another template. This isn't the case
anymore since https://github.com/odoo/odoo/commit/719f087b1b5be5f1f276a0f87670830d073f6ef4
(made in 12.0, and forward-ported). The module will not be updatable if we
don't manually clean inherit_id.
"""
cr.execute("""
update ir_ui_view v
set inherit_id = NULL, mode='primary'
from ir_model_data mdata
where
v.id = mdata.res_id
and mdata.model= 'ir.ui.view'
and mdata.name = 'l10n_ch_swissqr_template'
and mdata.module='l10n_ch';
""")

View file

@ -0,0 +1,23 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, SUPERUSER_ID
from odoo.addons.account.models.chart_template import update_taxes_from_templates
def migrate(cr, version):
env = api.Environment(cr, SUPERUSER_ID, {})
# We had corrupted data, handle the correction so the tax update can proceed.
# See https://github.com/odoo/odoo/commit/7b07df873535446f97abc1de9176b9332de5cb07
for company in env.companies:
taxes_to_check = (f'{company.id}_vat_purchase_81_reverse', f'{company.id}_vat_77_purchase_reverse')
tax_ids = env['ir.model.data'].search([
('name', 'in', taxes_to_check),
('model', '=', 'account.tax'),
]).mapped('res_id')
for tax in env['account.tax'].browse(tax_ids).with_context(active_test=False):
for child in tax.children_tax_ids:
if child.type_tax_use not in ('none', tax.type_tax_use):
# set the child to it's parent's value
child.type_tax_use = tax.type_tax_use
# Update taxes
update_taxes_from_templates(cr, 'l10n_ch.l10nch_chart_template')

View file

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
def migrate(cr, version):
cr.execute("SELECT res_id FROM ir_model_data WHERE module = 'l10n_ch' AND name='account_tax_report_line_chtax_solde_formula'")
expression_id = cr.fetchone()
if expression_id:
cr.execute(
"DELETE FROM account_report_external_value WHERE target_report_expression_id = %s",
[expression_id[0]]
)

View file

@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
import odoo
def migrate(cr, version):
registry = odoo.registry(cr.dbname)
from odoo.addons.account.models.chart_template import migrate_set_tags_and_taxes_updatable
migrate_set_tags_and_taxes_updatable(cr, registry, 'l10n_ch')

View file

@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import res_config_settings
from . import account_invoice
from . import account_journal
from . import res_bank
from . import res_company
from . import account_bank_statement
from . import ir_actions_report
from . import chart_template

View file

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api, _
from odoo.addons.l10n_ch.models.res_bank import _is_l10n_ch_postal
from odoo.tools.misc import str2bool
class AccountBankStatementLine(models.Model):
_inherit = "account.bank.statement.line"
def _find_or_create_bank_account(self):
if self.company_id.account_fiscal_country_id.code in ('CH', 'LI') and _is_l10n_ch_postal(self.account_number):
bank_account = self.env['res.partner.bank'].search(
[('company_id', '=', self.company_id.id),
('sanitized_acc_number', 'like', self.account_number + '%'),
('partner_id', '=', self.partner_id.id)])
if not bank_account and not str2bool(
self.env['ir.config_parameter'].sudo().get_param("account.skip_create_bank_account_on_reconcile")
):
bank_account = self.env['res.partner.bank'].create({
'company_id': self.company_id.id,
'acc_number': self.account_number + " " + self.partner_id.name,
'partner_id': self.partner_id.id
})
return bank_account
else:
return super()._find_or_create_bank_account()

View file

@ -0,0 +1,391 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import re
from odoo import models, fields, api, _
from odoo.exceptions import UserError
from odoo.tools.float_utils import float_split_str
from odoo.tools.misc import mod10r
l10n_ch_ISR_NUMBER_LENGTH = 27
l10n_ch_ISR_ID_NUM_LENGTH = 6
class AccountMove(models.Model):
# NOTE
# The ISR system is kept and taken into account up to September 2022.
# After that, the transition to the QR system will be completed and the ISR system won't exist anymore.
# This means that Odoo v16 shouldn't support the ISR system and all the references to it should be cleaned up by then.
# In the versions leading to that change,
# although the functions related to the ISR are still taken into account and still exist,
# the QR billing is always preferred.
_inherit = 'account.move'
l10n_ch_isr_subscription = fields.Char(compute='_compute_l10n_ch_isr_subscription', help='ISR subscription number identifying your company or your bank to generate ISR.')
l10n_ch_isr_subscription_formatted = fields.Char(compute='_compute_l10n_ch_isr_subscription', help="ISR subscription number your company or your bank, formated with '-' and without the padding zeros, to generate ISR report.")
l10n_ch_isr_number = fields.Char(compute='_compute_l10n_ch_isr_number', store=True, help='The reference number associated with this invoice')
l10n_ch_isr_number_spaced = fields.Char(compute='_compute_l10n_ch_isr_number_spaced', help="ISR number split in blocks of 5 characters (right-justified), to generate ISR report.")
l10n_ch_isr_optical_line = fields.Char(compute="_compute_l10n_ch_isr_optical_line", help='Optical reading line, as it will be printed on ISR')
l10n_ch_isr_valid = fields.Boolean(compute='_compute_l10n_ch_isr_valid', help='Boolean value. True iff all the data required to generate the ISR are present')
l10n_ch_isr_sent = fields.Boolean(default=False, help="Boolean value telling whether or not the ISR corresponding to this invoice has already been printed or sent by mail.")
l10n_ch_currency_name = fields.Char(related='currency_id.name', readonly=True, string="Currency Name", help="The name of this invoice's currency") #This field is used in the "invisible" condition field of the 'Print ISR' button.
l10n_ch_isr_needs_fixing = fields.Boolean(compute="_compute_l10n_ch_isr_needs_fixing", help="Used to show a warning banner when the vendor bill needs a correct ISR payment reference. ")
l10n_ch_is_qr_valid = fields.Boolean(compute='_compute_l10n_ch_qr_is_valid', help="Determines whether an invoice can be printed as a QR or not")
@api.depends('partner_id', 'currency_id')
def _compute_l10n_ch_qr_is_valid(self):
for move in self:
company_eligible = True
if(move.company_id.account_fiscal_country_id.code != 'CH'):
company_eligible = False
if move.partner_bank_id.acc_number and move.partner_bank_id.acc_type == 'iban':
iban = move.partner_bank_id.acc_number.replace(' ', '')
if iban.startswith('CH') and len(iban) >= 9:
bank_code = iban[4:9]
if bank_code.isdigit() and 30000 <= int(bank_code) <= 31999:
company_eligible = True
move.l10n_ch_is_qr_valid = (
move.move_type == 'out_invoice'
and move.partner_bank_id._eligible_for_qr_code('ch_qr', move.partner_id, move.currency_id, raises_error=False)
and company_eligible
)
@api.depends('partner_bank_id.l10n_ch_isr_subscription_eur', 'partner_bank_id.l10n_ch_isr_subscription_chf')
def _compute_l10n_ch_isr_subscription(self):
""" Computes the ISR subscription identifying your company or the bank that allows to generate ISR. And formats it accordingly"""
def _format_isr_subscription(isr_subscription):
#format the isr as per specifications
currency_code = isr_subscription[:2]
middle_part = isr_subscription[2:-1]
trailing_cipher = isr_subscription[-1]
middle_part = re.sub('^0*', '', middle_part)
return currency_code + '-' + middle_part + '-' + trailing_cipher
def _format_isr_subscription_scanline(isr_subscription):
# format the isr for scanline
return isr_subscription[:2] + isr_subscription[2:-1].rjust(6, '0') + isr_subscription[-1:]
for record in self:
record.l10n_ch_isr_subscription = False
record.l10n_ch_isr_subscription_formatted = False
if record.partner_bank_id:
if record.currency_id.name == 'EUR':
isr_subscription = record.partner_bank_id.l10n_ch_isr_subscription_eur
elif record.currency_id.name == 'CHF':
isr_subscription = record.partner_bank_id.l10n_ch_isr_subscription_chf
else:
#we don't format if in another currency as EUR or CHF
continue
if isr_subscription:
isr_subscription = isr_subscription.replace("-", "") # In case the user put the -
record.l10n_ch_isr_subscription = _format_isr_subscription_scanline(isr_subscription)
record.l10n_ch_isr_subscription_formatted = _format_isr_subscription(isr_subscription)
def _get_isrb_id_number(self):
"""Hook to fix the lack of proper field for ISR-B Customer ID"""
# FIXME
# replace l10n_ch_postal by an other field to not mix ISR-B
# customer ID as it forbid the following validations on l10n_ch_postal
# number for Vendor bank accounts:
# - validation of format xx-yyyyy-c
# - validation of checksum
return self.partner_bank_id.l10n_ch_postal or ''
@api.depends('name', 'partner_bank_id.l10n_ch_postal')
def _compute_l10n_ch_isr_number(self):
for record in self:
if (record.partner_bank_id.l10n_ch_qr_iban or record.l10n_ch_isr_subscription) and record.name:
invoice_ref = re.sub(r'\D', '', record.name)
record.l10n_ch_isr_number = record._compute_isr_number(invoice_ref)
else:
record.l10n_ch_isr_number = False
@api.model
def _compute_isr_number(self, invoice_ref):
r"""Generates the ISR or QRR reference
An ISR references are 27 characters long.
QRR is a recycling of ISR for QR-bills. Thus works the same.
The invoice sequence number is used, removing each of its non-digit characters,
and pad the unused spaces on the left of this number with zeros.
The last digit is a checksum (mod10r).
There are 2 types of references:
* ISR (Postfinance)
The reference is free but for the last
digit which is a checksum.
If shorter than 27 digits, it is filled with zeros on the left.
e.g.
120000000000234478943216899
\________________________/|
1 2
(1) 12000000000023447894321689 | reference
(2) 9: control digit for identification number and reference
* ISR-B (Indirect through a bank, requires a customer ID)
In case of ISR-B The firsts digits (usually 6), contain the customer ID
at the Bank of this ISR's issuer.
The rest (usually 20 digits) is reserved for the reference plus the
control digit.
If the [customer ID] + [the reference] + [the control digit] is shorter
than 27 digits, it is filled with zeros between the customer ID till
the start of the reference.
e.g.
150001123456789012345678901
\____/\__________________/|
1 2 3
(1) 150001 | id number of the customer (size may vary)
(2) 12345678901234567890 | reference
(3) 1: control digit for identification number and reference
"""
id_number = self._get_isrb_id_number()
if id_number:
id_number = id_number.zfill(l10n_ch_ISR_ID_NUM_LENGTH)
# keep only the last digits if it exceed boundaries
full_len = len(id_number) + len(invoice_ref)
ref_payload_len = l10n_ch_ISR_NUMBER_LENGTH - 1
extra = full_len - ref_payload_len
if extra > 0:
invoice_ref = invoice_ref[extra:]
internal_ref = invoice_ref.zfill(ref_payload_len - len(id_number))
return mod10r(id_number + internal_ref)
@api.depends('l10n_ch_isr_number')
def _compute_l10n_ch_isr_number_spaced(self):
def _space_isr_number(isr_number):
to_treat = isr_number
res = ''
while to_treat:
res = to_treat[-5:] + res
to_treat = to_treat[:-5]
if to_treat:
res = ' ' + res
return res
for record in self:
if record.l10n_ch_isr_number:
record.l10n_ch_isr_number_spaced = _space_isr_number(record.l10n_ch_isr_number)
else:
record.l10n_ch_isr_number_spaced = False
def _get_l10n_ch_isr_optical_amount(self):
"""Prepare amount string for ISR optical line"""
self.ensure_one()
currency_code = None
if self.currency_id.name == 'CHF':
currency_code = '01'
elif self.currency_id.name == 'EUR':
currency_code = '03'
units, cents = float_split_str(self.amount_residual, 2)
amount_to_display = units + cents
amount_ref = amount_to_display.zfill(10)
optical_amount = currency_code + amount_ref
optical_amount = mod10r(optical_amount)
return optical_amount
@api.depends(
'currency_id.name', 'amount_residual', 'name',
'partner_bank_id.l10n_ch_isr_subscription_eur',
'partner_bank_id.l10n_ch_isr_subscription_chf')
def _compute_l10n_ch_isr_optical_line(self):
r""" Compute the optical line to print on the bottom of the ISR.
This line is read by an OCR.
It's format is:
amount>reference+ creditor>
Where:
- amount: currency and invoice amount
- reference: ISR structured reference number
- in case of ISR-B contains the Customer ID number
- it can also contains a partner reference (of the debitor)
- creditor: Subscription number of the creditor
An optical line can have the 2 following formats:
* ISR (Postfinance)
0100003949753>120000000000234478943216899+ 010001628>
|/\________/| \________________________/| \_______/
1 2 3 4 5 6
(1) 01 | currency
(2) 0000394975 | amount 3949.75
(3) 4 | control digit for amount
(5) 12000000000023447894321689 | reference
(6) 9: control digit for identification number and reference
(7) 010001628: subscription number (01-162-8)
* ISR-B (Indirect through a bank, requires a customer ID)
0100000494004>150001123456789012345678901+ 010234567>
|/\________/| \____/\__________________/| \_______/
1 2 3 4 5 6 7
(1) 01 | currency
(2) 0000049400 | amount 494.00
(3) 4 | control digit for amount
(4) 150001 | id number of the customer (size may vary, usually 6 chars)
(5) 12345678901234567890 | reference
(6) 1: control digit for identification number and reference
(7) 010234567: subscription number (01-23456-7)
"""
for record in self:
record.l10n_ch_isr_optical_line = ''
if record.l10n_ch_isr_number and record.l10n_ch_isr_subscription and record.currency_id.name:
# Final assembly (the space after the '+' is no typo, it stands in the specs.)
record.l10n_ch_isr_optical_line = '{amount}>{reference}+ {creditor}>'.format(
amount=record._get_l10n_ch_isr_optical_amount(),
reference=record.l10n_ch_isr_number,
creditor=record.l10n_ch_isr_subscription,
)
@api.depends(
'move_type', 'name', 'currency_id.name',
'partner_bank_id.l10n_ch_isr_subscription_eur',
'partner_bank_id.l10n_ch_isr_subscription_chf')
def _compute_l10n_ch_isr_valid(self):
"""Returns True if all the data required to generate the ISR are present"""
for record in self:
record.l10n_ch_isr_valid = record.move_type == 'out_invoice' and\
record.name and \
record.l10n_ch_isr_subscription and \
record.l10n_ch_currency_name in ['EUR', 'CHF']
@api.depends('move_type', 'partner_bank_id', 'payment_reference')
def _compute_l10n_ch_isr_needs_fixing(self):
for inv in self:
if inv.move_type == 'in_invoice' and inv.company_id.account_fiscal_country_id.code in ('CH', 'LI'):
partner_bank = inv.partner_bank_id
needs_isr_ref = partner_bank.l10n_ch_qr_iban or partner_bank._is_isr_issuer()
if needs_isr_ref and not inv._has_isr_ref():
inv.l10n_ch_isr_needs_fixing = True
continue
inv.l10n_ch_isr_needs_fixing = False
def _has_isr_ref(self):
"""Check if this invoice has a valid ISR reference (for Switzerland)
e.g.
12371
000000000000000000000012371
210000000003139471430009017
21 00000 00003 13947 14300 09017
"""
self.ensure_one()
ref = self.payment_reference or self.ref
if not ref:
return False
ref = ref.replace(' ', '')
if re.match(r'^(\d{2,27})$', ref):
return ref == mod10r(ref[:-1])
return False
def split_total_amount(self):
""" Splits the total amount of this invoice in two parts, using the dot as
a separator, and taking two precision digits (always displayed).
These two parts are returned as the two elements of a tuple, as strings
to print in the report.
This function is needed on the model, as it must be called in the report
template, which cannot reference static functions
"""
return float_split_str(self.amount_residual, 2)
def action_invoice_sent(self):
# OVERRIDE
rslt = super(AccountMove, self).action_invoice_sent()
if self.l10n_ch_isr_valid or self.l10n_ch_is_qr_valid:
rslt['context']['l10n_ch_mark_isr_as_sent'] = True
return rslt
@api.returns('mail.message', lambda value: value.id)
def message_post(self, **kwargs):
if self.env.context.get('l10n_ch_mark_isr_as_sent'):
self.filtered(lambda inv: not inv.l10n_ch_isr_sent).write({'l10n_ch_isr_sent': True})
return super(AccountMove, self.with_context(mail_post_autofollow=self.env.context.get('mail_post_autofollow', True))).message_post(**kwargs)
def _get_invoice_reference_ch_invoice(self):
""" This sets ISR reference number which is generated based on customer's `Bank Account` and set it as
`Payment Reference` of the invoice when invoice's journal is using Switzerland's communication standard
"""
self.ensure_one()
# l10n_ch_isr_number is not always computed at this stage, and could change value when the invoice is posted.
# We manually compute here it to avoid this conflict.
self._compute_l10n_ch_isr_number()
return self.l10n_ch_isr_number
def _get_invoice_reference_ch_partner(self):
""" This sets ISR reference number which is generated based on customer's `Bank Account` and set it as
`Payment Reference` of the invoice when invoice's journal is using Switzerland's communication standard
"""
self.ensure_one()
return self.l10n_ch_isr_number
@api.model
def space_qrr_reference(self, qrr_ref):
""" Makes the provided QRR reference human-friendly, spacing its elements
by blocks of 5 from right to left.
"""
spaced_qrr_ref = ''
i = len(qrr_ref) # i is the index after the last index to consider in substrings
while i > 0:
spaced_qrr_ref = qrr_ref[max(i-5, 0) : i] + ' ' + spaced_qrr_ref
i -= 5
return spaced_qrr_ref
@api.model
def space_scor_reference(self, iso11649_ref):
""" Makes the provided SCOR reference human-friendly, spacing its elements
by blocks of 5 from right to left.
"""
return ' '.join(iso11649_ref[i:i + 4] for i in range(0, len(iso11649_ref), 4))
def l10n_ch_action_print_qr(self):
'''
Checks that all invoices can be printed in the QR format.
If so, launches the printing action.
Else, triggers the l10n_ch wizard that will display the informations.
'''
if any(x.move_type != 'out_invoice' for x in self):
raise UserError(_("Only customers invoices can be QR-printed."))
if False in self.mapped('l10n_ch_is_qr_valid'):
return {
'name': (_("Some invoices could not be printed in the QR format")),
'type': 'ir.actions.act_window',
'res_model': 'l10n_ch.qr_invoice.wizard',
'view_type': 'form',
'view_mode': 'form',
'target': 'new',
'context': {'active_ids': self.ids},
}
return self.env.ref('account.account_invoices').report_action(self)
def _l10n_ch_dispatch_invoices_to_print(self):
qr_invs = self.filtered('l10n_ch_is_qr_valid')
isr_invs = self.filtered('l10n_ch_isr_valid')
return {
'qr': qr_invs,
'isr': isr_invs,
'classic': self - qr_invs - isr_invs,
}

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api
from odoo.exceptions import ValidationError
from odoo.addons.base_iban.models.res_partner_bank import validate_iban
from odoo.addons.base.models.res_bank import sanitize_account_number
class AccountJournal(models.Model):
_inherit = 'account.journal'
invoice_reference_model = fields.Selection(selection_add=[
('ch', 'Switzerland')
], ondelete={'ch': lambda recs: recs.write({'invoice_reference_model': 'odoo'})})
def _process_reference_for_sale_order(self, order_reference):
'''
returns the order reference to be used for the payment respecting the ISR
'''
self.ensure_one()
if self.invoice_reference_model == 'ch':
# converting the sale order name into a unique number. Letters are converted to their base10 value
invoice_ref = "".join([a if a.isdigit() else str(ord(a)) for a in order_reference])
# id_number = self.company_id.bank_ids.l10n_ch_postal or ''
order_reference = self.env['account.move']._compute_isr_number(invoice_ref)
return order_reference
return super()._process_reference_for_sale_order(order_reference)

View file

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
from odoo import models
class AccountChartTemplate(models.Model):
_inherit = 'account.chart.template'
# Write paperformat and report template used on company
def _load(self, company):
res = super(AccountChartTemplate, self)._load(company)
if self == self.env.ref('l10n_ch.l10nch_chart_template'):
company.write({
'external_report_layout_id': self.env.ref('l10n_din5008.external_layout_din5008').id,
'paperformat_id': self.env.ref('l10n_din5008.paperformat_euro_din').id
})
return res

View file

@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import io
from odoo import api, models
from odoo.tools.pdf import OdooPdfFileReader, OdooPdfFileWriter
from pathlib import Path
from reportlab.graphics.shapes import Drawing as ReportLabDrawing, Image as ReportLabImage
from reportlab.lib.units import mm
CH_QR_CROSS_SIZE_RATIO = 0.1522 # Ratio between the side length of the Swiss QR-code cross image and the QR-code's
CH_QR_CROSS_FILE = Path('../static/src/img/CH-Cross_7mm.png') # Image file containing the Swiss QR-code cross to add on top of the QR-code
class IrActionsReport(models.Model):
_inherit = 'ir.actions.report'
@api.model
def get_available_barcode_masks(self):
rslt = super(IrActionsReport, self).get_available_barcode_masks()
rslt['ch_cross'] = self.apply_qr_code_ch_cross_mask
return rslt
@api.model
def apply_qr_code_ch_cross_mask(self, width, height, barcode_drawing):
assert isinstance(barcode_drawing, ReportLabDrawing)
zoom_x = barcode_drawing.transform[0]
zoom_y = barcode_drawing.transform[3]
cross_width = CH_QR_CROSS_SIZE_RATIO * width
cross_height = CH_QR_CROSS_SIZE_RATIO * height
cross_path = Path(__file__).absolute().parent / CH_QR_CROSS_FILE
qr_cross = ReportLabImage((width/2 - cross_width/2) / zoom_x, (height/2 - cross_height/2) / zoom_y, cross_width / zoom_x, cross_height / zoom_y, cross_path.as_posix())
barcode_drawing.add(qr_cross)
def _render_qweb_pdf_prepare_streams(self, report_ref, data, res_ids=None):
# OVERRIDE
res = super()._render_qweb_pdf_prepare_streams(report_ref, data, res_ids)
if not res_ids:
return res
report = self._get_report(report_ref)
if self._is_invoice_report(report_ref):
invoices = self.env[report.model].browse(res_ids)
# Determine which invoices need a QR/ISR.
qr_inv_ids = []
isr_inv_ids = []
for invoice in invoices:
# avoid duplicating existing streams
if report.attachment_use and report.retrieve_attachment(invoice):
continue
if invoice.l10n_ch_is_qr_valid:
qr_inv_ids.append(invoice.id)
elif invoice.company_id.country_code == 'CH' and invoice.l10n_ch_isr_valid:
isr_inv_ids.append(invoice.id)
# Render the additional reports.
streams_to_append = {}
if qr_inv_ids:
qr_res = self._render_qweb_pdf_prepare_streams(
'l10n_ch.l10n_ch_qr_report',
{
**data,
'skip_headers': False,
},
res_ids=qr_inv_ids,
)
header = self.env.ref('l10n_ch.l10n_ch_qr_header', raise_if_not_found=False)
if header:
# Make a separated rendering to get the a page containing the company header. Then, merge the qr bill with it.
header_res = self._render_qweb_pdf_prepare_streams(
'l10n_ch.l10n_ch_qr_header',
{
**data,
'skip_headers': True,
},
res_ids=qr_inv_ids,
)
for invoice_id, stream in qr_res.items():
qr_pdf = OdooPdfFileReader(stream['stream'], strict=False)
header_pdf = OdooPdfFileReader(header_res[invoice_id]['stream'], strict=False)
page = header_pdf.getPage(0)
page.mergePage(qr_pdf.getPage(0))
output_pdf = OdooPdfFileWriter()
output_pdf.addPage(page)
new_pdf_stream = io.BytesIO()
output_pdf.write(new_pdf_stream)
streams_to_append[invoice_id] = {'stream': new_pdf_stream}
else:
for invoice_id, stream in qr_res.items():
streams_to_append[invoice_id] = stream
if isr_inv_ids:
isr_res = self._render_qweb_pdf_prepare_streams('l10n_ch.l10n_ch_isr_report', data, res_ids=isr_inv_ids)
for invoice_id, stream in isr_res.items():
streams_to_append[invoice_id] = stream
# Add to results
for invoice_id, additional_stream in streams_to_append.items():
invoice_stream = res[invoice_id]['stream']
writer = OdooPdfFileWriter()
writer.appendPagesFromReader(OdooPdfFileReader(invoice_stream, strict=False))
writer.appendPagesFromReader(OdooPdfFileReader(additional_stream['stream'], strict=False))
new_pdf_stream = io.BytesIO()
writer.write(new_pdf_stream)
res[invoice_id]['stream'] = new_pdf_stream
invoice_stream.close()
additional_stream['stream'].close()
return res
def get_paperformat(self):
if self.env.context.get('snailmail_layout'):
if self.report_name == 'l10n_ch.qr_report_main':
return self.env.ref('l10n_ch.paperformat_euro_no_margin')
if self.report_name == 'l10n_ch.qr_report_header':
return self.env.ref('l10n_din5008.paperformat_euro_din')
return super(IrActionsReport, self).get_paperformat()

View file

@ -0,0 +1,388 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import re
from stdnum.util import clean
from odoo import api, fields, models, _
from odoo.addons.base.models.res_bank import sanitize_account_number
from odoo.addons.base_iban.models.res_partner_bank import normalize_iban, pretty_iban, validate_iban
from odoo.exceptions import ValidationError, UserError
from odoo.tools.misc import mod10r
ISR_SUBSCRIPTION_CODE = {'CHF': '01', 'EUR': '03'}
CLEARING = "09000"
_re_postal = re.compile('^[0-9]{2}-[0-9]{1,6}-[0-9]$')
def _is_l10n_ch_postal(account_ref):
""" Returns True if the string account_ref is a valid postal account number,
i.e. it only contains ciphers and is last cipher is the result of a recursive
modulo 10 operation ran over the rest of it. Shorten form with - is also accepted.
"""
if _re_postal.match(account_ref or ''):
ref_subparts = account_ref.split('-')
account_ref = ref_subparts[0] + ref_subparts[1].rjust(6, '0') + ref_subparts[2]
if re.match(r'\d+$', account_ref or ''):
account_ref_without_check = account_ref[:-1]
return mod10r(account_ref_without_check) == account_ref
return False
def _is_l10n_ch_isr_issuer(account_ref, currency_code):
""" Returns True if the string account_ref is a valid a valid ISR issuer
An ISR issuer is postal account number that starts by 01 (CHF) or 03 (EUR),
"""
if (account_ref or '').startswith(ISR_SUBSCRIPTION_CODE[currency_code]):
return _is_l10n_ch_postal(account_ref)
return False
def validate_qr_iban(qr_iban):
# Check first if it's a valid IBAN.
validate_iban(qr_iban)
# We sanitize first so that _check_qr_iban_range() can extract correct IID from IBAN to validate it.
sanitized_qr_iban = sanitize_account_number(qr_iban)
if sanitized_qr_iban[:2] not in ['CH', 'LI']:
raise ValidationError(_("QR-IBAN numbers are only available in Switzerland."))
# Now, check if it's valid QR-IBAN (based on its IID).
if not check_qr_iban_range(sanitized_qr_iban):
raise ValidationError(_("QR-IBAN '%s' is invalid.") % qr_iban)
return True
def check_qr_iban_range(iban):
if not iban or len(iban) < 9:
return False
iid_start_index = 4
iid_end_index = 8
iid = iban[iid_start_index : iid_end_index+1]
return re.match(r'\d+', iid) and 30000 <= int(iid) <= 31999 # Those values for iid are reserved for QR-IBANs only
class ResPartnerBank(models.Model):
_inherit = 'res.partner.bank'
l10n_ch_postal = fields.Char(
string="Swiss Postal Account",
readonly=False, store=True,
compute='_compute_l10n_ch_postal',
help="This field is used for the Swiss postal account number on a vendor account and for the client number on "
"your own account. The client number is mostly 6 numbers without -, while the postal account number can "
"be e.g. 01-162-8")
l10n_ch_qr_iban = fields.Char(string='QR-IBAN',
compute='_compute_l10n_ch_qr_iban',
store=True,
readonly=False,
help="Put the QR-IBAN here for your own bank accounts. That way, you can "
"still use the main IBAN in the Account Number while you will see the "
"QR-IBAN for the barcode. ")
# fields to configure ISR payment slip generation
l10n_ch_isr_subscription_chf = fields.Char(string='CHF ISR Subscription Number', help='The subscription number provided by the bank or Postfinance to identify the bank, used to generate ISR in CHF. eg. 01-162-8')
l10n_ch_isr_subscription_eur = fields.Char(string='EUR ISR Subscription Number', help='The subscription number provided by the bank or Postfinance to identify the bank, used to generate ISR in EUR. eg. 03-162-5')
l10n_ch_show_subscription = fields.Boolean(compute='_compute_l10n_ch_show_subscription', default=lambda self: self.env.company.account_fiscal_country_id.code == 'CH')
def _is_isr_issuer(self):
return (_is_l10n_ch_isr_issuer(self.l10n_ch_postal, 'CHF')
or _is_l10n_ch_isr_issuer(self.l10n_ch_postal, 'EUR'))
@api.constrains("l10n_ch_postal", "partner_id")
def _check_postal_num(self):
"""Validate postal number format"""
for rec in self:
if rec.l10n_ch_postal and not _is_l10n_ch_postal(rec.l10n_ch_postal):
# l10n_ch_postal is used for the purpose of Client Number on your own accounts, so don't do the check there
if rec.partner_id and not rec.partner_id.ref_company_ids:
raise ValidationError(
_("The postal number {} is not valid.\n"
"It must be a valid postal number format. eg. 10-8060-7").format(rec.l10n_ch_postal))
return True
@api.constrains("l10n_ch_isr_subscription_chf", "l10n_ch_isr_subscription_eur")
def _check_subscription_num(self):
"""Validate ISR subscription number format
Subscription number can only starts with 01 or 03
"""
for rec in self:
for currency in ["CHF", "EUR"]:
subscrip = rec.l10n_ch_isr_subscription_chf if currency == "CHF" else rec.l10n_ch_isr_subscription_eur
if subscrip and not _is_l10n_ch_isr_issuer(subscrip, currency):
example = "01-162-8" if currency == "CHF" else "03-162-5"
raise ValidationError(
_("The ISR subcription {} for {} number is not valid.\n"
"It must starts with {} and we a valid postal number format. eg. {}"
).format(subscrip, currency, ISR_SUBSCRIPTION_CODE[currency], example))
return True
@api.depends('partner_id', 'company_id')
def _compute_l10n_ch_show_subscription(self):
for bank in self:
if bank.partner_id:
bank.l10n_ch_show_subscription = bank.partner_id.ref_company_ids.country_id.code in ('CH', 'LI')
elif bank.company_id:
bank.l10n_ch_show_subscription = bank.company_id.account_fiscal_country_id.code in ('CH', 'LI')
else:
bank.l10n_ch_show_subscription = self.env.company.account_fiscal_country_id.code in ('CH', 'LI')
@api.depends('acc_number', 'acc_type')
def _compute_sanitized_acc_number(self):
#Only remove spaces in case it is not postal
postal_banks = self.filtered(lambda b: b.acc_type == "postal")
for bank in postal_banks:
bank.sanitized_acc_number = bank.acc_number
super(ResPartnerBank, self - postal_banks)._compute_sanitized_acc_number()
@api.depends('acc_number')
def _compute_l10n_ch_qr_iban(self):
for record in self:
try:
validate_qr_iban(record.acc_number)
valid_qr_iban = True
except ValidationError:
valid_qr_iban = False
if valid_qr_iban:
record.l10n_ch_qr_iban = record.sanitized_acc_number
else:
record.l10n_ch_qr_iban = None
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('l10n_ch_qr_iban'):
validate_qr_iban(vals['l10n_ch_qr_iban'])
vals['l10n_ch_qr_iban'] = pretty_iban(normalize_iban(vals['l10n_ch_qr_iban']))
return super().create(vals_list)
def write(self, vals):
if vals.get('l10n_ch_qr_iban'):
validate_qr_iban(vals['l10n_ch_qr_iban'])
vals['l10n_ch_qr_iban'] = pretty_iban(normalize_iban(vals['l10n_ch_qr_iban']))
return super().write(vals)
@api.model
def _get_supported_account_types(self):
rslt = super(ResPartnerBank, self)._get_supported_account_types()
rslt.append(('postal', _('Postal')))
return rslt
@api.model
def retrieve_acc_type(self, acc_number):
""" Overridden method enabling the recognition of swiss postal bank
account numbers.
"""
acc_number_split = ""
# acc_number_split is needed to continue to recognize the account
# as a postal account even if the difference
if acc_number and " " in acc_number:
acc_number_split = acc_number.split(" ")[0]
if _is_l10n_ch_postal(acc_number) or (acc_number_split and _is_l10n_ch_postal(acc_number_split)):
return 'postal'
else:
return super(ResPartnerBank, self).retrieve_acc_type(acc_number)
@api.depends('acc_number', 'partner_id', 'acc_type')
def _compute_l10n_ch_postal(self):
for record in self:
if record.acc_type == 'iban':
record.l10n_ch_postal = self._retrieve_l10n_ch_postal(record.sanitized_acc_number)
elif record.acc_type == 'postal':
if record.acc_number and " " in record.acc_number:
record.l10n_ch_postal = record.acc_number.split(" ")[0]
else:
record.l10n_ch_postal = record.acc_number
# In case of ISR issuer, this number is not
# unique and we fill acc_number with partner
# name to give proper information to the user
if record.partner_id and record.acc_number[:2] in ["01", "03"]:
record.acc_number = ("{} {}").format(record.acc_number, record.partner_id.name)
@api.model
def _is_postfinance_iban(self, iban):
"""Postfinance IBAN have format
CHXX 0900 0XXX XXXX XXXX K
Where 09000 is the clearing number
"""
return iban.startswith(('CH', 'LI')) and iban[4:9] == CLEARING
@api.model
def _pretty_postal_num(self, number):
"""format a postal account number or an ISR subscription number
as per specifications with '-' separators.
eg. 010001628 -> 01-162-8
"""
if re.match('^[0-9]{2}-[0-9]{1,6}-[0-9]$', number or ''):
return number
currency_code = number[:2]
middle_part = number[2:-1]
trailing_cipher = number[-1]
middle_part = middle_part.lstrip("0")
return currency_code + '-' + middle_part + '-' + trailing_cipher
@api.model
def _retrieve_l10n_ch_postal(self, iban):
"""Reads a swiss postal account number from a an IBAN and returns it as
a string. Returns None if no valid postal account number was found, or
the given iban was not from Swiss Postfinance.
CH09 0900 0000 1000 8060 7 -> 10-8060-7
"""
if self._is_postfinance_iban(iban):
# the IBAN corresponds to a swiss account
return self._pretty_postal_num(iban[-9:])
return None
def _l10n_ch_get_qr_vals(self, amount, currency, debtor_partner, free_communication, structured_communication):
comment = ""
if free_communication:
comment = (free_communication[:137] + '...') if len(free_communication) > 140 else free_communication
creditor_addr_1, creditor_addr_2 = self._get_partner_address_lines(self.partner_id)
debtor_addr_1, debtor_addr_2 = self._get_partner_address_lines(debtor_partner)
# Compute reference type (empty by default, only mandatory for QR-IBAN,
# and must then be 27 characters-long, with mod10r check digit as the 27th one,
# just like ISR number for invoices)
reference_type = 'NON'
reference = ''
acc_number = self.sanitized_acc_number
if self.l10n_ch_qr_iban:
# _check_for_qr_code_errors ensures we can't have a QR-IBAN without a QR-reference here
reference_type = 'QRR'
reference = structured_communication
acc_number = sanitize_account_number(self.l10n_ch_qr_iban)
elif self._is_iso11649_reference(structured_communication):
reference_type = 'SCOR'
reference = structured_communication.replace(' ', '')
currency = currency or self.currency_id or self.company_id.currency_id
return [
'SPC', # QR Type
'0200', # Version
'1', # Coding Type
acc_number, # IBAN / QR-IBAN
'K', # Creditor Address Type
(self.acc_holder_name or self.partner_id.name)[:70], # Creditor Name
creditor_addr_1, # Creditor Address Line 1
creditor_addr_2, # Creditor Address Line 2
'', # Creditor Postal Code (empty, since we're using combined addres elements)
'', # Creditor Town (empty, since we're using combined addres elements)
self.partner_id.country_id.code, # Creditor Country
'', # Ultimate Creditor Address Type
'', # Name
'', # Ultimate Creditor Address Line 1
'', # Ultimate Creditor Address Line 2
'', # Ultimate Creditor Postal Code
'', # Ultimate Creditor Town
'', # Ultimate Creditor Country
'{:.2f}'.format(amount), # Amount
currency.name, # Currency
'K', # Ultimate Debtor Address Type
debtor_partner.commercial_partner_id.name[:70], # Ultimate Debtor Name
debtor_addr_1, # Ultimate Debtor Address Line 1
debtor_addr_2, # Ultimate Debtor Address Line 2
'', # Ultimate Debtor Postal Code (not to be provided for address type K)
'', # Ultimate Debtor Postal City (not to be provided for address type K)
debtor_partner.country_id.code, # Ultimate Debtor Postal Country
reference_type, # Reference Type
reference, # Reference
comment, # Unstructured Message
'EPD', # Mandatory trailer part
]
def _get_qr_vals(self, qr_method, amount, currency, debtor_partner, free_communication, structured_communication):
if qr_method == 'ch_qr':
return self._l10n_ch_get_qr_vals(amount, currency, debtor_partner, free_communication, structured_communication)
return super()._get_qr_vals(qr_method, amount, currency, debtor_partner, free_communication, structured_communication)
def _get_qr_code_generation_params(self, qr_method, amount, currency, debtor_partner, free_communication, structured_communication):
if qr_method == 'ch_qr':
return {
'barcode_type': 'QR',
'width': 256,
'height': 256,
'quiet': 1,
'mask': 'ch_cross',
'value': '\n'.join(self._get_qr_vals(qr_method, amount, currency, debtor_partner, free_communication, structured_communication)),
# Swiss QR code requires Error Correction Level = 'M' by specification
'barLevel': 'M',
}
return super()._get_qr_code_generation_params(qr_method, amount, currency, debtor_partner, free_communication, structured_communication)
def _get_partner_address_lines(self, partner):
""" Returns a tuple of two elements containing the address lines to use
for this partner. Line 1 contains the street and number, line 2 contains
zip and city. Those two lines are limited to 70 characters
"""
streets = [partner.street, partner.street2]
line_1 = ' '.join(filter(None, streets))
line_2 = partner.zip + ' ' + partner.city
return line_1[:70], line_2[:70]
@api.model
def _is_qr_reference(self, reference):
""" Checks whether the given reference is a QR-reference, i.e. it is
made of 27 digits, the 27th being a mod10r check on the 26 previous ones.
"""
return reference \
and len(reference) == 27 \
and re.match(r'\d+$', reference) \
and reference == mod10r(reference[:-1])
@api.model
def _is_iso11649_reference(self, reference):
""" Checks whether the given reference is a ISO11649 (SCOR) reference.
"""
return reference \
and len(reference) >= 5 \
and len(reference) <= 25 \
and reference.startswith('RF') \
and int(''.join(str(int(x, 36)) for x in clean(reference[4:] + reference[:4], ' -.,/:').upper().strip())) % 97 == 1
# see https://github.com/arthurdejong/python-stdnum/blob/master/stdnum/iso11649.py
def _eligible_for_qr_code(self, qr_method, debtor_partner, currency, raises_error=True):
if qr_method == 'ch_qr':
error_messages = [_("The QR code could not be generated for the following reason(s):")]
if self.acc_type != 'iban':
error_messages.append(_("The account type isn't QR-IBAN or IBAN."))
if not debtor_partner or debtor_partner.country_id.code not in ('CH', 'LI'):
error_messages.append(_("The debtor partner's address isn't located in Switzerland."))
if currency.id not in (self.env.ref('base.EUR').id, self.env.ref('base.CHF').id):
error_messages.append(_("The currency isn't EUR nor CHF. \r\n"))
if len(error_messages) != 1:
if raises_error:
raise UserError(' '.join(error_messages))
return False
return True
return super()._eligible_for_qr_code(qr_method, debtor_partner, currency, raises_error)
def _check_for_qr_code_errors(self, qr_method, amount, currency, debtor_partner, free_communication, structured_communication):
def _partner_fields_set(partner):
return partner.zip and \
partner.city and \
partner.country_id.code and \
(partner.street or partner.street2)
if qr_method == 'ch_qr':
if not _partner_fields_set(self.partner_id):
return _("The partner set on the bank account meant to receive the payment (%s) must have a complete postal address (street, zip, city and country).", self.acc_number)
if debtor_partner and not _partner_fields_set(debtor_partner):
return _("The partner must have a complete postal address (street, zip, city and country).")
if self.l10n_ch_qr_iban and not self._is_qr_reference(structured_communication):
return _("When using a QR-IBAN as the destination account of a QR-code, the payment reference must be a QR-reference.")
return super()._check_for_qr_code_errors(qr_method, amount, currency, debtor_partner, free_communication, structured_communication)
@api.model
def _get_available_qr_methods(self):
rslt = super()._get_available_qr_methods()
rslt.append(('ch_qr', _("Swiss QR bill"), 10))
return rslt

View file

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class Company(models.Model):
_inherit = "res.company"
l10n_ch_isr_preprinted_account = fields.Boolean(string='Preprinted account', compute='_compute_l10n_ch_isr', inverse='_set_l10n_ch_isr')
l10n_ch_isr_preprinted_bank = fields.Boolean(string='Preprinted bank', compute='_compute_l10n_ch_isr', inverse='_set_l10n_ch_isr')
l10n_ch_isr_print_bank_location = fields.Boolean(string='Print bank location', default=False, help='Boolean option field indicating whether or not the alternate layout (the one printing bank name and address) must be used when generating an ISR.')
l10n_ch_isr_scan_line_left = fields.Float(string='Scan line horizontal offset (mm)', compute='_compute_l10n_ch_isr', inverse='_set_l10n_ch_isr')
l10n_ch_isr_scan_line_top = fields.Float(string='Scan line vertical offset (mm)', compute='_compute_l10n_ch_isr', inverse='_set_l10n_ch_isr')
def _compute_l10n_ch_isr(self):
get_param = self.env['ir.config_parameter'].sudo().get_param
for company in self:
company.l10n_ch_isr_preprinted_account = bool(get_param('l10n_ch.isr_preprinted_account', default=False))
company.l10n_ch_isr_preprinted_bank = bool(get_param('l10n_ch.isr_preprinted_bank', default=False))
company.l10n_ch_isr_scan_line_top = float(get_param('l10n_ch.isr_scan_line_top', default=0))
company.l10n_ch_isr_scan_line_left = float(get_param('l10n_ch.isr_scan_line_left', default=0))
def _set_l10n_ch_isr(self):
set_param = self.env['ir.config_parameter'].sudo().set_param
for company in self:
set_param("l10n_ch.isr_preprinted_account", company.l10n_ch_isr_preprinted_account)
set_param("l10n_ch.isr_preprinted_bank", company.l10n_ch_isr_preprinted_bank)
set_param("l10n_ch.isr_scan_line_top", company.l10n_ch_isr_scan_line_top)
set_param("l10n_ch.isr_scan_line_left", company.l10n_ch_isr_scan_line_left)

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
l10n_ch_isr_preprinted_account = fields.Boolean(string='Preprinted account',
related="company_id.l10n_ch_isr_preprinted_account", readonly=False)
l10n_ch_isr_preprinted_bank = fields.Boolean(string='Preprinted bank',
related="company_id.l10n_ch_isr_preprinted_bank", readonly=False)
l10n_ch_isr_print_bank_location = fields.Boolean(string="Print bank on ISR",
related="company_id.l10n_ch_isr_print_bank_location", readonly=False,
required=True)
l10n_ch_isr_scan_line_left = fields.Float(string='Horizontal offset',
related="company_id.l10n_ch_isr_scan_line_left", readonly=False)
l10n_ch_isr_scan_line_top = fields.Float(string='Vertical offset',
related="company_id.l10n_ch_isr_scan_line_top", readonly=False)

View file

@ -0,0 +1,3 @@
# -*- coding:utf-8 -*-
from . import swissqr_report

View file

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="paperformat_euro_no_margin" model="report.paperformat">
<field name="name">European A4 without borders</field>
<field name="default" eval="False" />
<field name="format">A4</field>
<field name="orientation">Portrait</field>
<field name="margin_top">0</field>
<field name="margin_bottom">0</field>
<field name="margin_left">0</field>
<field name="margin_right">0</field>
<field name="header_line" eval="False" />
<field name="header_spacing">0</field>
</record>
<!--Report containing an ISR corrresponding to an invoice.-->
<record id="l10n_ch_isr_report" model="ir.actions.report">
<field name="name">ISR</field>
<field name="model">account.move</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">l10n_ch.isr_report_main</field>
<field name="report_file">l10n_ch.isr_report_main</field>
<field name="print_report_name">'ISR-%s' % object.name</field>
<field name="paperformat_id" ref="paperformat_euro_no_margin"/>
<field name="attachment">'ISR-' + object.name + '.pdf'</field>
<field name="attachment_use">True</field>
</record>
<!--No additional condition in report name on invoice state or type as this
report is only available to be printed for out invoices after
'draft' state, if the fields required by the ISR have been set.-->
<template id="l10n_ch_isr_report_template">
<t t-call="web.external_layout">
<t t-set="split_total_amount" t-value="invoice.split_total_amount()"/>
<t t-set="print_bank" t-value="invoice.company_id.l10n_ch_isr_print_bank_location"/>
<!-- add class to body tag -->
<script>document.body.className += " l10n_ch_isr";</script>
<!-- since the body content take the whole page we need a way to add margin
back on content outside the ISR so it does not overlap with the header -->
<div id="content_outside_isr">
<h1>ISR for invoice <t t-esc="invoice.name"/></h1>
</div>
<div id="isr" t-att-class="'isr-print-bank' if print_bank else None">
<!--Voucher, left part of the ISR.-->
<div id="voucher">
<!--Einzahlung für/Versement pour/Versamento per-->
<!--If we use the alternate ISR layout, displaying name
and location of the bank.-->
<t t-if="print_bank">
<div id="voucher-for-bank">
<p t-if="not invoice.company_id.l10n_ch_isr_preprinted_bank">
<t t-esc="invoice.partner_bank_id.bank_id.name"/><br />
<t t-esc="invoice.partner_bank_id.bank_id.zip"/>
<t t-esc="invoice.partner_bank_id.bank_id.city"/>
</p>
</div>
<!--Zugunsten von/En faveur de/A favore di-->
</t>
<div id="voucher-for-contact">
<p id="voucher-for_name" t-field="invoice.company_id.display_name"/>
<p id="voucher-for_address1" t-field="invoice.company_id.street"/>
<p id="voucher-for_address2" t-field="invoice.company_id.street2"/>
<p id="voucher-for_address3">
<t t-esc="invoice.company_id.zip"/>
<t t-esc="invoice.company_id.city"/>
</p>
</div>
<div id="voucher-bank" t-if="not print_bank or not invoice.company_id.l10n_ch_isr_preprinted_account">
<!--Konto/Compte/Conto-->
<p id="voucher-bank_ref" t-field="invoice.l10n_ch_isr_subscription_formatted"/>
</div>
<p id="voucher-amount_units" t-esc="split_total_amount[0]"/>
<p id="voucher-amount_cents" t-esc="split_total_amount[1]"/>
<div id="voucher-by">
<!--Einbezahlt von/Versé par/Versato da-->
<p id="voucher-by_reference_number" t-field="invoice.l10n_ch_isr_number"/>
<address id="voucher-by_customer_address" t-field="invoice.partner_id" t-options='{"widget": "contact", "fields": ["address","name"], "no_marker": True}' />
</div>
</div>
<!--Slip, right part of the ISR.-->
<div id="slip">
<!--Einzahlung für/Versement pour/Versamento per-->
<!--If we use the alternate ISR layout, displaying name
and location of the bank.-->
<t t-if="print_bank">
<div id="slip-for-bank">
<p t-if="not invoice.company_id.l10n_ch_isr_preprinted_bank">
<t t-esc="invoice.partner_bank_id.bank_id.name"/><br />
<t t-esc="invoice.partner_bank_id.bank_id.zip"/>
<t t-esc="invoice.partner_bank_id.bank_id.city"/>
</p>
</div>
<!--Zugunsten von/En faveur de/A favore di-->
</t>
<div id="slip-for-contact">
<p id="slip-for_name" t-field="invoice.company_id.display_name"/>
<p id="slip-for_address1" t-field="invoice.company_id.street"/>
<p id="slip-for_address2" t-field="invoice.company_id.street2"/>
<p id="slip-for_address3">
<t t-esc="invoice.company_id.zip"/>
<t t-esc="invoice.company_id.city"/>
</p>
</div>
<div id="slip-bank" t-if="not print_bank or not invoice.company_id.l10n_ch_isr_preprinted_account">
<!--Konto/Compte/Conto-->
<!--aka ISR Subscriber number provided by the financial institution-->
<p id="slip-bank_ref" t-field="invoice.l10n_ch_isr_subscription_formatted"/>
</div>
<p id="slip-amount_units" t-esc="split_total_amount[0]"/>
<p id="slip-amount_cents" t-esc="split_total_amount[1]"/>
<div id="slip-reference">
<!--Referenz-Nr./N°de référence/N°di riferimento-->
<p id="slip-reference_number" t-field="invoice.l10n_ch_isr_number_spaced"/>
</div>
<div id="slip-by">
<!--Einbezahlt von/Versé par/Versato da-->
<address id="slip-by_customer_address" t-field="invoice.partner_id" t-options='{"widget": "contact", "fields": ["address","name"], "no_marker": True}' />
</div>
<div id="slip-optical-line">
<!--Optical reference-->
<div t-attf-style="top: {{ invoice.company_id.l10n_ch_isr_scan_line_top }}mm; left: {{ invoice.company_id.l10n_ch_isr_scan_line_left }}mm;">
<div t-foreach="invoice.l10n_ch_isr_optical_line" t-as="char" t-esc="char" t-attf-style="right: {{ round((char_size - char_index - 1) * 0.1, 1) }}in"/>
</div>
</div>
</div>
</div>
</t>
</template>
<template id="l10n_ch.isr_report_main">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="invoice">
<t t-set="o" t-value="invoice"/>
<t t-call="l10n_ch.l10n_ch_isr_report_template"/>
</t>
</t>
</template>
</data>
</odoo>

View file

@ -0,0 +1,21 @@
# -*- coding:utf-8 -*-
from odoo import api, models
class ReportSwissQR(models.AbstractModel):
_name = 'report.l10n_ch.qr_report_main'
_description = 'Swiss QR-bill report'
@api.model
def _get_report_values(self, docids, data=None):
docs = self.env['account.move'].browse(docids)
qr_code_urls = {}
for invoice in docs:
qr_code_urls[invoice.id] = invoice.partner_bank_id.build_qr_code_base64(invoice.amount_residual, invoice.ref or invoice.name, invoice.payment_reference, invoice.currency_id, invoice.partner_id, qr_method='ch_qr', silent_errors=False)
return {
'doc_ids': docids,
'doc_model': 'account.move',
'docs': docs,
'qr_code_urls': qr_code_urls,
}

View file

@ -0,0 +1,251 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="l10n_ch_qr_report" model="ir.actions.report">
<field name="name">QR-bill</field>
<field name="model">account.move</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">l10n_ch.qr_report_main</field>
<field name="report_file">l10n_ch.qr_report_main</field>
<field name="print_report_name">'QR-bill-%s' % object.name</field>
<field name="paperformat_id" ref="l10n_ch.paperformat_euro_no_margin"/>
</record>
<record id="l10n_ch_qr_header" model="ir.actions.report">
<field name="name">QR-bill Header</field>
<field name="model">account.move</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">l10n_ch.qr_report_header</field>
<field name="report_file">l10n_ch.qr_report_header</field>
</record>
<template id="l10n_ch_header_template">
<t t-call="web.external_layout">
<!--The following elements are necessary for the header to be displayed correctly.-->
<br/>
<p>&amp;nbsp;</p>
</t>
</template>
<template id="l10n_ch_swissqr_template">
<div class="article" t-att-data-oe-model="o._name" t-att-data-oe-id="o.id">
<t t-set="o" t-value="o.with_context(lang=lang)"/>
<t t-set="company" t-value="o.company_id"/>
<t t-set="formated_amount" t-value="'{:,.2f}'.format(o.amount_residual).replace(',','\xa0')"/>
<t t-set="is_qrr" t-value="o.partner_bank_id.l10n_ch_qr_iban"/>
<t t-set="is_scor" t-value="o.partner_bank_id._is_iso11649_reference(o.payment_reference)"/>
<div class="swissqr_content_v2">
<div class="swissqr_receipt">
<img src="/l10n_ch/static/src/img/scissors_h.png" class="scissors horizontal_scissors"/>
<div id="receipt_title_zone" class="swissqr_section_title">
<span>Receipt</span>
</div>
<div id="receipt_indication_zone" class="receipt_indication_zone">
<div class="swissqr_text title">
<span>Account / Payable to</span>
</div>
<div class="swissqr_text content">
<span t-field="o.partner_bank_id.acc_number" t-if="not o.partner_bank_id.l10n_ch_qr_iban"/>
<span t-field="o.partner_bank_id.l10n_ch_qr_iban" t-if="o.partner_bank_id.l10n_ch_qr_iban"/>
<br/>
<span t-esc="o.partner_bank_id.acc_holder_name or o.company_id.name"/><br/>
<span t-field="o.company_id.street"/><br/>
<span t-field="o.company_id.country_id.code"/>
<span t-field="o.company_id.zip"/>
<span t-field="o.company_id.city"/><br/>
<br/>
</div>
<t t-if="is_qrr or is_scor">
<div class="swissqr_text title">
<span>Reference</span>
</div>
</t>
<t t-if="is_qrr">
<div class="swissqr_text content">
<span t-esc="o.space_qrr_reference(o.payment_reference)"/><br/>
<br/>
</div>
</t>
<t t-if="is_scor">
<div class="swissqr_text content">
<span t-esc="o.space_scor_reference(o.payment_reference)"/><br/>
<br/>
</div>
</t>
<div class="swissqr_text title">
<span>Payable by</span>
</div>
<div class="swissqr_text content">
<span t-field="o.partner_id.commercial_partner_id.name"/><br/>
<span t-field="o.partner_id.street"/>
<span t-field="o.partner_id.street2"/><br/>
<span t-field="o.partner_id.country_id.code"/>
<span t-field="o.partner_id.zip"/>
<span t-field="o.partner_id.city"/>
</div>
</div>
<div id="receipt_amount_zone" class="swissqr_column_left receipt_amount_zone">
<div class="swissqr_text">
<div class="column">
<div class="title">
<span>Currency</span>
</div>
<div class="content">
<span t-field="o.currency_id.name"/>
</div>
</div>
<div class="column">
<div class="title">
<span>Amount</span>
</div>
<div class="content">
<span t-esc="formated_amount"/>
</div>
</div>
</div>
</div>
<div id="receipt_acceptance_point_zone" class="receipt_acceptance_point_zone">
<div class="swissqr_text content">
<span class="title">Acceptance point</span>
</div>
</div>
</div>
<div class="swissqr_body">
<img src="/l10n_ch/static/src/img/scissors_v.png" class="scissors vertical_scissors"/>
<div class="swissqr_column_left">
<div class="swissqr_section_title">
<span>Payment part</span>
</div>
<img class="swissqr" t-att-src="qr_code_urls[o.id]"/>
<div id="amount_zone" class="amount_zone">
<div class="swissqr_text">
<div class="column">
<div class="title">
<span>Currency</span>
</div>
<div class="content">
<span t-field="o.currency_id.name"/>
</div>
</div>
<div class="column">
<div class="title">
<span>Amount</span><br/>
</div>
<div class="content">
<span t-esc="formated_amount"/>
</div>
</div>
</div>
</div>
</div>
<div id="indications_zone" class="swissqr_column_right">
<div class="swissqr_text title">
<span>Account / Payable to</span><br/>
</div>
<div class="swissqr_text content">
<span t-field="o.partner_bank_id.acc_number" t-if="not o.partner_bank_id.l10n_ch_qr_iban"/>
<span t-field="o.partner_bank_id.l10n_ch_qr_iban" t-if="o.partner_bank_id.l10n_ch_qr_iban"/>
<br/>
<span t-esc="o.partner_bank_id.acc_holder_name or o.company_id.name"/><br/>
<span t-field="o.company_id.street"/><br/>
<span t-field="o.company_id.country_id.code"/>
<span t-field="o.company_id.zip"/>
<span t-field="o.company_id.city"/><br/>
<br/>
</div>
<t t-if="is_qrr or is_scor">
<div class="swissqr_text title">
<span class="title">Reference</span>
</div>
</t>
<t t-if="is_qrr">
<div class="swissqr_text content">
<span t-esc="o.space_qrr_reference(o.payment_reference)"/><br/>
<br/>
</div>
</t>
<t t-if="is_scor">
<div class="swissqr_text content">
<span t-esc="o.space_scor_reference(o.payment_reference)"/><br/>
<br/>
</div>
</t>
<t t-set="additional_info" t-value="(o.ref or o.name if is_qrr or is_scor else o.payment_reference or o.ref or o.name)"/>
<t t-if="additional_info">
<div class="swissqr_text title">
<span>Additional information</span>
</div>
<div class="swissqr_text content">
<span t-esc="additional_info"/><br/>
<br/>
</div>
</t>
<div class="swissqr_text title">
<span>Payable by</span>
</div>
<div class="swissqr_text content">
<span t-field="o.partner_id.commercial_partner_id.name"/><br/>
<span t-field="o.partner_id.street"> </span>
<span t-field="o.partner_id.street2"/><br/>
<span t-field="o.partner_id.country_id.code"/>
<span t-field="o.partner_id.zip"/>
<span t-field="o.partner_id.city"/><br/>
<br/>
</div>
</div>
</div>
</div>
</div>
</template>
<template id="l10n_ch.qr_report_main">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">
<t t-set="lang" t-value="o.partner_id.lang"/>
<t t-call="l10n_ch.l10n_ch_swissqr_template" t-lang="lang"/>
</t>
</t>
</template>
<template id="l10n_ch.qr_report_header">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="invoice">
<t t-set="o" t-value="invoice"/>
<t t-set="lang" t-value="o.partner_id.lang"/>
<t t-call="l10n_ch.l10n_ch_header_template" t-lang="lang"/>
</t>
</t>
</template>
<template id="minimal_layout_with_report_attribute" inherit_id="web.minimal_layout">
<body position="attributes">
<attribute name="t-att-data-report-id">report_xml_id</attribute>
</body>
</template>
</data>
</odoo>

View file

@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_l10n_ch_qr_invoice_wizard,l10n_ch.qr_invoice.wizard,model_l10n_ch_qr_invoice_wizard,account.group_account_invoice,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_l10n_ch_qr_invoice_wizard l10n_ch.qr_invoice.wizard model_l10n_ch_qr_invoice_wizard account.group_account_invoice 1 1 1 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

View file

@ -0,0 +1,102 @@
Digitized data copyright (c) 2010 Google Corporation
with Reserved Font Arimo, Tinos and Cousine.
Copyright (c) 2012 Red Hat, Inc.
with Reserved Font Name Liberation.
This Font Software is licensed under the SIL Open Font License,
Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
PREAMBLE The goals of the Open Font License (OFL) are to stimulate
worldwide development of collaborative font projects, to support the font
creation efforts of academic and linguistic communities, and to provide
a free and open framework in which fonts may be shared and improved in
partnership with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves.
The fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply to
any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such.
This may include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components
as distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting ? in part or in whole ?
any of the components of the Original Version, by changing formats or
by porting the Font Software to a new environment.
"Author" refers to any designer, engineer, programmer, technical writer
or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining a
copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,in
Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the
corresponding Copyright Holder. This restriction only applies to the
primary font name as presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole, must
be distributed entirely under this license, and must not be distributed
under any other license. The requirement for fonts to remain under
this license does not apply to any document created using the Font
Software.
TERMINATION
This license becomes null and void if any of the above conditions are not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
DEALINGS IN THE FONT SOFTWARE.

View file

@ -0,0 +1,4 @@
Files: ocrb.otf
Copyright: 2012 Matthew Skala
License: public-domain
This file is released to the public domain by its author, Matthew Skala.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -0,0 +1,208 @@
@font-face {
font-family: ocrb;
src: url('../font/ocrb.otf') format('opentype');
}
.l10n_ch_isr {
/*
all elements are positionned for A4 format (210 x 297mm) but the viewport
is bigger than this, hence we zoom the whole page to be bigger than the viewport
which will then be resized down by wkhtmltopdf to get back to an A4 format
*/
zoom: 1.25;
&.o_in_iframe {
zoom: 1;
/* display dummy check bacground in html rendering to help see the end result */
#isr {
background: url(../img/background_virgin_isr.png) bottom no-repeat;
background-size: 100%;
&.isr-print-bank {
background-image: url(../img/background_virgin_isr_bank.png);
}
}
}
/* content outside isr needs margins to not overlap header */
#content_outside_isr {
padding: 15px;
padding-top: 150px;
}
/* ISR is intended for pre-printed paper, we don't want stylistic background */
.o_report_layout_striped {
background: none;
min-height: 0;
}
#isr {
height: 106mm;
width: 210mm;
position: absolute;
/* position bvr at bottom of page */
top: 297 - 106mm;
left: 0;
overflow: hidden;
font-family: ocrb;
line-height: 0.16in;
font-size: 10pt;
p {
margin-bottom: 0;
}
#voucher {
height: 4in;
width: 2.4in;
position: absolute;
/* header title of BVR section */
top: 0.167in;
/* right of voucher corresponds to left of slip */
right: 5.9in;
}
#voucher > * {
position: absolute;
/* default left margin for fields content */
left: 0.15in;
&#voucher-for-contact {
top: 0.25in;
}
&#voucher-for-bank {
top: 0.18in;
}
&#voucher-for-bank + #voucher-for-contact {
top: 0.68in;
}
&#voucher-bank {
top: 1.51in;
left: 1.1in;
}
&#voucher-amount_units {
width: 1.62in;
top: 1.87in;
text-align: right;
font-size: 14px;
letter-spacing: 0.095in;
}
&#voucher-amount_cents {
width: 0.4in;
top: 1.87in;
left: 1.96in;
font-size: 14px;
letter-spacing: 0.095in;
}
&#voucher-by {
top: 2.22in;
font-size: 9pt;
max-width: 2in;
#voucher-by_reference_number {
font-size: 7.5pt;
margin-bottom: 0.05in;
}
}
}
#slip {
height: 4in;
width: 5.9in;
position: absolute;
/* header title of BVR section */
top: 0.167in;
/* right of slip corresponds to right of slip */
right: 0;
}
#slip > * {
position: absolute;
/* default left margin for fields content */
left: 0.15in;
&#slip-for-contact {
top: 0.25in;
p {
margin-bottom: 0;
}
}
&#slip-for-bank {
top: 0.18in;
}
&#slip-for-bank + #slip-for-contact {
top: 0.68in;
}
&#slip-bank {
top: 1.51in;
left: 1.1in;
}
&#slip-amount_units {
width: 1.62in;
top: 1.87in;
text-align: right;
font-size: 14px;
letter-spacing: 0.095in;
}
&#slip-amount_cents {
width: 0.4in;
top: 1.87in;
left: 1.96in;
font-size: 14px;
letter-spacing: 0.095in;
}
&#slip-reference {
width: 3.3in;
top: 1.2in;
left: 2.5in;
text-align: center;
}
&#slip-by {
top: 1.85in;
left: 2.55in;
}
&#slip-optical-line {
right: 0.32in;
bottom: 0.667in;
/* Positioning is set for OCRB of Tsukurimashou Font Family */
font-family: ocrb;
font-size: 10pt;
line-height: 0.1in;
> div {
position: relative;
> div {
position: absolute;
bottom: 0;
}
}
}
}
}
}

View file

@ -0,0 +1,193 @@
@font-face {
font-family: LiberationSans;
src: url('../font/LiberationSans-Bold.woff') format('woff');
font-weight: bold;
}
@font-face {
font-family: LiberationSans;
src: url('../font/LiberationSans-Regular.woff') format('woff');
}
$l10n-ch-qr-ratio: 1.25;
body.l10n_ch_qr{
padding: 0;
span{
padding-left: 10mm;
white-space: nowrap;
}
/* Disable custom bakground */
.o_report_layout_striped {
background-color: white;
min-height: 0;
}
}
.swissqr_page_title {
color: black;
font-weight: bold;
height: 7mm * $l10n-ch-qr-ratio;
padding: 15px;
padding-top: 150px;
h1{
padding-left:20mm;
white-space:nowrap;
}
}
.swissqr_content_v2 {
$receipt_width: 52mm * $l10n-ch-qr-ratio;
$left_col_width: 46mm * $l10n-ch-qr-ratio;
$right_col_width: 87mm * $l10n-ch-qr-ratio;
$rounding_offset: 0.25mm;
@mixin font {
font-family: LiberationSans;
color: black;
}
@mixin title {
@include font;
font-weight: bold;
}
/* New QR Bill code */
background-color: white !important;
/* Disable custom font-family */
.o_company_2_layout {
font-family: revert;
}
.title {
@include title;
}
.swissqr_text {
@include font;
}
.swissqr_section_title {
@include title;
width: $receipt_width;
height: 7mm * $l10n-ch-qr-ratio;
font-size: 11pt * $l10n-ch-qr-ratio;
line-height: 9pt * $l10n-ch-qr-ratio;
}
.swissqr_receipt {
background-color: white !important;
position: absolute;
left: 0mm;
top: 192mm * $l10n-ch-qr-ratio;
width: 62mm * $l10n-ch-qr-ratio;
height: 105mm * $l10n-ch-qr-ratio - $rounding_offset;
border-top: 0.75pt * $l10n-ch-qr-ratio dashed black;
padding: 5mm * $l10n-ch-qr-ratio;
.title {
font-size: 6pt * $l10n-ch-qr-ratio;
line-height: 9pt * $l10n-ch-qr-ratio;
}
.content {
font-size: 8pt * $l10n-ch-qr-ratio;
line-height: 9pt * $l10n-ch-qr-ratio;
}
.receipt_indication_zone {
width: $receipt_width;
height: 56mm * $l10n-ch-qr-ratio;
}
.receipt_amount_zone {
width: $receipt_width;
height: 14mm * $l10n-ch-qr-ratio;
.column {
float: left;
margin-right: 5mm;
}
.content {
font-size: 8pt * $l10n-ch-qr-ratio;
line-height: 11pt * $l10n-ch-qr-ratio;
}
}
.receipt_acceptance_point_zone {
width: $receipt_width;
height: 18mm * $l10n-ch-qr-ratio;
.content {
float: right;
padding-right: 2mm * $l10n-ch-qr-ratio;
font-size: 6pt * $l10n-ch-qr-ratio;
line-height: 8pt * $l10n-ch-qr-ratio;
}
}
}
.swissqr_body {
background-color: white !important;
position: absolute;
top: 192mm * $l10n-ch-qr-ratio;
left: 62mm * $l10n-ch-qr-ratio;
width: 148mm * $l10n-ch-qr-ratio;
height: 105mm * $l10n-ch-qr-ratio - $rounding_offset;
border: 0.75pt * $l10n-ch-qr-ratio dashed black;
border-bottom: none;
border-right: none;
padding: 5mm * $l10n-ch-qr-ratio;
.title {
font-size: 8pt * $l10n-ch-qr-ratio;
line-height: 11pt * $l10n-ch-qr-ratio;
}
.content {
font-size: 10pt * $l10n-ch-qr-ratio;
line-height: 11pt * $l10n-ch-qr-ratio;
}
.swissqr_column_left {
float: left;
width: $left_col_width;
.swissqr_section_title{
height: 7mm * $l10n-ch-qr-ratio;
}
.swissqr {
margin-top: 5mm * $l10n-ch-qr-ratio;
margin-bottom: 5mm * $l10n-ch-qr-ratio;
height: 46mm * $l10n-ch-qr-ratio;
width: 46mm * $l10n-ch-qr-ratio;
}
.amount_zone {
width: $left_col_width;
height: 22mm * $l10n-ch-qr-ratio;
.column {
margin-right: 3mm;
float: left;
}
.title {
font-size: 8pt * $l10n-ch-qr-ratio;
line-height: 11pt * $l10n-ch-qr-ratio;
}
.content {
font-size: 10pt * $l10n-ch-qr-ratio;
line-height: 13pt * $l10n-ch-qr-ratio;
}
}
}
.swissqr_column_right {
float: right;
width: $right_col_width;
}
}
.scissors {
width: 16px;
height: 16px;
}
.vertical_scissors {
position: absolute;
top: 5mm * $l10n-ch-qr-ratio;
left: -1.8mm * $l10n-ch-qr-ratio;
}
.horizontal_scissors {
position: absolute;
top: -2mm * $l10n-ch-qr-ratio;
left: 6mm * $l10n-ch-qr-ratio;
}
}

View file

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_ch_qr_code
from . import test_swissqr
from . import test_l10n_ch_isr_print
from . import test_l10n_ch_qr_print
from . import test_vendor_bill_isr
from . import test_onchange_l10n_ch_postal
from . import test_gen_isr_reference

View file

@ -0,0 +1,113 @@
# -*- coding:utf-8 -*-
from reportlab.graphics.barcode import createBarcodeDrawing
from odoo import Command
from odoo.tests import tagged
from odoo.exceptions import UserError
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
@tagged('post_install_l10n', 'post_install', '-at_install')
class TestSwissQRCode(AccountTestInvoicingCommon):
""" Tests the generation of Swiss QR-codes on invoices
"""
@classmethod
def setUpClass(cls, chart_template_ref='l10n_ch.l10nch_chart_template'):
super().setUpClass(chart_template_ref=chart_template_ref)
cls.company_data['company'].qr_code = True
cls.company_data['company'].country_id = None
cls.swiss_iban = cls.env['res.partner.bank'].create({
'acc_number': 'CH15 3881 5158 3845 3843 7',
'partner_id': cls.company_data['company'].partner_id.id,
})
cls.swiss_qr_iban = cls.env['res.partner.bank'].create({
'acc_number': 'CH21 3080 8001 2345 6782 7',
'partner_id': cls.company_data['company'].partner_id.id,
})
cls.ch_qr_invoice = cls.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': cls.partner_a.id,
'currency_id': cls.env.ref('base.CHF').id,
'partner_bank_id': cls.swiss_iban.id,
'company_id': cls.company_data['company'].id,
'payment_reference': "Papa a vu le fifi de lolo",
'invoice_line_ids': [
Command.create({
'quantity': 1,
'price_unit': 100,
'tax_ids': [],
})
],
})
def _assign_partner_address(self, partner):
partner.write({
'country_id': self.env.ref('base.ch').id,
'street': "Crab street, 11",
'city': "Crab City",
'zip': "4242",
})
def test_swiss_qr_code_generation(self):
""" Check different cases of Swiss QR-code generation, when qr_method is
specified beforehand.
"""
self.ch_qr_invoice.qr_code_method = 'ch_qr'
# First check with a regular IBAN
with self.assertRaises(UserError, msg="It shouldn't be possible to generate a Swiss QR-code for partners without a complete Swiss address."):
self.ch_qr_invoice._generate_qr_code()
# Setting the address should make it work
self._assign_partner_address(self.ch_qr_invoice.company_id.partner_id)
self._assign_partner_address(self.ch_qr_invoice.partner_id)
self.ch_qr_invoice._generate_qr_code()
# Now, check with a QR-IBAN as the payment account
self.ch_qr_invoice.partner_bank_id = self.swiss_qr_iban
with self.assertRaises(UserError, msg="It shouldn't be possible to generate a Swiss QR-cde for a QR-IBAN without giving it a valid QR-reference as payment reference."):
self.ch_qr_invoice._generate_qr_code()
# Assigning a QR reference should fix it
self.ch_qr_invoice.payment_reference = '210000000003139471430009017'
# even if the invoice is not issued from Switzerland we want to generate the code
self.ch_qr_invoice.company_id.partner_id.country_id = self.env.ref('base.fr')
self.ch_qr_invoice._generate_qr_code()
def test_ch_qr_code_detection(self):
""" Checks Swiss QR-code auto-detection when no specific QR-method
is given to the invoice.
"""
self._assign_partner_address(self.ch_qr_invoice.company_id.partner_id)
self._assign_partner_address(self.ch_qr_invoice.partner_id)
self.ch_qr_invoice._generate_qr_code()
self.assertEqual(self.ch_qr_invoice.qr_code_method, 'ch_qr', "Swiss QR-code generator should have been chosen for this invoice.")
def test_ch_qr_code_cross_mask(self):
for width, height in ((64, 128), (128, 128), (256, 256), (512, 512)):
barcode = createBarcodeDrawing('QR', value='', format='png', width=width, height=height)
mask_to_apply = self.env['ir.actions.report'].get_available_barcode_masks()['ch_cross']
mask_to_apply(width, height, barcode)
zoom_x = width / (32 * (72 / 25.4))
zoom_y = height / (32 * (72 / 25.4))
self.assertEqual(
[zoom_x, 0, 0, zoom_y, 0, 0],
barcode.transform,
)
self.assertEqual(
(0, 0, 90.70866141732284, 90.70866141732284),
barcode.contents[0].getBounds(),
)
self.assertEqual(
(38.45140157480315, 38.45140157480315, 52.25725984251969, 52.25725984251969),
barcode.contents[1].getBounds(),
)

View file

@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.tests import tagged
QR_IBAN = 'CH21 3080 8001 2345 6782 7'
ISR_SUBS_NUMBER = "01-162-8"
@tagged('post_install_l10n', 'post_install', '-at_install')
class TestGenISRReference(AccountTestInvoicingCommon):
"""Check condition of generation of and content of the structured ref"""
@classmethod
def setUpClass(cls, chart_template_ref="l10n_ch.l10nch_chart_template"):
super().setUpClass(chart_template_ref=chart_template_ref)
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.bank = cls.env["res.bank"].create(
{
"name": "Alternative Bank Schweiz AG",
"bic": "ALSWCH21XXX",
}
)
cls.bank_acc_isr = cls.env["res.partner.bank"].create(
{
"acc_number": "ISR",
"l10n_ch_isr_subscription_chf": "01-162-8",
"bank_id": cls.bank.id,
"partner_id": cls.partner_a.id,
}
)
cls.bank_acc_qriban = cls.env["res.partner.bank"].create(
{
"acc_number": QR_IBAN,
"bank_id": cls.bank.id,
"partner_id": cls.partner_a.id,
}
)
cls.product_a.taxes_id = cls.product_b.taxes_id = None
cls.invoice = cls.init_invoice("out_invoice", products=cls.product_a+cls.product_b)
def test_isr(self):
self.invoice.partner_bank_id = self.bank_acc_isr
self.invoice.name = "INV/01234567890"
# Post invoice to have the expected amount due (amount_residual)
self.invoice.action_post()
expected_isr = "000000000000000012345678903"
expected_isr_spaced = "00 00000 00000 00001 23456 78903"
expected_optical_line = "0100001297203>000000000000000012345678903+ 010001628>"
self.assertEqual(self.invoice.l10n_ch_isr_number, expected_isr)
self.assertEqual(self.invoice.l10n_ch_isr_number_spaced, expected_isr_spaced)
self.assertEqual(self.invoice.l10n_ch_isr_optical_line, expected_optical_line)
def test_qrr(self):
self.invoice.partner_bank_id = self.bank_acc_qriban
self.invoice.name = "INV/01234567890"
expected_isr = "000000000000000012345678903"
expected_isr_spaced = "00 00000 00000 00001 23456 78903"
self.assertEqual(self.invoice.l10n_ch_isr_number, expected_isr)
self.assertEqual(self.invoice.l10n_ch_isr_number_spaced, expected_isr_spaced)
# No need to check optical line, we have no use for it with QR-bill
def test_isr_long_reference(self):
self.invoice.partner_bank_id = self.bank_acc_isr
self.invoice.name = "INV/123456789012345678901234567890"
# Post invoice to have the expected amount due (amount_residual)
self.invoice.action_post()
expected_isr = "567890123456789012345678901"
expected_isr_spaced = "56 78901 23456 78901 23456 78901"
expected_optical_line = "0100001297203>567890123456789012345678901+ 010001628>"
self.assertEqual(self.invoice.l10n_ch_isr_number, expected_isr)
self.assertEqual(self.invoice.l10n_ch_isr_number_spaced, expected_isr_spaced)
self.assertEqual(self.invoice.l10n_ch_isr_optical_line, expected_optical_line)
def test_missing_isr_subscription_num(self):
self.bank_acc_isr.l10n_ch_isr_subscription_chf = False
self.invoice.partner_bank_id = self.bank_acc_isr
self.assertFalse(self.invoice.l10n_ch_isr_number)
self.assertFalse(self.invoice.l10n_ch_isr_number_spaced)
self.assertFalse(self.invoice.l10n_ch_isr_optical_line)
def test_missing_isr_subscription_num_in_wrong_field(self):
self.bank_acc_isr.l10n_ch_isr_subscription_chf = False
self.bank_acc_isr.l10n_ch_postal = ISR_SUBS_NUMBER
self.invoice.partner_bank_id = self.bank_acc_isr
self.assertFalse(self.invoice.l10n_ch_isr_number)
self.assertFalse(self.invoice.l10n_ch_isr_number_spaced)
self.assertFalse(self.invoice.l10n_ch_isr_optical_line)
def test_no_bank_account(self):
self.invoice.partner_bank_id = False
self.assertFalse(self.invoice.l10n_ch_isr_number)
self.assertFalse(self.invoice.l10n_ch_isr_number_spaced)
self.assertFalse(self.invoice.l10n_ch_isr_optical_line)
def test_wrong_currency(self):
self.invoice.partner_bank_id = self.bank_acc_isr
self.invoice.currency_id = self.env.ref("base.BTN")
self.assertFalse(self.invoice.l10n_ch_isr_number)
self.assertFalse(self.invoice.l10n_ch_isr_number_spaced)
self.assertFalse(self.invoice.l10n_ch_isr_optical_line)

View file

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.tests import tagged
from odoo.exceptions import ValidationError
@tagged('post_install_l10n', 'post_install', '-at_install')
class ISRTest(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls, chart_template_ref='l10n_ch.l10nch_chart_template'):
super().setUpClass(chart_template_ref=chart_template_ref)
def print_isr(self, invoice):
try:
invoice.action_invoice_sent()
return True
except ValidationError:
return False
def test_l10n_ch_postals(self):
def assertBankAccountValid(account_number, expected_account_type, expected_postal=None):
partner_bank = self.env['res.partner.bank'].create({
'acc_number': account_number,
'partner_id': self.partner_a.id,
})
expected_vals = {'acc_type': expected_account_type}
if expected_postal is not None:
expected_vals['l10n_ch_postal'] = expected_postal
self.assertRecordValues(partner_bank, [expected_vals])
assertBankAccountValid('010391391', 'postal', expected_postal='010391391')
assertBankAccountValid('CH6309000000250097798', 'iban', expected_postal='25-9779-8')
assertBankAccountValid('GR1601101250000000012300695', 'iban', expected_postal=False)
partner_bank = self.env['res.partner.bank'].create({
'acc_number': '010391394',
'partner_id': self.partner_a.id,
})
self.assertNotEqual(partner_bank.acc_type, 'postal')
def test_isr(self):
isr_bank_account = self.env['res.partner.bank'].create({
'acc_number': "ISR {} number",
'partner_id': self.env.company.partner_id.id,
'l10n_ch_isr_subscription_chf': '01-39139-1',
})
invoice_chf = self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': self.partner_a.id,
'partner_bank_id': isr_bank_account.id,
'currency_id': self.env.ref('base.CHF').id,
'invoice_date': '2019-01-01',
'invoice_line_ids': [(0, 0, {'product_id': self.product_a.id})],
})
invoice_chf.action_post()
self.assertTrue(self.print_isr(invoice_chf))
self.env.ref('base.EUR').active = True
invoice_eur = self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': self.partner_a.id,
'partner_bank_id': isr_bank_account.id,
'currency_id': self.env.ref('base.EUR').id,
'invoice_date': '2019-01-01',
'invoice_line_ids': [(0, 0, {'product_id': self.product_a.id})],
})
invoice_eur.action_post()
#a normal invoice will still get printed
self.assertTrue(self.print_isr(invoice_eur))
# However, a isr bill can't be printed with those infos
self.assertFalse(invoice_eur.l10n_ch_isr_valid)

View file

@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.exceptions import UserError
from odoo.tests import tagged
_logger = logging.getLogger(__name__)
@tagged('post_install_l10n', 'post_install', '-at_install')
class QRPrintTest(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls, chart_template_ref='l10n_ch.l10nch_chart_template'):
super().setUpClass(chart_template_ref=chart_template_ref)
# the partner must be located in Switzerland.
cls.partner = cls.env['res.partner'].create({
'name': 'Bobby',
'country_id': cls.env.ref('base.ch').id,
})
# The bank account must be QR-compatible
cls.qr_bank_account = cls.env['res.partner.bank'].create({
'acc_number': "CH4431999123000889012",
'partner_id': cls.env.company.partner_id.id,
'l10n_ch_isr_subscription_chf': '01-39139-1',
})
cls.correct_invoice_chf = cls.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': cls.partner.id,
'partner_bank_id': cls.qr_bank_account.id,
'currency_id': cls.env.ref('base.CHF').id,
'invoice_date': '2019-01-01',
'invoice_line_ids': [(0, 0, {'product_id': cls.product_a.id})],
})
cls.correct_invoice_eur = cls.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': cls.partner.id,
'partner_bank_id': cls.qr_bank_account.id,
'currency_id': cls.env.ref('base.EUR').id,
'invoice_date': '2019-01-01',
'invoice_line_ids': [(0, 0, {'product_id': cls.product_a.id})],
})
cls.wrong_partner_invoice = cls.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': cls.partner_a.id,
'partner_bank_id': cls.qr_bank_account.id,
'currency_id': cls.env.ref('base.EUR').id,
'invoice_date': '2019-01-01',
'invoice_line_ids': [(0, 0, {'product_id': cls.product_a.id})],
})
def print_qr_bill(self, invoice):
try:
invoice.action_invoice_sent()
return True
except UserError as e:
_logger.warning(e.name)
return False
def test_print_qr(self):
self.correct_invoice_chf.action_post()
self.assertTrue(self.print_qr_bill(self.correct_invoice_chf))
#The QR can also be printed if the currency is EUR
self.env.ref('base.EUR').active = True
self.correct_invoice_eur.action_post()
self.assertTrue(self.print_qr_bill(self.correct_invoice_eur))
#A normal invoice will be printed if the partner is not from Switzerland
self.wrong_partner_invoice.action_post()
self.assertTrue(self.print_qr_bill(self.wrong_partner_invoice))
#However, a qr bill can't be printed with those infos
self.assertFalse(self.wrong_partner_invoice.l10n_ch_is_qr_valid)

View file

@ -0,0 +1,117 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests import tagged
from odoo.tests.common import Form, TransactionCase
CH_ISR_ISSUER = '01-162-8'
CH_IBAN = 'CH15 3881 5158 3845 3843 7'
FR_IBAN = 'FR83 8723 4133 8709 9079 4002 530'
CH_POST_IBAN = 'CH09 0900 0000 1000 8060 7'
CH_POSTAL_ACC = '10-8060-7'
@tagged('post_install_l10n', 'post_install', '-at_install')
class TestOnchangePostal(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.partner = cls.env['res.partner'].create({
'name': 'Swiss Company',
'street': 'Route de Berne 41',
'zip': '1000',
'city': 'Lausanne',
'is_company': 1,
'country_id': cls.env.ref('base.ch').id,
})
cls.ch_bank = cls.env['res.bank'].create({
'name': 'Alternative Bank Schweiz AG',
'bic': 'ALSWCH21XXX',
})
cls.post_bank = cls.env['res.bank'].search(
[('bic', '=', 'POFICHBEXXX')])
if not cls.post_bank:
cls.post_bank = cls.env['res.bank'].create({
'name': 'PostFinance AG',
'bic': 'POFICHBEXXX',
})
def new_partner_bank_form(self):
form = Form(
self.env['res.partner.bank'],
view="l10n_ch.isr_partner_bank_form",
)
form.partner_id = self.partner
return form
def test_onchange_acc_number_isr_issuer(self):
"""The user entered ISR issuer number into acc_number
We detect and move it to l10n_ch_postal.
It must be moved as it is not unique.
"""
bank_acc = self.new_partner_bank_form()
bank_acc.acc_number = CH_ISR_ISSUER
account = bank_acc.save()
self.assertEqual(
account.acc_number,
"{} {}".format(CH_ISR_ISSUER, self.partner.name)
)
self.assertEqual(account.l10n_ch_postal, CH_ISR_ISSUER)
self.assertEqual(account.acc_type, 'postal')
def test_onchange_acc_number_postal(self):
"""The user entered postal number into acc_number
We detect and copy it to l10n_ch_postal.
"""
bank_acc = self.new_partner_bank_form()
bank_acc.acc_number = CH_POSTAL_ACC
account = bank_acc.save()
self.assertEqual(account.acc_number, CH_POSTAL_ACC)
self.assertEqual(account.l10n_ch_postal, CH_POSTAL_ACC)
self.assertEqual(account.acc_type, 'postal')
def test_onchange_acc_number_iban_ch(self):
bank_acc = self.new_partner_bank_form()
bank_acc.acc_number = CH_IBAN
account = bank_acc.save()
self.assertEqual(account.acc_number, CH_IBAN)
self.assertFalse(account.l10n_ch_postal)
self.assertEqual(account.acc_type, 'iban')
def test_onchange_acc_number_iban_ch_postfinance(self):
"""The user enter a postal IBAN, postal number can be deduced"""
bank_acc = self.new_partner_bank_form()
bank_acc.acc_number = CH_POST_IBAN
account = bank_acc.save()
self.assertEqual(account.acc_number, CH_POST_IBAN)
self.assertEqual(account.l10n_ch_postal, CH_POSTAL_ACC)
self.assertEqual(account.acc_type, 'iban')
def test_onchange_acc_number_iban_foreign(self):
"""Check IBAN still works changed"""
bank_acc = self.new_partner_bank_form()
bank_acc.acc_number = FR_IBAN
account = bank_acc.save()
self.assertEqual(account.acc_number, FR_IBAN)
self.assertFalse(account.l10n_ch_postal)
self.assertEqual(account.acc_type, 'iban')
def test_onchange_acc_number_none(self):
"""Check misc format still works"""
bank_acc = self.new_partner_bank_form()
bank_acc.acc_number = 'anything'
account = bank_acc.save()
self.assertEqual(account.acc_number, 'anything')
self.assertFalse(account.l10n_ch_postal)
self.assertEqual(account.acc_type, 'bank')

View file

@ -0,0 +1,223 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import time
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.exceptions import UserError
from odoo.tests import tagged
from odoo.tools.misc import mod10r
CH_IBAN = 'CH15 3881 5158 3845 3843 7'
QR_IBAN = 'CH21 3080 8001 2345 6782 7'
@tagged('post_install_l10n', 'post_install', '-at_install')
class TestSwissQR(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls, chart_template_ref='l10n_ch.l10nch_chart_template'):
super().setUpClass(chart_template_ref=chart_template_ref)
def setUp(self):
super(TestSwissQR, self).setUp()
# Activate SwissQR in Swiss invoices
self.env['ir.config_parameter'].create(
{'key': 'l10n_ch.print_qrcode', 'value': '1'}
)
self.customer = self.env['res.partner'].create(
{
"name": "Partner",
"street": "Route de Berne 41",
"street2": "",
"zip": "1000",
"city": "Lausanne",
"country_id": self.env.ref("base.ch").id,
}
)
self.env.user.company_id.partner_id.write(
{
"street": "Route de Berne 88",
"street2": "",
"zip": "2000",
"city": "Neuchâtel",
"country_id": self.env.ref('base.ch').id,
}
)
self.product = self.env['product.product'].create({
'name': 'Customizable Desk',
})
self.invoice1 = self.create_invoice('base.CHF')
sale_journal = self.env['account.journal'].search([("type", "=", "sale")])
sale_journal.invoice_reference_model = "ch"
def create_invoice(self, currency_to_use='base.CHF'):
""" Generates a test invoice """
account = self.env['account.account'].search(
[('account_type', '=', 'asset_current')], limit=1
)
invoice = (
self.env['account.move']
.create(
{
'move_type': 'out_invoice',
'partner_id': self.customer.id,
'currency_id': self.env.ref(currency_to_use).id,
'date': time.strftime('%Y') + '-12-22',
'invoice_line_ids': [
(
0,
0,
{
'name': self.product.name,
'product_id': self.product.id,
'account_id': account.id,
'quantity': 1,
'price_unit': 42.0,
},
)
],
}
)
)
return invoice
def create_account(self, number):
""" Generates a test res.partner.bank. """
return self.env['res.partner.bank'].create(
{
'acc_number': number,
'partner_id': self.env.user.company_id.partner_id.id,
}
)
def swissqr_not_generated(self, invoice):
""" Prints the given invoice and tests that no Swiss QR generation is triggered. """
self.assertFalse(
invoice.partner_bank_id._eligible_for_qr_code('ch_qr', invoice.partner_id, invoice.currency_id),
'No Swiss QR should be generated for this invoice',
)
def swissqr_generated(self, invoice, ref_type='NON'):
""" Ensure correct params for Swiss QR generation. """
self.assertTrue(
invoice.partner_bank_id._eligible_for_qr_code('ch_qr', invoice.partner_id, invoice.currency_id), 'A Swiss QR can be generated'
)
if ref_type == 'QRR':
self.assertTrue(invoice.payment_reference)
struct_ref = invoice.payment_reference
unstr_msg = invoice.ref or invoice.name or ''
else:
struct_ref = ''
unstr_msg = invoice.payment_reference or invoice.ref or invoice.name or ''
unstr_msg = unstr_msg or invoice.number
payload = (
"SPC\n"
"0200\n"
"1\n"
"{iban}\n"
"K\n"
"company_1_data\n"
"Route de Berne 88\n"
"2000 Neuchâtel\n"
"\n\n"
"CH\n"
"\n\n\n\n\n\n\n"
"42.00\n"
"CHF\n"
"K\n"
"Partner\n"
"Route de Berne 41\n"
"1000 Lausanne\n"
"\n\n"
"CH\n"
"{ref_type}\n"
"{struct_ref}\n"
"{unstr_msg}\n"
"EPD"
).format(
iban=invoice.partner_bank_id.sanitized_acc_number,
ref_type=ref_type,
struct_ref=struct_ref or '',
unstr_msg=unstr_msg,
)
expected_params = {
'barcode_type': 'QR',
'barLevel': 'M',
'width': 256,
'height': 256,
'quiet': 1,
'mask': 'ch_cross',
'value': payload,
}
params = invoice.partner_bank_id._get_qr_code_generation_params(
'ch_qr', 42.0, invoice.currency_id, invoice.partner_id, unstr_msg, struct_ref
)
self.assertEqual(params, expected_params)
def test_swissQR_missing_bank(self):
# Let us test the generation of a SwissQR for an invoice, first by showing an
# QR is included in the invoice is only generated when Odoo has all the data it needs.
with self.assertRaises(UserError), self.cr.savepoint():
self.invoice1.action_post()
self.swissqr_not_generated(self.invoice1)
def test_swissQR_iban(self):
# Now we add an account for payment to our invoice
# Here we don't use a structured reference
iban_account = self.create_account(CH_IBAN)
self.invoice1.partner_bank_id = iban_account
self.invoice1.action_post()
self.swissqr_generated(self.invoice1, ref_type="NON")
def test_swissQR_qriban(self):
# Now use a proper QR-IBAN, we are good to print a QR Bill
qriban_account = self.create_account(QR_IBAN)
self.assertTrue(qriban_account.l10n_ch_qr_iban)
self.invoice1.partner_bank_id = qriban_account
self.invoice1.action_post()
self.swissqr_generated(self.invoice1, ref_type="QRR")
def test_swiss_order_reference_isr_for_qr_code(self):
"""
Test that the order reference is correctly generated for QR-Code
We summon the skipTest if Sale is not installed (instead of creating a whole module for one test)
"""
if 'sale.order' not in self.env:
self.skipTest('`sale` is not installed')
payment_custom = self.env['ir.module.module']._get('payment_custom')
if payment_custom.state != 'installed':
self.skipTest("payment_custom module is not installed")
provider = self.env['payment.provider'].create({
'name': 'Test',
'code': 'custom',
})
invoice_journal = self.env['account.journal'].search(
[('type', '=', 'sale'), ('company_id', '=', self.env.company.id)], limit=1)
invoice_journal.write({'invoice_reference_model': 'ch'})
order = self.env['sale.order'].create({
'name': "S00001",
'partner_id': self.env['res.partner'].search([("name", '=', 'Partner')])[0].id,
'order_line': [
(0, 0, {'product_id': self.product_a.id, 'price_unit': 100}),
],
})
payment_transaction = self.env['payment.transaction'].create({
'provider_id': provider.id,
'sale_order_ids': [order.id],
'partner_id': self.env['res.partner'].search([("name", '=', 'Partner')])[0].id,
'amount': 100,
'currency_id': self.env.company.currency_id.id,
})
payment_transaction._set_pending()
self.assertEqual(order.reference, mod10r(order.reference[:-1]))

View file

@ -0,0 +1,124 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests import Form, common, tagged
from odoo.exceptions import ValidationError
CH_ISR_SUBSCRIPTION = "01-162-8"
CH_POSTAL = "10-8060-7"
CH_IBAN = "CH15 3881 5158 3845 3843 7"
ISR_REFERENCE_GOOD = "16 00011 23456 78901 23456 78901"
ISR_REFERENCE_ZEROS = "00 00000 00000 00001 23456 78903"
ISR_REFERENCE_NO_ZEROS = "1 23456 78903"
ISR_REFERENCE_BAD = "11 11111 11111 11111 11111 11111"
@tagged('post_install_l10n', 'post_install', '-at_install')
class TestVendorBillISR(common.TransactionCase):
"""Check we can encode Vendor bills with ISR references
The ISR is a structured reference with a checksum.
User are guided to ensure they don't encode wrong ISR references.
Only vendors with ISR issuer accounts send ISR references.
ISR references can be received at least till 2022.
"""
@classmethod
def setUpClass(cls):
super(TestVendorBillISR, cls).setUpClass()
cls.abs_bank = cls.env["res.bank"].create(
{"name": "Alternative Bank Schweiz", "bic": "ABSOCH22XXX"}
)
cls.supplier1 = cls.env["res.partner"].create({"name": "Supplier ISR"})
cls.supplier2 = cls.env["res.partner"].create({"name": "Supplier postal"})
cls.supplier3 = cls.env["res.partner"].create({"name": "Supplier IBAN"})
cls.bank_acc_isr = cls.env['res.partner.bank'].create({
"acc_number": "ISR 01-162-8 Supplier ISR",
"partner_id": cls.supplier1.id,
"l10n_ch_postal": CH_ISR_SUBSCRIPTION,
})
cls.bank_acc_postal = cls.env['res.partner.bank'].create({
"acc_number": CH_POSTAL,
"partner_id": cls.supplier2.id,
"l10n_ch_postal": CH_POSTAL,
})
cls.bank_acc_iban = cls.env['res.partner.bank'].create({
"acc_number": CH_IBAN,
"partner_id": cls.supplier2.id,
"l10n_ch_postal": False,
})
def test_isr_ref(self):
"""Enter ISR reference with ISR subscription account number
The vendor bill can be saved.
"""
self.env.company.country_id = self.env.ref('base.ch')
self.env.company.account_fiscal_country_id = self.env.company.country_id
form = Form(self.env["account.move"].with_context(
default_move_type="in_invoice"), view="l10n_ch.isr_invoice_form")
form.partner_id = self.supplier1
form.partner_bank_id = self.bank_acc_isr
form.payment_reference = ISR_REFERENCE_GOOD
invoice = form.save()
self.assertFalse(invoice.l10n_ch_isr_needs_fixing)
def test_isr_ref_with_zeros(self):
"""Enter ISR reference with ISR subscription account number
An ISR Reference can have lots of zeros on the left.
The vendor bill can be saved.
"""
self.env.company.country_id = self.env.ref('base.ch')
self.env.company.account_fiscal_country_id = self.env.company.country_id
form = Form(self.env["account.move"].with_context(
default_move_type="in_invoice"), view="l10n_ch.isr_invoice_form")
form.partner_id = self.supplier1
form.partner_bank_id = self.bank_acc_isr
form.payment_reference = ISR_REFERENCE_ZEROS
invoice = form.save()
self.assertFalse(invoice.l10n_ch_isr_needs_fixing)
def test_isr_ref_no_zeros(self):
"""Enter ISR reference with ISR subscription account number
An ISR Reference full of zeros can be entered starting by the
first non zero digit.
The vendor bill can be saved.
"""
self.env.company.country_id = self.env.ref('base.ch')
self.env.company.account_fiscal_country_id = self.env.company.country_id
form = Form(self.env["account.move"].with_context(
default_move_type="in_invoice"), view="l10n_ch.isr_invoice_form")
form.partner_id = self.supplier1
form.partner_bank_id = self.bank_acc_isr
form.payment_reference = ISR_REFERENCE_NO_ZEROS
invoice = form.save()
self.assertFalse(invoice.l10n_ch_isr_needs_fixing)
def test_isr_wrong_ref(self):
"""Mistype ISR reference with ISR subscription account number
Check it will show the warning
"""
self.env.company.country_id = self.env.ref('base.ch')
self.env.company.account_fiscal_country_id = self.env.company.country_id
form = Form(self.env["account.move"].with_context(
default_move_type="in_invoice"), view="l10n_ch.isr_invoice_form")
form.partner_id = self.supplier1
form.partner_bank_id = self.bank_acc_isr
form.payment_reference = ISR_REFERENCE_BAD
invoice = form.save()
self.assertTrue(invoice.l10n_ch_isr_needs_fixing)

View file

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<odoo>
<template id="l10n_ch_report_invoice_document" inherit_id="account.report_invoice_document">
<xpath expr="//div[@id='qrcode']" position="attributes">
<attribute name="t-if" add="and o.qr_code_method != 'ch_qr'" separator=" "/>
</xpath>
</template>
</odoo>

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="isr_invoice_form" model="ir.ui.view">
<field name="name">l10n_ch.account.invoice.form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='is_move_sent']" position="after">
<field name="l10n_ch_isr_sent" invisible="1"/>
<field name="l10n_ch_currency_name" invisible="1" readonly="1"/>
<field name="l10n_ch_is_qr_valid" invisible="1"/>
</xpath>
<header position="after">
<field name="l10n_ch_isr_needs_fixing" invisible="1"/>
<div groups="account.group_account_invoice" class="alert alert-warning" role="alert" style="margin-bottom:0px;" attrs="{'invisible': [('l10n_ch_isr_needs_fixing', '=', False)]}">
Please fill in a correct ISR reference in the payment reference. The banks will refuse your payment file otherwise.
</div>
</header>
</field>
</record>
<record id="isr_invoice_search_view" model="ir.ui.view">
<field name="name">l10n_ch.invoice.select</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_account_invoice_filter"/>
<field name="mode">primary</field>
<field name="arch" type="xml">
<xpath expr="//search" position="inside">
<field name="l10n_ch_isr_number" string="ISR reference number"/>
</xpath>
</field>
</record>
<!--Overridden action (and primary child view), so the filter are only
available for customer invoices-->
<record id="account.action_move_out_invoice_type" model="ir.actions.act_window">
<field name="name">Customer Invoices</field>
<field name="res_model">account.move</field>
<field name="search_view_id" ref="isr_invoice_search_view"/>
</record>
<record id="l10n_ch_qr_server_action" model="ir.actions.server">
<field name="name">Print QR Invoices</field>
<field name="model_id" ref="account.model_account_move"/>
<field name="binding_model_id" ref="account.model_account_move"/>
<field name="binding_view_types">list</field>
<field name="state">code</field>
<field name="code">
if records:
action = records.l10n_ch_action_print_qr()
</field>
</record>
</data>
</odoo>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="l10n_ch_qr_invoice_wizard_form" model="ir.ui.view">
<field name="name">l10n_ch.qr_invoice.wizard.form</field>
<field name="model">l10n_ch.qr_invoice.wizard</field>
<field name="arch" type="xml">
<form string="QR printing encountered a problem">
<field name='nb_qr_inv' invisible="1"/>
<field name="nb_classic_inv" invisible="1"/>
<field name="nb_isr_inv" invisible="1"/>
<p>
<field name="qr_inv_text"/>
<field name="isr_inv_text"/>
<field name="classic_inv_text"/>
</p>
<p>
To be able to print all invoices in the QR format, you might need to : <br/>
- check the account is a valid QR-IBAN<br/>
- or check your company and the partners are located in Switzerland.<br/>
Press Check Invalid Invoices to see a list of the invoices that were printed without an ISR or a QR.
</p>
<footer>
<button name="print_all_invoices" string="Print All" type="object" class="btn-primary"/>
<button name="action_view_faulty_invoices" string="Check invalid invoices" type="object"/>
</footer>
</form>
</field>
</record>
<record id="l10n_ch_qr_invoice_wizard" model="ir.actions.act_window">
<field name="name">Qr Batch error Wizard</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">l10n_ch.qr_invoice.wizard</field>
<field name="view_mode">form</field>
<field name="view_id" ref="l10n_ch_qr_invoice_wizard_form"/>
<field name="target">new</field>
</record>
</odoo>

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="isr_partner_bank_form" model="ir.ui.view">
<field name="name">l10n_ch.res.partner.bank.form</field>
<field name="model">res.partner.bank</field>
<field name="inherit_id" ref="base.view_partner_bank_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='acc_number']" position="after">
<field name="l10n_ch_qr_iban" attrs="{'invisible': [('l10n_ch_show_subscription', '=', False)]}"/>
<label for="l10n_ch_postal" string="ISR Client Identification Number" attrs="{'invisible': [('l10n_ch_show_subscription', '=', False)]}"/>
<field name="l10n_ch_postal" nolabel="1" attrs="{'invisible': [('l10n_ch_show_subscription', '=', False)]}"/>
<field name="l10n_ch_postal" attrs="{'invisible': [('l10n_ch_show_subscription', '=', True)]}"/>
<field name="l10n_ch_show_subscription" invisible="1"/>
<field name="l10n_ch_isr_subscription_chf" attrs="{'invisible': [('l10n_ch_show_subscription', '=', False)]}"/>
<field name="l10n_ch_isr_subscription_eur" attrs="{'invisible': [('l10n_ch_show_subscription', '=', False)]}"/>
</xpath>
</field>
</record>
<record id="isr_partner_bank_tree" model="ir.ui.view">
<field name="name">l10n_ch.res.partner.bank.tree</field>
<field name="model">res.partner.bank</field>
<field name="inherit_id" ref="base.view_partner_bank_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='acc_number']" position="after">
<field name="l10n_ch_postal" invisible="1"/>
</xpath>
</field>
</record>
<record id="isr_partner_property_bank_tree" model="ir.ui.view">
<field name="name">l10n_ch.res.partner.property.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="account.view_partner_property_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='acc_number']" position="after">
<field name="l10n_ch_postal" invisible="1"/>
</xpath>
</field>
</record>
</data>
</odoo>

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.l10n.ch</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="account.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='invoicing_settings']" position="inside">
<div class="col-12 col-lg-6 o_setting_box" id="l10n_ch-isr_print_bank" attrs="{'invisible': [('country_code', '!=', 'CH')]}">
<div class="o_setting_left_pane">
<field name="l10n_ch_isr_print_bank_location"/>
</div>
<div class="o_setting_right_pane">
<label for="l10n_ch_isr_print_bank_location"/>
<div class="text-muted">
Print the coordinates of your bank under the &apos;Payment for&apos; title of the ISR.
Your address will be moved to the &apos;in favour of&apos; section.
</div>
<div class="content-group" attrs="{'invisible': [('l10n_ch_isr_print_bank_location', '=', False)]}">
<div class="row mt16">
<label for="l10n_ch_isr_preprinted_bank" class="col-lg-4 o_light_label"/>
<field name="l10n_ch_isr_preprinted_bank"/>
</div>
<div class="row">
<label for="l10n_ch_isr_preprinted_account" class="col-lg-4 o_light_label"/>
<field name="l10n_ch_isr_preprinted_account"/>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box" id="l10n_ch-isr_print_scanline_offset" attrs="{'invisible': [('country_code', '!=', 'CH')]}">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<span class="o_form_label">ISR scan line offset</span>
<div class="text-muted">
Offset to move the scan line in mm
</div>
<div class="content-group">
<div class="row mt16">
<label for="l10n_ch_isr_scan_line_top" class="col-lg-4 o_light_label"/>
<field name="l10n_ch_isr_scan_line_top"/>
</div>
<div class="row">
<label for="l10n_ch_isr_scan_line_left" class="col-lg-4 o_light_label"/>
<field name="l10n_ch_isr_scan_line_left"/>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>
</data>
</odoo>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="setup_bank_account_wizard_inherit" model="ir.ui.view">
<field name="name">account.setup.bank.manual.config.form.ch.inherit</field>
<field name="model">account.setup.bank.manual.config</field>
<field name="inherit_id" ref="account.setup_bank_account_wizard"/>
<field name="arch" type="xml">
<field name="bank_bic" position="after">
<field name="l10n_ch_show_subscription" invisible="1"/>
<field name="l10n_ch_isr_subscription_chf" attrs="{'invisible': [('l10n_ch_show_subscription', '=', False)]}"/>
<label for="l10n_ch_postal" string="ISR Client Identification Number" attrs="{'invisible': [('l10n_ch_show_subscription', '=', False)]}"/>
<field name="l10n_ch_postal" nolabel="1" attrs="{'invisible': [('l10n_ch_show_subscription', '=', False)]}"/>
<field name="l10n_ch_qr_iban" attrs="{'invisible': [('l10n_ch_show_subscription', '=', False)]}"/>
</field>
</field>
</record>
</data>
</odoo>

View file

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import setup_wizards
from . import qr_invoice_wizard

View file

@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class QrInvoiceWizard(models.TransientModel):
'''
Wizard :
When multiple invoices are selected to be printed in the QR-Iban format,
this wizard will appear if one or more invoice(s) could not be QR-printed (wrong format...)
The user will then be able to print the invoices (in the format available, priority : QR --> ISR --> normal)
or to see a list of the non-QR/ISR invoices.
The non-QR/ISR invoices will have a note logged in their chatter, detailing the reason of the failure.
'''
_name = 'l10n_ch.qr_invoice.wizard'
_description = 'Handles problems occurring while creating multiple QR-invoices at once'
nb_qr_inv = fields.Integer(readonly=True)
nb_isr_inv = fields.Integer(readonly=True)
nb_classic_inv = fields.Integer(readonly=True)
qr_inv_text = fields.Text(readonly=True)
isr_inv_text = fields.Text(readonly=True)
classic_inv_text = fields.Text(readonly=True)
@api.model
def default_get(self, fields):
# Extends 'base'.
def determine_invoices_text(nb_inv, inv_format):
'''
Creates a sentence explaining nb_inv invoices could be printed in the inv_format format.
'''
if nb_inv == 0:
return _("No invoice could be printed in the %s format.", inv_format)
if nb_inv == 1:
return _("One invoice could be printed in the %s format.", inv_format)
return _("%s invoices could be printed in the %s format.", nb_inv, inv_format)
if not self._context.get('active_ids'):
raise UserError(_("No invoice was found to be printed."))
invoices = self.env['account.move'].browse(self._context['active_ids'])
companies = invoices.company_id
if len(companies) != 1 or companies[0].country_code != 'CH':
raise UserError(_("All selected invoices must belong to the same Switzerland company"))
results = super().default_get(fields)
dispatched_invoices = invoices._l10n_ch_dispatch_invoices_to_print()
results.update({
'nb_qr_inv': len(dispatched_invoices['qr']),
'nb_isr_inv': len(dispatched_invoices['isr']),
'nb_classic_inv': len(dispatched_invoices['classic']),
'qr_inv_text': determine_invoices_text(nb_inv=len(dispatched_invoices['qr']), inv_format="QR"),
'isr_inv_text': determine_invoices_text(nb_inv=len(dispatched_invoices['isr']), inv_format="ISR"),
'classic_inv_text': determine_invoices_text(nb_inv=len(dispatched_invoices['classic']),
inv_format="classic"),
})
return results
def print_all_invoices(self):
'''
Triggered by the Print All button
'''
all_invoices_ids = self.env.context.get('inv_ids')
return self.env.ref('account.account_invoices').report_action(all_invoices_ids)
def action_view_faulty_invoices(self):
'''
Open a list view of all the invoices that could not be printed in the QR nor the ISR format.
'''
# Prints the error stopping the invoice from being QR-printed in the invoice's chatter.
invoices = self.env['account.move'].browse(self._context['active_ids'])
dispatched_invoices = invoices._l10n_ch_dispatch_invoices_to_print()
faulty_invoices = dispatched_invoices['classic']
# Log a message inside the chatter explaining why the invoice is faulty.
for inv in faulty_invoices:
try:
# The error potentially raised in the following function helps create the wizard's message.
inv.partner_bank_id._eligible_for_qr_code('ch_qr', inv.partner_id, inv.currency_id, raises_error=True)
except UserError as e:
inv.message_post(body=e.name, message_type="comment")
action_vals = {
'name': _("Invalid Invoices"),
'type': 'ir.actions.act_window',
'res_model': 'account.move',
'context': {'create': False},
}
if len(faulty_invoices) == 1:
action_vals.update({
'view_mode': 'form',
'res_id': faulty_invoices.id,
})
else:
action_vals.update({
'view_mode': 'tree',
'domain': [('id', 'in', faulty_invoices.ids)],
})
return action_vals

View file

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
from odoo import api, models
class SwissSetupBarBankConfigWizard(models.TransientModel):
_inherit = 'account.setup.bank.manual.config'
@api.onchange('acc_number')
def _onchange_recompute_qr_iban(self):
# Needed because ORM doesn't properly call the compute in 'new' mode, due to inherits, and
# we want this field to be displayed in the wizard. We need to manually set acc_number
# on the inherits m2o before calling the compute function manually.
self.res_partner_bank_id.acc_number = self.acc_number
self.res_partner_bank_id._compute_l10n_ch_qr_iban()
self.l10n_ch_qr_iban = self.res_partner_bank_id.l10n_ch_qr_iban