2015-02-04 22:59:37 +01:00
|
|
|
# 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 trytond.model import fields
|
2021-12-11 17:58:42 +01:00
|
|
|
from trytond.pool import Pool, PoolMeta
|
2019-08-18 19:03:12 +02:00
|
|
|
from trytond.pyson import Eval
|
2015-02-04 22:59:37 +01:00
|
|
|
|
|
|
|
|
|
2019-08-18 19:03:12 +02:00
|
|
|
class TaxRule(metaclass=PoolMeta):
|
|
|
|
|
__name__ = 'account.tax.rule'
|
|
|
|
|
|
|
|
|
|
def apply(self, tax, pattern):
|
|
|
|
|
pool = Pool()
|
|
|
|
|
Subdivision = pool.get('country.subdivision')
|
|
|
|
|
|
|
|
|
|
def parents(subdivision):
|
|
|
|
|
while subdivision:
|
|
|
|
|
yield subdivision.id
|
|
|
|
|
subdivision = subdivision.parent
|
|
|
|
|
|
|
|
|
|
pattern = pattern.copy()
|
2024-04-08 12:13:33 +02:00
|
|
|
pattern.setdefault('from_country')
|
|
|
|
|
pattern.setdefault('to_country')
|
2019-08-18 19:03:12 +02:00
|
|
|
for name in ['from_subdivision', 'to_subdivision']:
|
|
|
|
|
subdivision = pattern.pop(name, None)
|
|
|
|
|
if not subdivision:
|
|
|
|
|
continue
|
|
|
|
|
subdivision = Subdivision(subdivision)
|
|
|
|
|
pattern[name] = list(parents(subdivision))
|
|
|
|
|
return super().apply(tax, pattern)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _TaxRuleLineMixin:
|
2019-09-07 23:45:08 +02:00
|
|
|
__slots__ = ()
|
2019-08-18 19:03:12 +02:00
|
|
|
from_country = fields.Many2One(
|
|
|
|
|
'country.country', 'From Country', ondelete='RESTRICT',
|
|
|
|
|
help="Apply only to addresses of this country.")
|
|
|
|
|
from_subdivision = fields.Many2One(
|
|
|
|
|
'country.subdivision', "From Subdivision", ondelete='RESTRICT',
|
|
|
|
|
domain=[
|
|
|
|
|
('country', '=', Eval('from_country', -1)),
|
|
|
|
|
],
|
|
|
|
|
states={
|
|
|
|
|
'invisible': ~Eval('from_country'),
|
|
|
|
|
},
|
|
|
|
|
help="Apply only to addresses in this subdivision.")
|
|
|
|
|
to_country = fields.Many2One(
|
|
|
|
|
'country.country', 'To Country', ondelete='RESTRICT',
|
|
|
|
|
help="Apply only to addresses of this country.")
|
|
|
|
|
to_subdivision = fields.Many2One(
|
|
|
|
|
'country.subdivision', "To Subdivision", ondelete='RESTRICT',
|
|
|
|
|
domain=[
|
|
|
|
|
('country', '=', Eval('to_country', -1)),
|
|
|
|
|
],
|
|
|
|
|
states={
|
|
|
|
|
'invisible': ~Eval('to_country'),
|
|
|
|
|
},
|
|
|
|
|
help="Apply only to addresses in this subdivision.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TaxRuleLineTemplate(_TaxRuleLineMixin, metaclass=PoolMeta):
|
2015-02-04 22:59:37 +01:00
|
|
|
__name__ = 'account.tax.rule.line.template'
|
|
|
|
|
|
2016-03-21 23:37:35 +01:00
|
|
|
def _get_tax_rule_line_value(self, rule_line=None):
|
2025-04-04 00:45:18 +02:00
|
|
|
value = super()._get_tax_rule_line_value(
|
2016-03-21 23:37:35 +01:00
|
|
|
rule_line=rule_line)
|
|
|
|
|
if not rule_line or rule_line.from_country != self.from_country:
|
|
|
|
|
value['from_country'] = (
|
|
|
|
|
self.from_country.id if self.from_country else None)
|
2019-08-18 19:03:12 +02:00
|
|
|
if (not rule_line
|
|
|
|
|
or rule_line.from_subdivision != self.from_subdivision):
|
|
|
|
|
value['from_subdivision'] = (
|
|
|
|
|
self.from_subdivision.id if self.from_subdivision else None)
|
2016-03-21 23:37:35 +01:00
|
|
|
if not rule_line or rule_line.to_country != self.to_country:
|
|
|
|
|
value['to_country'] = (
|
|
|
|
|
self.to_country.id if self.to_country else None)
|
2019-08-18 19:03:12 +02:00
|
|
|
if (not rule_line
|
|
|
|
|
or rule_line.to_subdivision != self.to_subdivision):
|
|
|
|
|
value['to_subdivision'] = (
|
|
|
|
|
self.to_subdivision.id if self.to_subdivision else None)
|
2016-03-21 23:37:35 +01:00
|
|
|
return value
|
|
|
|
|
|
2015-02-04 22:59:37 +01:00
|
|
|
|
2019-08-18 19:03:12 +02:00
|
|
|
class TaxRuleLine(_TaxRuleLineMixin, metaclass=PoolMeta):
|
2015-02-04 22:59:37 +01:00
|
|
|
__name__ = 'account.tax.rule.line'
|
2019-08-18 19:03:12 +02:00
|
|
|
|
|
|
|
|
def match(self, pattern):
|
|
|
|
|
for name in ['from_subdivision', 'to_subdivision']:
|
|
|
|
|
subdivision = getattr(self, name)
|
|
|
|
|
if name not in pattern:
|
|
|
|
|
if subdivision:
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
continue
|
|
|
|
|
pattern = pattern.copy()
|
|
|
|
|
subdivisions = pattern.pop(name)
|
|
|
|
|
if (subdivision is not None
|
|
|
|
|
and subdivision.id not in subdivisions):
|
|
|
|
|
return False
|
|
|
|
|
return super().match(pattern)
|
2015-02-04 22:59:37 +01:00
|
|
|
|
|
|
|
|
|
2018-06-26 19:11:45 +02:00
|
|
|
class InvoiceLine(metaclass=PoolMeta):
|
2015-02-04 22:59:37 +01:00
|
|
|
__name__ = 'account.invoice.line'
|
|
|
|
|
|
2018-05-31 13:25:29 +02:00
|
|
|
@fields.depends('origin')
|
2015-02-04 22:59:37 +01:00
|
|
|
def _get_tax_rule_pattern(self):
|
|
|
|
|
pool = Pool()
|
2021-04-10 14:02:31 +02:00
|
|
|
try:
|
|
|
|
|
SaleLine = pool.get('sale.line')
|
|
|
|
|
except KeyError:
|
|
|
|
|
SaleLine = None
|
|
|
|
|
try:
|
|
|
|
|
PurchaseLine = pool.get('purchase.line')
|
|
|
|
|
except KeyError:
|
|
|
|
|
PurchaseLine = None
|
2024-08-01 16:04:41 +02:00
|
|
|
try:
|
|
|
|
|
Move = pool.get('stock.move')
|
|
|
|
|
ShipmentOut = pool.get('stock.shipment.out')
|
|
|
|
|
ShipmentOutReturn = pool.get('stock.shipment.out.return')
|
|
|
|
|
except KeyError:
|
|
|
|
|
Move = ShipmentOut = ShipmentOutReturn = None
|
2015-02-04 22:59:37 +01:00
|
|
|
|
2025-04-04 00:45:18 +02:00
|
|
|
pattern = super()._get_tax_rule_pattern()
|
2015-02-04 22:59:37 +01:00
|
|
|
|
2019-08-18 19:03:12 +02:00
|
|
|
from_country = from_subdivision = to_country = to_subdivision = None
|
2026-03-18 12:01:17 +01:00
|
|
|
origin = self.origin
|
|
|
|
|
# find the first origin which is not an invoice line
|
|
|
|
|
while isinstance(origin, self.__class__) and origin.id >= 0:
|
|
|
|
|
origin = origin.origin
|
2021-04-23 20:33:03 +02:00
|
|
|
if (SaleLine
|
2026-03-18 12:01:17 +01:00
|
|
|
and isinstance(origin, SaleLine)
|
|
|
|
|
and origin.id >= 0):
|
|
|
|
|
warehouse = origin.warehouse
|
2021-06-09 08:31:59 +02:00
|
|
|
if warehouse and warehouse.address:
|
|
|
|
|
from_country = warehouse.address.country
|
|
|
|
|
from_subdivision = warehouse.address.subdivision
|
2026-03-18 12:01:17 +01:00
|
|
|
shipment_address = origin.sale.shipment_address
|
2019-08-18 19:03:12 +02:00
|
|
|
to_country = shipment_address.country
|
|
|
|
|
to_subdivision = shipment_address.subdivision
|
2021-04-23 20:33:03 +02:00
|
|
|
elif (PurchaseLine
|
2026-03-18 12:01:17 +01:00
|
|
|
and isinstance(origin, PurchaseLine)
|
|
|
|
|
and origin.id >= 0):
|
|
|
|
|
invoice_address = origin.purchase.invoice_address
|
2019-08-18 19:03:12 +02:00
|
|
|
from_country = invoice_address.country
|
|
|
|
|
from_subdivision = invoice_address.subdivision
|
2026-03-18 12:01:17 +01:00
|
|
|
warehouse = origin.warehouse
|
2021-06-09 08:31:59 +02:00
|
|
|
if warehouse and warehouse.address:
|
|
|
|
|
to_country = warehouse.address.country
|
|
|
|
|
to_subdivision = warehouse.address.subdivision
|
2024-08-01 16:04:41 +02:00
|
|
|
elif (Move
|
2026-03-18 12:01:17 +01:00
|
|
|
and isinstance(origin, Move)
|
|
|
|
|
and origin.id >= 0):
|
|
|
|
|
move = origin
|
2024-08-01 16:04:41 +02:00
|
|
|
if move.from_location.warehouse:
|
|
|
|
|
warehouse_address = move.from_location.warehouse.address
|
|
|
|
|
if warehouse_address:
|
|
|
|
|
from_country = warehouse_address.country
|
|
|
|
|
from_subdivision = warehouse_address.subdivision
|
|
|
|
|
elif isinstance(move.origin, ShipmentOutReturn):
|
|
|
|
|
delivery_address = move.origin.delivery_address
|
|
|
|
|
from_country = delivery_address.country
|
|
|
|
|
from_subdivision = delivery_address.subdivision
|
|
|
|
|
if move.to_location.warehouse:
|
|
|
|
|
warehouse_address = move.to_location.warehouse.address
|
|
|
|
|
if warehouse_address:
|
|
|
|
|
to_country = warehouse_address.country
|
|
|
|
|
to_subdivision = warehouse_address.subdivision
|
|
|
|
|
elif isinstance(move.origin, ShipmentOut):
|
|
|
|
|
delivery_address = move.origin.delivery_address
|
|
|
|
|
to_country = delivery_address.country
|
|
|
|
|
to_subdivision = delivery_address.subdivision
|
2015-02-04 22:59:37 +01:00
|
|
|
|
|
|
|
|
pattern['from_country'] = from_country.id if from_country else None
|
2019-08-18 19:03:12 +02:00
|
|
|
pattern['from_subdivision'] = (
|
|
|
|
|
from_subdivision.id if from_subdivision else None)
|
2015-02-04 22:59:37 +01:00
|
|
|
pattern['to_country'] = to_country.id if to_country else None
|
2019-08-18 19:03:12 +02:00
|
|
|
pattern['to_subdivision'] = (
|
|
|
|
|
to_subdivision.id if to_subdivision else None)
|
2015-02-04 22:59:37 +01:00
|
|
|
return pattern
|