diff --git a/__init__.py b/__init__.py index 63a1389..64c571d 100644 --- a/__init__.py +++ b/__init__.py @@ -64,6 +64,7 @@ def register(): dash.DashApp, dash.AppHotelPlanner, invoice.InvoiceLine, + invoice.Invoice, # folio.TransferfolioStart, # folio.TransferChargeStart, # folio.CheckOutfolioFailed, diff --git a/booking.py b/booking.py index 1ae0403..587f09b 100644 --- a/booking.py +++ b/booking.py @@ -64,6 +64,7 @@ class Booking(Workflow, ModelSQL, ModelView): 'invisible': ~Bool(Eval('complementary')), 'required': Bool(Eval('complementary')), }) + # rename to channel party_seller = fields.Many2One('hotel.channel', 'Channel', states=STATES_CHECKIN, help="Agency or channel that do reservation.") state = fields.Selection(STATE_BOOKING, 'State', readonly=True, @@ -132,6 +133,8 @@ class Booking(Workflow, ModelSQL, ModelView): pending_to_pay = fields.Function(fields.Numeric('Pending to Pay', digits=(16, 2)), 'get_pending_to_pay') breakfast_included = fields.Boolean('Breakfast Included') + channel_commission = fields.Function(fields.Numeric('Channel Commission', + digits=(16, 2), depends=['lines']), 'get_channel_commission') @classmethod def __setup__(cls): @@ -512,14 +515,6 @@ class Booking(Workflow, ModelSQL, ModelView): invoice.on_change_invoice_type() invoice.save() - # Here add payments to invoice - # if rec.get('vouchers'): - # for v in rec['vouchers']: - # SaleVoucher.create([{ - # 'voucher': v.id, - # 'sale': sale.id - # }]) - # Add and create default charges lines if exists if rec.get('guests_qty') and rec.get('add_default_charges'): for product in config.default_charges: @@ -556,8 +551,6 @@ class Booking(Workflow, ModelSQL, ModelView): }) invoice.save() invoice.update_taxes([invoice]) - # for payment in self.payments: - # pass @classmethod def _get_new_invoice(cls, data): @@ -700,12 +693,17 @@ class Booking(Workflow, ModelSQL, ModelView): res += line.total_amount return res - def get_occupancies(self, name): - occupancies = set() - for line in self.lines: - if line.occupancy_line: - occupancies.add(line.occupancy_line.id) - return list(occupancies) + # def get_occupancies(self, name): + # occupancies = set() + # for line in self.lines: + # if line.occupancy_line: + # occupancies.add(line.occupancy_line.id) + # return list(occupancies) + + def get_channel_commission(self, name): + res = sum(line.commission_amount for line in self.lines if + line.commission_amount) + return res def send_email_to(self): pool = Pool() diff --git a/channel.py b/channel.py index dad3df7..717f2a3 100644 --- a/channel.py +++ b/channel.py @@ -1,5 +1,6 @@ # This file is part of Presik. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. +from decimal import Decimal from trytond.model import ModelView, ModelSQL, fields from trytond.pyson import Eval, If from trytond.transaction import Transaction @@ -14,24 +15,25 @@ class SaleChannel(ModelSQL, ModelView): type_commission = fields.Selection([ ('percentage', 'Percentage'), ('fixed', 'Fixed'), - ], 'Type Commission', required=True) + ], 'Type Commission', required=True) + # Remove this field company = fields.Many2One('company.company', 'Company', required=True, domain=[ ('id', If(Eval('context', {}).contains('company'), '=', '!='), Eval('context', {}).get('company', 0)), ], select=True) - commission = fields.Numeric('Commission', required=True, digits=(16, 2)) + commission = fields.Float('Commission', required=True, digits=(4, 2)) debit_account = fields.Many2One('account.account', 'Debit Account', domain=[ ('company', '=', Eval('company')), ('kind', 'not in', ['view']), - ], + ], depends=['company', 'type_commission']) credit_account = fields.Many2One('account.account', 'Credit Account', domain=[ ('company', '=', Eval('company')), ('kind', 'not in', ['view']), - ], + ], depends=['company', 'type_commission']) taxes = fields.Many2Many('hotel.channel-account.tax', 'channel', 'tax', 'Channel Taxes', @@ -69,6 +71,10 @@ class SaleChannel(ModelSQL, ModelView): if company: return Company(company).currency.id + def compute(self, amount): + res = Decimal(round(float(amount) * self.commission / 100, 2)) + return res + class ChannelTax(ModelSQL): 'Channel - Tax' diff --git a/folio.py b/folio.py index 33f5819..54fa71c 100644 --- a/folio.py +++ b/folio.py @@ -92,14 +92,15 @@ class Folio(ModelSQL, ModelView): num_children = fields.Function(fields.Integer('No. Children'), 'get_num_children') nights_quantity = fields.Function(fields.Integer('Nights'), - 'get_nights_quantity') + 'on_change_with_nights_quantity') host_quantity = fields.Integer('Host', states=STATES_CHECKIN) unit_digits = fields.Function(fields.Integer('Unit Digits'), 'get_unit_digits') notes = fields.Text('Notes') total_amount = fields.Function(fields.Numeric('Total Amount', digits=(16, 2)), 'get_total_amount') - total_commission = fields.Function(fields.Numeric('Channel Commission', - digits=(16, 2)), 'get_channel_commission') + commission_amount = fields.Numeric('Commission Amount', digits=(16, 2), + depends=['product', 'departure_date', 'arrival_date'] + ) guests = fields.One2Many('hotel.folio.guest', 'folio', 'Guests', states={'readonly': Eval('registration_state').in_(['check_out'])}) nationality = fields.Many2One('party.nationality', 'Nationality', @@ -135,7 +136,7 @@ class Folio(ModelSQL, ModelView): 'readonly': Eval('registration_state') != 'check_in', }) room_amount = fields.Function(fields.Numeric('Room Amount', - digits=(16, 2)), 'get_room_amount') + digits=(16, 2)), 'get_change_with_room_amount') stock_moves = fields.Many2Many('hotel.folio-stock.move', 'folio', 'move', 'Stock Moves', states={'readonly': True}) @@ -276,7 +277,8 @@ class Folio(ModelSQL, ModelView): res = value['base'] + value['amount'] return res - def get_room_amount(self, name=None): + @fields.depends('unit_price_w_tax', 'nights_quantity') + def get_change_with_room_amount(self, name=None): res = 0 Date = Pool().get('ir.date') if self.unit_price_w_tax and self.nights_quantity: @@ -365,39 +367,6 @@ class Folio(ModelSQL, ModelView): raise UserError(gettext('hotel.msg_invalid_arrival_date')) if self.arrival_date >= self.departure_date: raise UserError(gettext('hotel.msg_invalid_date')) - # Operation = Pool().get('hotel.operation') - # operations = Operation.search([ - # ('room', '=', self.room.id), - # ['AND', - # ['OR', [ - # ('start_date', '>=', self.arrival_date), - # ('end_date', '<=', self.arrival_date), - # ], [ - # ('start_date', '>=', self.departure_date), - # ('end_date', '<=', self.departure_date), - # ]] - # ] - # ]) - # if operations: - # raise AccessError(gettext('hotel.msg_occupied_room', s=self.departure_date)) - # config = Pool().get('hotel.configuration')(1) - # quarantine_days = config.quarantine_rooms - # room_id = self.room.id - # if quarantine_days: - # delta = timedelta(days=int(quarantine_days)) - # _date = self.arrival_date - delta - # operations = Operation.search([ - # ['AND', - # ['OR', [ - # ('room', '=', room_id), - # ('end_date', '=', _date) - # ], - # [ - # ('room', '=', room_id), - # ('end_date', '=', self.arrival_date) - # ]]]]) - # if operations: - # raise AccessError(gettext('hotel.msg_restring_room', s=self.room.name)) def get_state(self, name): if self.booking: @@ -460,7 +429,7 @@ class Folio(ModelSQL, ModelView): return list(rooms_available_ids) @fields.depends('arrival_date', 'departure_date') - def get_nights_quantity(self, name=None): + def on_change_with_nights_quantity(self, name=None): """ Compute nights between start and end return a integer the mean days of occupancy. @@ -485,15 +454,18 @@ class Folio(ModelSQL, ModelView): res = round(sum(res), Folio.total_amount.digits[1]) return res - def get_channel_commission(self, name): + @fields.depends('arrival_date', 'departure_date', 'product') + def on_change_with_commission_amount(self): """ - Calculation of sale commission for channel based on booking total amount + Calculation of commission amount for channel based on booking """ + print(' - - - - >', self.arrival_date, self.product, self.departure_date) res = Decimal(0) - # if self.total_amount and self.booking.party_seller and \ - # self.booking.party_seller.agent.sale_commission: - # res = self.total_amount * self.booking.party_seller.sale_commission / 100 - return res + if all([self.arrival_date, self.product, self.departure_date]): + if self.booking.party_seller: + print(self.room_amount) + res = self.booking.party_seller.compute(self.room_amount) + return res class FolioGuest(ModelSQL, ModelView): diff --git a/invoice.py b/invoice.py index d0c3f97..6bb906b 100644 --- a/invoice.py +++ b/invoice.py @@ -18,10 +18,21 @@ class Invoice(metaclass=PoolMeta): # if self.purchase.invoice_method != 'manual': # print(' qty ', qty) for invoice in invoices: - invoice.set_advances_from_booking() + if invoice.type == 'out': + cls.set_advances_from_origin(invoice) - def set_advances_from_booking(self): - pass + @classmethod + def set_advances_from_origin(cls, invoice): + advances_to_add = [] + vouchers = [] + for line in invoice.lines: + if line.origin and line.origin.__name__ == 'hotel.booking': + booking = line.origin + if not booking.vouchers: + continue + vouchers.extend(booking.vouchers) + if vouchers: + invoice.create_move_advance(set(vouchers)) class InvoiceLine(metaclass=PoolMeta): diff --git a/view/booking_folio_form.xml b/view/booking_folio_form.xml index a8253d0..c6bce76 100644 --- a/view/booking_folio_form.xml +++ b/view/booking_folio_form.xml @@ -36,6 +36,8 @@ this repository contains the full copyright notices and license terms. --> + diff --git a/view/booking_form.xml b/view/booking_form.xml index 6cd4440..7ab2ffd 100644 --- a/view/booking_form.xml +++ b/view/booking_form.xml @@ -72,6 +72,8 @@ this repository contains the full copyright notices and license terms. -->