diff --git a/__init__.py b/__init__.py index 383fb5c..8d4ba77 100644 --- a/__init__.py +++ b/__init__.py @@ -60,6 +60,7 @@ def register(): folio.StatisticsByMonthStart, folio.Folio, folio.FolioCharge, + folio.HotelFolioTax, folio.FolioStockMove, folio.OpenMigrationStart, stock.Move, diff --git a/booking.py b/booking.py index 3bca53a..e104552 100644 --- a/booking.py +++ b/booking.py @@ -15,6 +15,7 @@ from trytond.transaction import Transaction from trytond.pool import Pool from trytond.exceptions import UserError from trytond.i18n import gettext +from trytond.modules.account.tax import TaxableMixin from .constants import ( STATE_BOOKING, REGISTRATION_STATE, REASON, GUARANTEE, SATISFACTION, MEDIA, PLAN, INVOICE_METHOD, COMPLEMENTARY, PAYMENT_METHOD_CHANNEL, @@ -65,7 +66,6 @@ class Booking(Workflow, ModelSQL, ModelView): 'invisible': ~Bool(Eval('complementary')), 'required': Bool(Eval('complementary')), }) - # rename to channel channel = fields.Many2One('hotel.channel', 'Channel', states={ 'invisible': Eval('media') != 'ota', @@ -291,6 +291,48 @@ class Booking(Workflow, ModelSQL, ModelView): now = datetime.now() return now + def _round_taxes(self, taxes): + if not self.currency: + return + for taxline in taxes.values(): + taxline['amount'] = self.currency.round(taxline['amount']) + + def _get_taxes(self): + pool = Pool() + Tax = pool.get('account.tax') + Configuration = pool.get('account.configuration') + + taxes = {} + with Transaction().set_context({}): + config = Configuration(1) + tax_rounding = config.get_multivalue('tax_rounding') + + def compute(_taxes, unit_price, quantity): + l_taxes = Tax.compute(Tax.browse(_taxes), unit_price, quantity) + for tax in l_taxes: + taxline = TaxableMixin._compute_tax_line(**tax) + # Base must always be rounded per folio as there will be one + # tax folio per taxable_lines + if self.currency: + taxline['base'] = self.currency.round(taxline['base']) + if taxline not in taxes: + taxes[taxline] = taxline + else: + taxes[taxline]['base'] += taxline['base'] + taxes[taxline]['amount'] += taxline['amount'] + if tax_rounding == 'line': + self._round_taxes(taxes) + + for folio in self.lines: + compute(folio.taxes, folio.unit_price, folio.nights_quantity) + + for charge in folio.charges: + compute(folio.taxes, charge.unit_price, charge.quantity) + + if tax_rounding == 'document': + self._round_taxes(taxes) + return taxes + def get_invoices(self, name=None): res = [] for folio in self.lines: @@ -969,22 +1011,24 @@ class Booking(Workflow, ModelSQL, ModelView): return res def get_tax_amount(self, name): - Tax = Pool().get('account.tax') - Booking = Pool().get('hotel.booking') - - res = _ZERO - for line in self.lines: - taxes_ids = Booking.get_taxes(line.product) - if taxes_ids: - taxes = Tax.browse(taxes_ids) - tax_list = Tax.compute( - taxes, line.unit_price or _ZERO, line.nights_quantity or 0 - ) - - tax_amount = sum([t['amount'] for t in tax_list], _ZERO) - res += tax_amount - - res = Decimal(round(res, 2)) + # Tax = Pool().get('account.tax') + # Booking = Pool().get('hotel.booking') + # + # res = _ZERO + # for folio in self.lines: + # taxes_ids = Booking.get_taxes(line.product) + # if taxes_ids: + # taxes = Tax.browse(taxes_ids) + # tax_list = Tax.compute( + # taxes, line.unit_price or _ZERO, line.nights_quantity or 0 + # ) + # + # tax_amount = sum([t['amount'] for t in tax_list], _ZERO) + # res += tax_amount + # + # res = Decimal(round(res, 2)) + taxes_computed = self._get_taxes() + res = sum([t['amount'] for t in taxes_computed], _ZERO) return res def get_untaxed_amount(self, name): diff --git a/folio.py b/folio.py index dfade19..f3df1a1 100644 --- a/folio.py +++ b/folio.py @@ -140,6 +140,13 @@ class Folio(ModelSQL, ModelView): stock_moves = fields.Function(fields.One2Many('stock.move', 'origin', 'Moves', readonly=True), 'get_stock_moves') vehicle_plate = fields.Char('Vehicle Plate') + taxes = fields.Many2Many('hotel.folio-account.tax', 'folio', 'tax', 'Taxes', + order=[('tax.sequence', 'ASC'), ('tax.id', 'ASC')], + domain=[('parent', '=', None), ['OR', + ('group', '=', None), + ('group.kind', 'in', ['sale', 'both'])], + ], + ) @classmethod def __setup__(cls): @@ -228,6 +235,10 @@ class Folio(ModelSQL, ModelView): gettext('hotel.msg_room_no_clean', s=self.room.name) ) + # def get_tax_amount(self): + # return sum( + # (v['amount'] for v in self._get_taxes().values()), Decimal(0)) + @classmethod @ModelView.button def check_out(cls, records): @@ -1737,3 +1748,13 @@ class RegistrationCardReport(Report): _records.append(rec) report_context['records'] = _records return report_context + + +class HotelFolioTax(ModelSQL): + 'Hotel Folio - Tax' + __name__ = 'hotel.folio-account.tax' + _table = 'hotel_folio_account_tax' + folio = fields.Many2One('hotel.folio', 'Folio', ondelete='CASCADE', + select=True, required=True) + tax = fields.Many2One('account.tax', 'Tax', ondelete='RESTRICT', + select=True, required=True) diff --git a/statement.fodt b/statement.fodt index dba6c0d..a2be929 100644 Binary files a/statement.fodt and b/statement.fodt differ diff --git a/tryton.cfg b/tryton.cfg index f7cb1c7..802ea5d 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -1,5 +1,5 @@ [tryton] -version=6.0.25 +version=6.0.26 depends: party company diff --git a/view/board_folio_form.xml b/view/board_folio_form.xml index 180d3c9..7382ae2 100644 --- a/view/board_folio_form.xml +++ b/view/board_folio_form.xml @@ -37,6 +37,9 @@ this repository contains the full copyright notices and license terms. --> + + + diff --git a/view/booking_folio_form.xml b/view/booking_folio_form.xml index b5b37d7..a895433 100644 --- a/view/booking_folio_form.xml +++ b/view/booking_folio_form.xml @@ -35,6 +35,9 @@ this repository contains the full copyright notices and license terms. --> + + +