# 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 datetime import datetime from trytond.model import ModelView, Workflow, ModelSQL, fields from trytond.pool import Pool from trytond.pyson import Eval, In, If, Get from trytond.modules.company import CompanyReport from trytond.wizard import Wizard, StateView, Button, StateTransition from trytond.transaction import Transaction from trytond.exceptions import UserError from trytond.i18n import gettext STATES = { 'readonly': Eval('state') == 'checked' } STATES_LINE = { 'readonly': Eval('state') == 'loaded' } class ServiceKind(ModelSQL, ModelView): 'Service Kind' __name__ = 'hotel.service.kind' name = fields.Char('Name', select=True, required=True) product = fields.Many2One('product.product', 'Product') salable = fields.Boolean('Salable') category = fields.Selection([ ('breakfast', 'Breakfast'), ('restaurant', 'Restaurant'), ('laundry', 'Laundry'), ('spa', 'Spa'), ], 'Category') class Service(Workflow, ModelSQL, ModelView): 'Service' __name__ = 'hotel.service' _rec_name = 'kind.name' number = fields.Char('Number', select=True, required=False) kind = fields.Many2One('hotel.service.kind', 'Kind', required=True, states={ 'readonly': Eval('state').in_(['confirmed', 'checked']) }) service_date = fields.Date('Date', required=True, states={ 'readonly': Eval('state').in_(['confirmed', 'checked']) }) lines = fields.One2Many('hotel.service.line', 'service', 'Lines', states={'readonly': Eval('state') != 'open'} ) state = fields.Selection([ ('draft', 'Draft'), ('open', 'Open'), ('confirmed', 'Confirmed'), ('checked', 'Checked'), ], 'State', readonly=True, states=STATES) state_string = state.translated('state') description = fields.Char('Description', select=True, states=STATES) count_services = fields.Function(fields.Integer('Count Services', select=True), 'get_count_services') company = fields.Many2One('company.company', 'Company', required=True, states=STATES, domain=[('id', If(In('company', Eval('context', {})), '=', '!='), Get(Eval('context', {}), 'company', 0))]) @classmethod def __setup__(cls): super(Service, cls).__setup__() cls._order.insert(0, ('service_date', 'DESC')) cls._transitions |= set(( ('draft', 'open'), ('open', 'confirmed'), ('confirmed', 'open'), ('confirmed', 'checked'), )) cls._buttons.update({ 'draft': { 'invisible': Eval('state') != 'open', }, 'open': { 'invisible': Eval('state') != 'draft', }, 'confirm': { 'invisible': Eval('state') != 'open', }, 'checked': { 'invisible': Eval('state') != 'confirmed', }, }) @staticmethod def default_state(): return 'draft' @staticmethod def default_company(): return Transaction().context.get('company') @classmethod @ModelView.button @Workflow.transition('draft') def draft(cls, records): pass @classmethod @ModelView.button @Workflow.transition('open') def open(cls, records): cls.set_number(records) @classmethod @ModelView.button @Workflow.transition('confirmed') def confirm(cls, records): pass @classmethod @ModelView.button @Workflow.transition('checked') def checked(cls, records): pass def get_count_services(self, name=None): return len(self.lines) @classmethod def set_number(cls, services): """ Fill the number field with the service sequence """ Config = Pool().get('hotel.configuration') config = Config.get_configuration() for service in services: if service.number or not config.hotel_service_sequence: continue number = config.hotel_service_sequence.get() cls.write([service], {'number': number}) class ServiceLine(Workflow, ModelSQL, ModelView): 'Service Line' __name__ = 'hotel.service.line' service = fields.Many2One('hotel.service', 'Service', required=True) room = fields.Many2One('hotel.room', 'Room', select=True, required=True, states=STATES_LINE) time_service = fields.Time('Time Service', select=True, states=STATES_LINE) product = fields.Many2One('product.product', 'Product', domain=[ ('salable', '=', True), ('active', '=', True), ], required=True) quantity = fields.Integer('Quantity', required=True, states=STATES_LINE) description = fields.Char('Description', states=STATES_LINE) order = fields.Char('Order', select=True, states=STATES_LINE) folio_line = fields.Many2One('hotel.folio', 'Folio Line', states={'readonly': True}) guest = fields.Char('Guest', states=STATES_LINE) charge = fields.Many2One('hotel.folio.charge', 'Operation Line', states={'readonly': True}) folio = fields.Many2One('hotel.folio', 'Folio', domain=[ ('room', '=', Eval('room')), ('registration_state', '=', 'check_in') ], depends=['room']) state = fields.Selection([ ('draft', 'Draft'), ('loaded', 'Loaded'), ('deleted', 'Deleted'), ('done', 'Done'), ], 'State', readonly=True) state_string = state.translated('state') @classmethod def __setup__(cls): super(ServiceLine, cls).__setup__() cls._transitions |= set(( ('draft', 'invoiced'), ('draft', 'loaded'), ('draft', 'done'), ('loaded', 'draft'), )) cls._buttons.update({ 'draft': { 'invisible': ~Eval('state').in_(['invoiced']), }, 'load': { 'invisible': Eval('state') != 'draft', }, 'done': { 'invisible': Eval('state') != 'draft', }, }) @staticmethod def default_quantity(): return 1 @staticmethod def default_state(): return 'draft' @staticmethod def default_time_service(): Company = Pool().get('company.company') local_date = Company.convert_timezone(datetime.now()) return local_date.time() @fields.depends('product', 'description') def on_change_product(self): if self.product: self.description = self.product.name @classmethod @ModelView.button @Workflow.transition('loaded') def load(cls, records): for record in records: record.add_product_to_room() @classmethod @ModelView.button @Workflow.transition('draft') def draft(cls, records): pass @classmethod @ModelView.button @Workflow.transition('done') def done(cls, records): pass def add_product_to_room(self): FolioCharge = Pool().get('hotel.folio.charge') if self.folio_line: return # if not folios: # raise UserError( # gettext('hotel.msg_room_not_occupied', s=self.room.name) # ) # elif len(folios) > 1: # raise UserError( # gettext('hotel.msg_multiple_rooms_active', s=self.room.name) # ) # folio = folios[0] new_line = { 'folio': self.folio.id, 'date_service': self.service.service_date, 'order': self.order, 'description': self.description, 'quantity': int(self.quantity), 'invoice_to': self.folio.main_guest.id, 'unit_price': self.product.template.list_price, 'product': self.product.id, 'to_invoice': True, 'state': '', } line, = FolioCharge.create([new_line]) self.write([self], {'charge': line.id}) class ServiceReport(CompanyReport): __name__ = 'hotel.service' @classmethod def get_context(cls, records, header, data): report_context = super().get_context(records, header, data) return report_context class CreateDailyServicesStart(ModelView): 'Create Daily Services Start' __name__ = 'hotel.daily_services.start' kind = fields.Many2One('hotel.service.kind', 'Kind', required=True, domain=[ ('category', '=', 'breakfast'), ('product', '!=', None) ]) date = fields.Date('Date', required=True) company = fields.Many2One('company.company', 'Company', required=True) description = fields.Char('Description') @staticmethod def default_company(): return Transaction().context.get('company') class CreateDailyServices(Wizard): 'Create Daily Services' __name__ = 'hotel.daily_services' start = StateView('hotel.daily_services.start', 'hotel.create_daily_services_start_view_form', [ Button('Cancel', 'end', 'tryton-cancel'), Button('Accept', 'accept_', 'tryton-ok', default=True), ]) accept_ = StateTransition() def transition_accept_(self): pool = Pool() Service = pool.get('hotel.service') Folio = pool.get('hotel.folio') folios = Folio.search([ ('arrival_date', '<', self.start.date), # ('departure_date', '<', self.start.date), ('registration_state', 'in', ['check_in']), ]) lines_to_create = [] service, = Service.create([{ 'service_date': self.start.date, 'state': 'draft', 'kind': self.start.kind.id, }]) Service.open([service]) product = self.start.kind.product for fol in folios: if not fol.breakfast_included: continue for guest in fol.guests: if guest.party: guest_name = guest.party.name else: guest_name = fol.main_guest.name lines_to_create.append({ 'folio': fol.id, 'service': service.id, 'room': fol.room.id, 'guest': guest_name, 'product': product.id, 'quantity': 1, }) if lines_to_create: ServiceLine.create(lines_to_create) return 'end'