Files
2026-02-04 10:12:56 +01:00

316 lines
12 KiB
Python

# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from sql import Null
from sql.aggregate import Min, Sum
from trytond.model import ModelSQL, ModelView, fields
from trytond.modules.account.exceptions import FiscalYearNotFoundError
from trytond.modules.currency.fields import Monetary
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval
from trytond.transaction import Transaction
VATEX_CODES = [
('VATEX-EU-79-C',
"Exempt based on article 79, point c of Council Directive "
"2006/112/EC"),
('VATEX-EU-132',
"Exempt based on article 132 of Council Directive 2006/112/EC"),
('VATEX-EU-132-1A',
"Exempt based on article 132, section 1 (a) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1B',
"Exempt based on article 132, section 1 (b) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1C',
"Exempt based on article 132, section 1 (c) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1D',
"Exempt based on article 132, section 1 (d) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1E',
"Exempt based on article 132, section 1 (e) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1F',
"Exempt based on article 132, section 1 (f) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1G',
"Exempt based on article 132, section 1 (g) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1H',
"Exempt based on article 132, section 1 (h) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1I',
"Exempt based on article 132, section 1 (i) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1J',
"Exempt based on article 132, section 1 (j) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1K',
"Exempt based on article 132, section 1 (k) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1L',
"Exempt based on article 132, section 1 (l) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1M',
"Exempt based on article 132, section 1 (m) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1N',
"Exempt based on article 132, section 1 (n) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1O',
"Exempt based on article 132, section 1 (o) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1P',
"Exempt based on article 132, section 1 (p) of Council Directive "
"2006/112/EC"),
('VATEX-EU-132-1Q',
"Exempt based on article 132, section 1 (q) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143',
"Exempt based on article 143 of Council Directive 2006/112/EC"),
('VATEX-EU-143-1A',
"Exempt based on article 143, section 1 (a) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1B',
"Exempt based on article 143, section 1 (b) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1C',
"Exempt based on article 143, section 1 (c) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1D',
"Exempt based on article 143, section 1 (d) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1E',
"Exempt based on article 143, section 1 (e) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1F',
"Exempt based on article 143, section 1 (f) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1FA',
"Exempt based on article 143, section 1 (fa) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1G',
"Exempt based on article 143, section 1 (g) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1H',
"Exempt based on article 143, section 1 (h) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1I',
"Exempt based on article 143, section 1 (i) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1J',
"Exempt based on article 143, section 1 (j) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1K',
"Exempt based on article 143, section 1 (k) of Council Directive "
"2006/112/EC"),
('VATEX-EU-143-1L',
"Exempt based on article 143, section 1 (l) of Council Directive "
"2006/112/EC"),
('VATEX-EU-144',
"Exempt based on article 144 of Council Directive 2006/112/EC"),
('VATEX-EU-146-1E',
"Exempt based on article 146 section 1 (e) of Council Directive "
"2006/112/EC"),
('VATEX-EU-148',
"Exempt based on article 148 of Council Directive 2006/112/EC"),
('VATEX-EU-148-A',
"Exempt based on article 148, section (a) of Council Directive "
"2006/112/EC"),
('VATEX-EU-148-B',
"Exempt based on article 148, section (b) of Council Directive "
"2006/112/EC"),
('VATEX-EU-148-C',
"Exempt based on article 148, section (c) of Council Directive "
"2006/112/EC"),
('VATEX-EU-148-D',
"Exempt based on article 148, section (d) of Council Directive "
"2006/112/EC"),
('VATEX-EU-148-E',
"Exempt based on article 148, section (e) of Council Directive "
"2006/112/EC"),
('VATEX-EU-148-F',
"Exempt based on article 148, section (f) of Council Directive "
"2006/112/EC"),
('VATEX-EU-148-G',
"Exempt based on article 148, section (g) of Council Directive "
"2006/112/EC"),
('VATEX-EU-151',
"Exempt based on article 151 of Council Directive 2006/112/EC"),
('VATEX-EU-151-1A',
"Exempt based on article 151, section 1 (a) of Council Directive "
"2006/112/EC"),
('VATEX-EU-151-1AA',
"Exempt based on article 151, section 1 (aa) of Council Directive "
"2006/112/EC"),
('VATEX-EU-151-1B',
"Exempt based on article 151, section 1 (b) of Council Directive "
"2006/112/EC"),
('VATEX-EU-151-1C',
"Exempt based on article 151, section 1 (c) of Council Directive "
"2006/112/EC"),
('VATEX-EU-151-1D',
"Exempt based on article 151, section 1 (d) of Council Directive "
"2006/112/EC"),
('VATEX-EU-151-1E',
"Exempt based on article 151, section 1 (e) of Council Directive "
"2006/112/EC"),
('VATEX-EU-159',
"Exempt based on article 159 of Council Directive 2006/112/EC"),
('VATEX-EU-309',
"Exempt based on article 309 of Council Directive 2006/112/EC"),
('VATEX-EU-AE', "Reverse charge"),
('VATEX-EU-D',
"Intra-Community acquisition from second hand means of transport"),
('VATEX-EU-F', "Intra-Community acquisition of second hand goods"),
('VATEX-EU-G', "Export outside the EU"),
('VATEX-EU-I', "Intra-Community acquisition of works of art"),
('VATEX-EU-IC', "Intra-Community supply"),
('VATEX-EU-O', "Not subject to VAT"),
('VATEX-EU-J',
"Intra-Community acquisition of collectors items and antiques"),
]
class TaxTemplate(metaclass=PoolMeta):
__name__ = 'account.tax.template'
ec_sales_list_code = fields.Char("EC Sales List Code")
vatex_code = fields.Selection(
'get_vatex_codes', "Tax Exemption Code")
def _get_tax_value(self, tax=None):
value = super()._get_tax_value(tax=tax)
if not tax or tax.ec_sales_list_code != self.ec_sales_list_code:
value['ec_sales_list_code'] = self.ec_sales_list_code
if not tax or tax.vatex_code != self.vatex_code:
value['vatex_code'] = self.vatex_code
return value
@classmethod
def get_vatex_codes(cls):
pool = Pool()
Tax = pool.get('account.tax')
return Tax.fields_get(['vatex_code'])['vatex_code']['selection']
class Tax(metaclass=PoolMeta):
__name__ = 'account.tax'
ec_sales_list_code = fields.Char("EC Sales List Code",
states={
'readonly': (Bool(Eval('template', -1))
& ~Eval('template_override', False)),
})
vatex_code = fields.Selection(
[(None, "")] + VATEX_CODES, "Tax Exemption Code", sort=False,
states={
'readonly': (Bool(Eval('template', -1))
& ~Eval('template_override', False)),
},
help="The reason why the amount is exempted from VAT.")
class ECSalesList(ModelSQL, ModelView):
__name__ = 'account.ec_sales_list'
company_tax_identifier = fields.Many2One(
'party.identifier', "Company Tax Identifier")
party = fields.Many2One('party.party', "Party")
party_tax_identifier = fields.Many2One(
'party.identifier', "Party Tax Identifier")
code = fields.Char("Code")
amount = Monetary(
"Amount", currency='currency', digits='currency')
currency = fields.Many2One('currency.currency', "Currency")
@classmethod
def table_query(cls):
pool = Pool()
Company = pool.get('company.company')
Invoice = pool.get('account.invoice')
Move = pool.get('account.move')
Line = pool.get('account.move.line')
TaxLine = pool.get('account.tax.line')
Period = pool.get('account.period')
Tax = pool.get('account.tax')
context = Transaction().context
company = Company.__table__()
invoice = Invoice.__table__()
move = Move.__table__()
line = Line.__table__()
tax_line = TaxLine.__table__()
period = Period.__table__()
tax = Tax.__table__()
where = invoice.company == context.get('company')
if context.get('fiscalyear'):
where &= (period.fiscalyear == context.get('fiscalyear'))
if context.get('period'):
where &= (period.id == context.get('period'))
if context.get('start_date'):
where &= (move.date >= context.get('start_date'))
if context.get('end_date'):
where &= (move.date <= context.get('end_date'))
where &= ((tax.ec_sales_list_code != Null)
& (tax.ec_sales_list_code != ''))
where &= tax_line.type == 'base'
where &= invoice.type == 'out'
return (tax_line
.join(tax, condition=tax_line.tax == tax.id)
.join(line, condition=tax_line.move_line == line.id)
.join(move, condition=line.move == move.id)
.join(period, condition=move.period == period.id)
.join(invoice, condition=invoice.move == move.id)
.join(company, condition=company.id == invoice.company)
.select(
Min(tax_line.id).as_('id'),
invoice.tax_identifier.as_('company_tax_identifier'),
invoice.party.as_('party'),
invoice.party_tax_identifier.as_('party_tax_identifier'),
tax.ec_sales_list_code.as_('code'),
Sum(tax_line.amount).as_('amount'),
company.currency.as_('currency'),
where=where,
group_by=[
invoice.tax_identifier,
invoice.party,
invoice.party_tax_identifier,
tax.ec_sales_list_code,
company.currency,
]))
class ECSalesListContext(ModelView):
__name__ = 'account.ec_sales_list.context'
company = fields.Many2One('company.company', "Company", required=True)
fiscalyear = fields.Many2One(
'account.fiscalyear', "Fiscal Year", required=True,
domain=[
('company', '=', Eval('company', -1)),
])
period = fields.Many2One(
'account.period', "Period",
domain=[
('fiscalyear', '=', Eval('fiscalyear', -1)),
])
@classmethod
def default_company(cls):
return Transaction().context.get('company')
@classmethod
def default_fiscalyear(cls):
pool = Pool()
FiscalYear = pool.get('account.fiscalyear')
context = Transaction().context
if 'fiscalyear' not in context:
try:
fiscalyear = FiscalYear.find(
cls.default_company(), test_state=False)
except FiscalYearNotFoundError:
return None
return fiscalyear.id
return context['fiscalyear']