commit a9a4e59882c4e14aa2afd6c9aeb32b04f61a3f1a Author: Dario Lodeiros Date: Thu Jul 26 13:06:48 2018 +0200 First Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..be0ddc715 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.pyc + +.settings/ + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..dc36e45bd --- /dev/null +++ b/.travis.yml @@ -0,0 +1,45 @@ +language: python + +python: + - "2.7" + +sudo: false +cache: pip + +addons: + postgresql: "9.2" # minimal postgresql version for the daterange method + apt: + packages: + - expect-dev # provides unbuffer utility + - python-lxml # because pip installation is slow + # needed because server-tools is loaded in the dependency chain + - unixodbc-dev + - python-mysqldb + +env: + global: + - VERSION="10.0" TESTS="0" LINT_CHECK="0" TRANSIFEX="0" UNIT_TEST="0" +# - TRANSIFEX_USER='transbot@odoo-community.org' +# - secure: "XLhGdCIh86zcqww9qBpnk8Xqsf1Pcgw9SKr7X0KYBHJofHj4Z6Kq/oVFjpZ1LSjadsaABKbwY7h4hvKEpxZwptCv+fNTOKYy7hXFLGYnDeNeWu4zA4LI7TA5uPvyZjZ+g2xc+9dzR/VbfRHNqjvmgiEidxxqLeOnNFZ5CHdOdCw=" + matrix: + # Option temporarily disabled + #- LINT_CHECK="1" + - TESTS="1" ODOO_REPO="odoo/odoo" + - TESTS="1" ODOO_REPO="OCA/OCB" + +virtualenv: + system_site_packages: true + +install: + - git clone https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools --depth=1 + - export PATH=${HOME}/maintainer-quality-tools/travis:${PATH} + - travis_install_nightly + - git clone -b ${VERSION} https://github.com/OCA/web.git ${HOME}/dependencies/web --depth=1 + - git clone -b ${VERSION} https://github.com/OCA/partner-contact.git ${HOME}/dependencies/partner-contact --depth=1 + - git clone -b ${VERSION} https://github.com/OCA/account-payment.git ${HOME}/dependencies/account_payment_return --depth=1 + +script: + - travis_wait travis_run_tests + +after_success: + - travis_after_tests_success diff --git a/README.md b/README.md new file mode 100644 index 000000000..356c7bf5f --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# HOOTEL PROJECT MODULES [![Build Status](https://travis-ci.org/hootel/hootel.svg?branch=10.0)](https://travis-ci.org/hootel/hootel) [![codecov](https://codecov.io/gh/hootel/hootel/branch/10.0/graph/badge.svg)](https://codecov.io/gh/hootel/hootel) ![Unstable](https://img.shields.io/badge/stability-unstable-yellow.svg) + + +**IMPORTANT:** + - Set time zone of users that use the calendar + +**MODULES:** + - [x] hotel: Base module (Inspired by the work of SerpentCS Hotel Module) + - [x] hotel_calendar: Adds calendar for manage hotel reservations and rooms configuration + - [x] hotel_calendar_wubook: Unify 'hotel_wubook_prototype' and 'hotel_calendar' modules + - [x] hotel_data_bi: Export reservations data for Revenue to MyDataBI + - [x] hotel_l10n_es: Procedures for check-in process in Spain + - [ ] hotel_wubook: NOTHING... the idea is use Odoo Connector + - [x] hotel_wubook_prototype: Current implementation of Wubook Connector... sync data with wubook.net account. + - [ ] hotel_node_slave: Configure a node as a slave to serve and get information from a master one + - [ ] hotel_node_master: Configure a node as a master + - [ ] glasof_exporter: Export Odoo data to Glasof xls format + - [x] hotel_revenue: Export Odoo data for Revenue in xls format + - [x] cash_daily_report: Export Odoo Payments & Payment Returns to xls format + - [x] invoice_payments_report: Add payments info in invoices + - [x] theme_chatter_right: Puts chatter to the right + - [x] report_qweb_pdf_preview: Adds new report_type to generate pdf and launch preview/print process + - [x] l10n_es_events_scraper: Gets info about relevant events in Spain + +**HOW WORKS?** + - The idea is... the hotel sell 'virtual rooms' and the customer is assigned to one 'normal room'. + - The folio have all reservation lines, used services... diff --git a/hotel/Doc/ChangeLog.txt b/hotel/Doc/ChangeLog.txt new file mode 100644 index 000000000..9e2d7b790 --- /dev/null +++ b/hotel/Doc/ChangeLog.txt @@ -0,0 +1,28 @@ +============================================================================================================================ + Version Change Log (hotel) +============================================================================================================================ +0.07 on 2013-10-31 by Murtuza Saleh + *Improved hotel.room kanban view as per in v9. + +0.06 on 2013-10-29 by Ashish Thakkar + *Set the product_category_tree_view in the hotel_view.xml file. + *Improved the code to get the hierarchy in rooms,amenities and services. + +0.05 on 2013-10-28 by Anu Patel + * Set the default value of check in date and check out date. + * Improved calculation of duration for hotel check in - checkout. + +0.04 on 2013-10-28 by Anu Patel + * Improved ir.sequence for hotel.folio. + * Improved hotel folio line one2many field as faced problem because of product_uos field. + +0.03 on 2013-10-25 by Anu Patel + * Improved on_change in hotel folio line where product_id onchange is not working. + * Removed on_chage from .xml file as there is no need to define there. + +0.02 on 2013-10-26 by Anu Patel + * Improved the code for removed the workflow in hotel folio as workflow is no longer used in v9. + * Improved states used in hotel folio from sale order as per in v9. + +0.01 on 2013-10-16 by Ashish Thakkar + * Made the module installable in v9. diff --git a/hotel/README.rst b/hotel/README.rst new file mode 100644 index 000000000..1490d7347 --- /dev/null +++ b/hotel/README.rst @@ -0,0 +1,53 @@ +hotel + +This Module is for Providing Hotel management Features. + +You can manage: +-Hotel Booking, +-Hotel Facilities and Amenities, +-RESTURANTS, +-Currency Exchange, +-REPORTS + +-Different reports are also provided, mainly for hotel. + +Installation + +To install this module, you need to: + +install 'product_uos', 'sale_stock', 'point_of_sale', 'report' modules + +Configuration + +To configure this module, you need to: + +have a Hotel management functionality. + +Usage + +To use this module, you need to: + +go to apps, then install module to apply this functionality. + +Try me on Runbot +Known issues / Roadmap + +... + +Bug Tracker + +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed feedback here. + +Credits + +Contributors + +Serpent Consulting Services PVT. LTD. + +Maintainer + +Serpent Consulting Services PVT. LTD. + +This module is maintained by the SerpentCS. + +To contribute to this module, please visit https://github.com/JayVora-SerpentCS/hotelmgmt_v8. diff --git a/hotel/__init__.py b/hotel/__init__.py new file mode 100644 index 000000000..4e39d461f --- /dev/null +++ b/hotel/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Tecnotel - Alexandre Díaz +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models +from . import wizard +from . import report +from . import date_utils diff --git a/hotel/__manifest__.py b/hotel/__manifest__.py new file mode 100644 index 000000000..9be7e4ce2 --- /dev/null +++ b/hotel/__manifest__.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Alexandre Díaz +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Hotel Management', + 'version': '0.07', + 'author': 'Odoo Community Association (OCA),\ + Darío Lodeiros,\ + Jose Luis Algara,\ + Alexandre Díaz', + 'images': [], + 'category': 'Generic Modules/Hotel Management', + 'website': '', + 'depends': [ + 'sale_stock', + 'account_payment_return', + 'cash_daily_report', + ], + 'license': "", + 'demo': ['data/hotel_data.xml'], + 'data': [ + 'security/hotel_security.xml', + 'security/ir.model.access.csv', + 'wizard/massive_changes.xml', + 'wizard/split_reservation.xml', + 'wizard/duplicate_reservation.xml', + 'views/res_config.xml', + 'data/menus.xml', + 'views/inherit_account_payment_views.xml', + 'views/inherit_account_invoice_views.xml', + 'wizard/hotel_wizard.xml', + 'wizard/checkinwizard.xml', + 'wizard/massive_price_reservation_days.xml', + 'wizard/folio_make_invoice_advance_views.xml', + 'views/hotel_sequence.xml', + 'views/hotel_report.xml', + 'views/report_hotel_management.xml', + 'views/currency_exchange.xml', + 'views/hotel_floor.xml', + 'views/hotel_folio.xml', + 'views/inherit_res_partner.xml', + # 'views/hotel_service_type.xml', + # 'views/hotel_service_line.xml', + 'views/hotel_room_type.xml', + 'views/hotel_room.xml', + # 'views/hotel_service.xml', + 'views/inherit_product_product.xml', + 'views/hotel_room_amenities_type.xml', + 'views/hotel_room_amenities.xml', + 'views/reservation_restriction_views.xml', + 'views/reservation_restriction_item_views.xml', + 'views/hotel_reservation.xml', + # 'views/virtual_room_views.xml', + 'views/cardex.xml', + 'views/virtual_room_availability.xml', + # 'views/hotel_dashboard.xml', + 'data/cron_jobs.xml', + 'data/records.xml', + 'data/email_template_cancel.xml', + 'data/email_template_reserv.xml', + 'data/email_template_exit.xml', + ], + 'css': ['static/src/css/room_kanban.css'], + 'auto_install': False, + 'installable': True +} diff --git a/hotel/data/cron_jobs.xml b/hotel/data/cron_jobs.xml new file mode 100644 index 000000000..894fac0a9 --- /dev/null +++ b/hotel/data/cron_jobs.xml @@ -0,0 +1,32 @@ + + + + + + + Daily Plan + + + 1 + days + -1 + 0 + + + model.daily_plan() + + + + + Inform Guest About Reservation Before 24 Hours + 1 + days + -1 + + + model.reservation_reminder_24hrs() + + + + + diff --git a/hotel/data/email_template_cancel.xml b/hotel/data/email_template_cancel.xml new file mode 100644 index 000000000..4abc1c9fe --- /dev/null +++ b/hotel/data/email_template_cancel.xml @@ -0,0 +1,538 @@ + + + + + + + Cancel Reservation-Send by Email + ${(object.warehouse_id.partner_id.email or'')} + Cancelación de su reserva en ${object.company_id.property_name} + ${(object.partner_id.id or '')} + + + + + + /*Global Styles*/ + .global {margin: 0; padding: 0; min-width: 100%!important;} + a { color: #5e96ea; text-decoration: none; font-weight: bold;} + img {height: auto;} + .content { border: 1px solid #eeeeee; } + .logo {font-family: sans-serif; font-size: 36px; font-weight: bold; color: #ffffff;} + .link a {font-family: sans-serif; font-size: 12px; color: #ffffff;} + .subheading {font-size: 14px; color: #cccccc; font-family: sans-serif; font-weight: bold; padding: 0 0 0 0; text-transform: uppercase; letter-spacing: 1px;} + .h1 {font-family: sans-serif; font-size: 48px; font-weight: bold; line-height: 56px; color: #ffffff; padding: 0 0 0 0;} + .h2 {font-family: sans-serif; font-size: 18px; font-weight: bold; color: #444444; padding: 0 0 0 0; text-transform: uppercase; letter-spacing: 0.5px;} + .h3 {font-family: sans-serif; font-size: 24px; font-weight: regular; color: #555555; padding: 0 0 0 0;} + .h4 {font-family: sans-serif; font-size: 18px; font-weight: bold; color: #666666; padding: 0 0 0 0;} + .paragraph {font-family: sans-serif; font-size: 14px; line-height: 22px; color: #666666; font-weight: 200; padding: 20px 0 0 0;} + .listitem {font-family: sans-serif; font-size: 15px; color: #666666; font-weight: 200; padding: 0 0 20px 0;} + .smalltext { font-family: sans-serif; font-size: 14px; color: #cccccc; padding: 3px 0 0 0; } + .borderbottom {border-bottom: 1px solid #f2eeed;} + + /*Media Queries*/ + @media only screen and (max-width: 651px){ + .columns{width:100% !important;} + .columncontainer{display:block !important; width:100% !important;} + .paragraph, .listitem {font-size: 18px;} + .link { float: left;} + } + + @media only screen and (min-width: 651px) { + .content {width: 650px !important;} + } + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Alda Hotels + + + + +
+ + + + +
+ + + + + +
+
+
+ + + + + + + + + + + + +
Tu reserva se ha cancelado en ${object.company_id.property_name}
+ + + + +
  + +
+
Hola ${object.partner_id.firstname}
+ Tu reserva en ${object.company_id.property_name} se ha anulado correctamente. No es necesario que hagas nada más. + Si la cancelación conlleva la devolución de alguna cantidad, nos pondremos en contacto contigo. + En caso de que tengas alguna duda, estaremos encantados de atenderte. +
+ + + + +
+ +
Contactar +
+
+
+
+
+ + + + + +
+ + + + +
+ Cancelación +
+
+ + + + +
+ + + + + + + + + + + + +
Datos de tu reserva cancelada
+ ${object.partner_id.name} +
+ % if object.partner_id.contact_address: + ${object.partner_id.contact_address}
+ % endif +
+ % for rline in object.get_grouped_reservations_json('cancelled'): + ${rline['num']} x ${rline['virtual_room']['name']} + % if rline['childrens'] > 0: + (${rline['adults']} Adults + ${rline['childrens']} Childrens) + % else: + (${rline['adults']} Adults) + %endif + +
+ Entrada: ${format_tz(rline['checkin'], format="%d de %B de %Y")}
+ Salida: ${format_tz(rline['checkout'], format="%d de %B de %Y")}
+ Nº de noches: ${rline['nights']}

+ % endfor +
+
+
+
+ + + + + +
+ + + + +
+ Pago +
+
+ + + + +
+ + + + + + + + + + + + +
IMPORTES
+ Noches: ${len(object.room_lines[0].reservation_lines)}
+ Base imponible: ${object.amount_untaxed} €
+ I.V.A (10%): ${object.amount_tax} €
+ Precio total: ${object.amount_total} €
+ Coste de cancelación: [[importe]]
+
+
+
+
+
+
+ + + + + + + +
+ + + + +
+ + + +
+
+
+ + + +
+
+
+ + + + +
+ + + + + + + + + +
NUESTRAS REDES SOCIALES 
+
+
+ + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + +
+ + Facebook + +
Facebook
+ + + + +
  +
+
Toda la actualidad de nuestros alojamientos, así como ofertas y promociones.
+ + + + +
+ + +
Dale a Me gusta
+
+ +
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + +
+ + Instagram + +
Instagram
+ + + + +
  +
+
Cada detalle cuenta, y es por eso que tratamos de reflejarlo en nuestras fotos.
+ + + + +
+ + +
#Entra +
+
+ +
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + +
+ + Twitter + +
Twitter
+ + + + +
  +
+
Propuestas al minuto para hacer de tu viaje una experiencia inmejorable.
+ + + + +
+ + +
Síguenos +
+
+ +
+
+
+
+
+ + + + + + +
¡Esperamos verte pronto!
+
+ + + +
+ Alda Hotels + + + +
+
+ +
+
+ ]]> +
+
+
+
diff --git a/hotel/data/email_template_exit.xml b/hotel/data/email_template_exit.xml new file mode 100644 index 000000000..09cdb0a7e --- /dev/null +++ b/hotel/data/email_template_exit.xml @@ -0,0 +1,580 @@ + + + + + + + Exit Reservation-Send by Email + ${(object.warehouse_id.partner_id.email or'')} + Gracias por alojarse con nosotros en ${object.company_id.property_name} + ${(object.partner_id.id or '')} + + + /*Global Styles*/ + .marco {bgcolor:#f6f6f6; margin: 0; padding: 0; min-width: 100%!important;} + a { color: #5e96ea; text-decoration: none; font-weight: bold;} + img {height: auto;} + .content { border: 1px solid #eeeeee; } + .logo {font-family: sans-serif; font-size: 36px; font-weight: bold; color: #ffffff;} + .link a {font-family: sans-serif; font-size: 12px; color: #ffffff;} + .subheading {font-size: 14px; color: #cccccc; font-family: sans-serif; font-weight: bold; padding: 0 0 0 0; text-transform: uppercase; letter-spacing: 1px;} + .h1 {font-family: sans-serif; font-size: 48px; font-weight: bold; line-height: 56px; color: #ffffff; padding: 0 0 0 0;} + .h2 {font-family: sans-serif; font-size: 18px; font-weight: bold; color: #444444; padding: 0 0 0 0; text-transform: uppercase; letter-spacing: 0.5px;} + .h3 {font-family: sans-serif; font-size: 24px; font-weight: regular; color: #555555; padding: 0 0 0 0;} + .h4 {font-family: sans-serif; font-size: 18px; font-weight: bold; color: #666666; padding: 0 0 0 0;} + .paragraph {font-family: sans-serif; font-size: 14px; line-height: 22px; color: #666666; font-weight: 200; padding: 20px 0 0 0;} + .listitem {font-family: sans-serif; font-size: 15px; color: #666666; font-weight: 200; padding: 0 0 20px 0;} + .smalltext { font-family: sans-serif; font-size: 14px; color: #cccccc; padding: 3px 0 0 0; } + .borderbottom {border-bottom: 1px solid #f2eeed;} + /*Media Queries*/ + @media only screen and (max-width: 651px){ + .columns{width:100% !important;} + .columncontainer{display:block !important; width:100% !important;} + .paragraph, .listitem {font-size: 18px;} + .link { float: left;} + } + @media only screen and (min-width: 651px) { + .content {width: 650px !important;} + } + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Alda Hotels + + + + +
+ + + + +
+ + + + + +
+
+
+ + + + + + + + + + + + +
¡Muchas gracias por tu visita! +
+

__

+
Hola ${object.partner_id.firstname},
+ Esperamos que hayas disfrutado de la ciudad, y que muy especialmente te hayas sentido a gusto en nuestro alojamiento. Todo el equipo de ${object.company_id.property_name} te agradece tu estancia en nuestro centro y te desea un feliz regreso.
+ Recibe un cordial saludo y esperamos volver a verte.
+
+
+ + + + +
+ + + + +
+ + + + + + + + + +
Disfruta de tu descuento de cliente +
+

__

+
+ + + + + + +
Solo por ser cliente de Alda Hotels disfruta, automáticamente, de hasta un 10% de descuento en cualquiera de nuestros establecimientos, totalmente transferible y sin fecha de caducidad.
+
+
+ Descuento 10% + + + +
+
+
+ + + + +
+ + + + +
+ + + + + + + + + +
¿Tienes algo que comentarnos? +
+

__

+
+ + + + + + + +
Cada día intentamos dar un mejor servicio, es por ello que si quieres aportar alguna propuesta o crítica constructiva, te invitamos a utilizar el siguiente formulario. Estamos encantados de recibir tus propuestas. Todas serán leídas y tenidas en cuenta, y atenderemos aquellas que nos permitan nuestros medios y posibilidades.
+
+ + +
Entrar al formulario ▶ +
+
+ +
+ + + + + +
+
+
+
+ + + + + +
+ + + + +
+ Localización +
+
+ + + + +
+ + + + + + + + + + +
nuestros alojamientos
Descubre dónde estamos +
Estamos presentes a lo largo del territorio peninsular. Si quieres saber dónde puedes alojarte con nosotros, pincha en el mapa.
+
+
+ Mapa + + + + + + + +
+
+ + + +
+ + + +
+
+
+ + + + + + + + + +
+ + + + +
+ + + +
+
+
+ + + +
+
+ + + +
+
+ + + + +
+ + + +
+
+
+
+ + + + +
+ + + + + + + + + +
NUESTRAS REDES SOCIALES +   +
+
+
+ + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + +
Facebook +
Facebook
+ + + + +
  +
+
Toda la actualidad de nuestros alojamientos, así como ofertas y promociones.
+ + + + +
+ + + +
Dale a Me gusta
+
+ +
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + +
Instagram +
Instagram
+ + + + +
  +
+
Cada detalle cuenta, y es por eso que tratamos de reflejarlo en nuestras fotos. +
+ + + + +
+ + +
#Entra +
+
+ +
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + +
Twitter +
Twitter +
+ + + + +
  +
+
Propuestas al minuto para hacer de tu viaje una experiencia inmejorable. +
+ + + + +
+ + +
Síguenos +
+
+ +
+
+
+
+
+ + + + + + +
¡Muchas gracias por alojarte con nosotros! +
+
+ + + +
+ Alda Hotels + + + +
+
+ +
+
]]>
+
+
+
diff --git a/hotel/data/email_template_reserv.xml b/hotel/data/email_template_reserv.xml new file mode 100644 index 000000000..6e6829dd6 --- /dev/null +++ b/hotel/data/email_template_reserv.xml @@ -0,0 +1,972 @@ + + + + + + + Confirm Reservation-Send by Email + ${(object.warehouse_id.partner_id.email or '')} + Confirmación de los detalles de su reserva en ${object.company_id.property_name} + ${(object.partner_id.id or '')} + + + + + /*Global Styles*/ + .marco {bgcolor:#f6f6f6; margin: 0; padding: 0; min-width: 100%!important;} + a { color: #5e96ea; text-decoration: none; font-weight: bold;} + img {height: auto;} + .content { border: 1px solid #eeeeee; } + .logo {font-family: sans-serif; font-size: 36px; font-weight: bold; color: #ffffff;} + .link a {font-family: sans-serif; font-size: 12px; color: #ffffff;} + .subheading {font-size: 14px; color: #cccccc; font-family: sans-serif; font-weight: bold; padding: 0 0 0 0; text-transform: uppercase; letter-spacing: 1px;} + .h1 {font-family: sans-serif; font-size: 48px; font-weight: bold; line-height: 56px; color: #ffffff; padding: 0 0 0 0;} + .h2 {font-family: sans-serif; font-size: 18px; font-weight: bold; color: #444444; padding: 0 0 0 0; text-transform: uppercase; letter-spacing: 0.5px;} + .h3 {font-family: sans-serif; font-size: 24px; font-weight: regular; color: #555555; padding: 0 0 0 0;} + .h4 {font-family: sans-serif; font-size: 18px; font-weight: bold; color: #666666; padding: 0 0 0 0;} + .paragraph {font-family: sans-serif; font-size: 14px; line-height: 22px; color: #666666; font-weight: 200; padding: 20px 0 0 0;} + .listitem {font-family: sans-serif; font-size: 15px; color: #666666; font-weight: 200; padding: 0 0 20px 0;} + .smalltext { font-family: sans-serif; font-size: 14px; color: #cccccc; padding: 3px 0 0 0; } + .borderbottom {border-bottom: 1px solid #f2eeed;} + /*Media Queries*/ + @media only screen and (max-width: 651px){ + .columns{width:100% !important;} + .columncontainer{display:block !important; width:100% !important;} + .paragraph, .listitem {font-size: 18px;} + .link { float: left;} + } + @media only screen and (min-width: 651px) { + .content {width: 650px !important;} + } + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Alda Hotels + + + + +
+ + + + +
+ + + + + +
+
+
+ + + + + + + + + + + + + +
Confirmación de reserva en ${object.company_id.property_name}
+

__

+
Hola ${object.partner_id.firstname}
+ Tu reserva en ${object.company_id.property_name} queda confirmada. Te esperamos el día ${object.room_lines[0].checkin[8:10]} del ${object.room_lines[0].checkin[5:7]} de ${object.room_lines[0].checkin[0:4]}. Si podemos ayudarte en cualquier tipo de gestión, no dudes en hacérnoslo saber.
+
+ + + + +
+ +
Contactar +
+
+
+
+
+ + + + + +
+ + + + +
+ + + + + + + + + + + + + +
¿Llegarás más tarde de las 17:00 horas?
+

__

+
En ese caso te rogamos que te pongas en contacto con nosotros para facilitarte las instrucciones necesarias.
+
+ + + + +
+ + +
Contactar +
+
+ +
+
+
+
+ + + + +
+ + + + +
+ + + + + + + +
Servicios
+ + + + + + + + + + + + + + + + + +
+ Info + Información turística
+ Wifi + Wi-Fi gratuito
+ Restauracion + Restauración
+ Parking + Parking concertado
+
+
+
+
+
+ + + + + +
+ + + + +
+ Alda Hotels +
+
+ + + + +
+ + + + + + + + + + + + +
Datos de tu reserva
+ ${object.partner_id.name} +
+ % if object.partner_id.contact_address: + ${object.partner_id.contact_address}
+ % endif + % if object.partner_id.phone: + Tel.: ${object.partner_id.phone}
+ % endif + % if object.partner_id.mobile: + Mov.: ${object.partner_id.mobile}
+ % endif +
+ + % for rline in object.get_grouped_reservations_json('confirm'): + ${rline['num']} x ${rline['virtual_room']['name']} + % if rline['childrens'] > 0: + (${rline['adults']} Adultos + ${rline['childrens']} Niños) + % else: + (${rline['adults']} Adultos) + % endif + +
+ Entrada: ${format_tz(rline['checkin'], format="%d de %B de %Y")}
+ Salida: ${format_tz(rline['checkout'], format="%d de %B de %Y")}
+ Nº de noches: ${rline['nights']}

+ % endfor + +
+ Recuerda que puedas cancelar gratuitamente esta reserva hasta las 12:00 h del día anterior a tu llegada. +
+
+
+
+ + + + +
+ + + + + + + + + +
Mapa
+ + + + + +
+ Ver mapa +
+

+
+ +

+ +

+ + + + +
+ + + + +
+ + +
+
+
+
+
+ + + + + +
+ + + + +
+ Importes +
+
+ + + + +
+ + + + + + + + + + + + +
IMPORTES
+ Noches: ${len(object.room_lines[0].reservation_lines)}
+ Base imponible: ${object.amount_untaxed} €
+ I.V.A (10%): ${object.amount_tax} €
+ Precio total: ${object.amount_total} €
+
+
+
+
+
+ + + + + +
+ + + + +
+ Habitacion +
+
+ + + + +
+ + + + + % set vroom_ids = object.room_lines.filtered('to_send').mapped('virtual_room_id.id') + % set vrooms = user.env['hotel.virtual.room'].browse(vroom_ids) + % for vroom in vrooms: + + % if vroom.name: + + % else: + + % endif + + + + + + + + % endfor +
Información de la habitación
+ ${vroom.name} + + Habitación ${loop.index} +
+ Esta habitación cuenta con TV, Wi-Fi gratuita, calefacción y baño privado. +
+ + + + + + + + + +
+
+
+
+
+
+
+ + + + + +
+ + + + +
+ Peticiones +
+
+ + + + +
+ + + + + + + + + + + + +
Peticiones especiales
+ Estamos a tu servicio +
+ [[petición]] +
+
+
+
+
+ + + + +
+ + + + +
+ + + + + + + + + + + +
Información adicional
+ + +

__

+ +
+
+
+
+
+ + + + + +
+ + + + +
+ Coche +
+
+ + + + +
+ + + + + + + + + + + + +
Cómo acceder
+ En coche +
+

+
+ Pulse en este enlace, para conocer como llegar desde su ubicación actual +

+ Si vienes en coche, queremos informarte de que nos encontramos en una calle peatonal. Para aparcar, te recomendamos nuestro parking concertado, a tan sólo 3 minutos caminando. Es el Parking La Salle, en la calle Ramón del Valle Inclán. Tiene un coste de 10€/día por ser cliente de Alda Hotels. +
+
+
+
+ + + + + +
+ + + + +
+ Bus +
+
+ + + + +
+ + + + + + + + + + + + +
Cómo acceder
+ En autobús o tren +
Si vienes en autobús nos encontramos a 15 minutos caminando. Si prefieres coger un bus urbano, te recomendamos las líneas P1 y P2 y parar en la Praciña das Penas. Desde la parada solo tendrás que caminar 2 minutos.

+ Si llegas a la ciudad en tren, puedes coger las líneas de bus C5, C6, 6 o 9, y parar en Praciña das Penas, muy cerca de nuestra ubicación.
+
+
+
+
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + + + + + + +
${object.company_id.city}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ac lobortis sem. Donec in tincidunt diam, id ultrices risus. Fusce ultrices posuere lectus vitae commodo.
+ + + + +
+ + + +
+
+
+
+
+ + + + +
+ +
+
+ + + + +
+ +
+
+ + + + +
+ + + + +
+ + + + + + + + + +
${object.company_id.property_name}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ac lobortis sem. Donec in tincidunt diam, id ultrices risus. Fusce ultrices posuere lectus vitae commodo. Nulla facilisi. Donec condimentum gravida ex et dapibus.
+
+
+
+
+ + + + +
+ + + + + + + + + +
NUESTRAS REDES SOCIALES
+
+
+ + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + +
+ + Facebook + +
Facebook
+ + + + +
+ +
+
Toda la actualidad de nuestros alojamientos, así como ofertas y promociones.
+ + + + +
+ + +
Dale a Me gusta
+
+ +
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + +
+ + Instagram + +
Instagram
+ + + + +
+ +
+
Cada detalle cuenta, y es por eso que tratamos de reflejarlo en nuestras fotos.
+ + + + +
+ + +
#Entra +
+
+ +
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + +
+ + Twitter + +
Twitter
+ + + + +
+ +
+
Propuestas al minuto para hacer de tu viaje una experiencia inmejorable.
+ + + + +
+ + +
Síguenos +
+
+ +
+
+
+
+
+ + + + + + +
¡Muchas gracias por alojarte con nosotros!
+
+ + + +
+ Alda Hotels + + + +
+
+ +
+
+ ]]> +
+
+
+
diff --git a/hotel/data/hotel-color.png b/hotel/data/hotel-color.png new file mode 100644 index 000000000..0e3644a50 Binary files /dev/null and b/hotel/data/hotel-color.png differ diff --git a/hotel/data/hotel-grey.png b/hotel/data/hotel-grey.png new file mode 100644 index 000000000..110e14614 Binary files /dev/null and b/hotel/data/hotel-grey.png differ diff --git a/hotel/data/hotel_data.xml b/hotel/data/hotel_data.xml new file mode 100644 index 000000000..52c60b31c --- /dev/null +++ b/hotel/data/hotel_data.xml @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + All Aminities + 1 + + + + Beds + 1 + + + + Tables + 1 + + + + Single Bed + 1 + + + + Double Bed + 1 + + + + + + All Rooms + ALL + 1 + + + + Single + SNG + 1 + + + + Double + DBL + 1 + + + + Triple + TRP + 1 + + + + + + All Services + 1 + + + + 1 + Fixed + + + + 1 + Variable + + + + + + Single-101 + 1 + + 100.00 + 2 + + + Single-102 + 1 + + 100.00 + 2 + + + Single-103 + 1 + + 100.00 + 2 + + + Double-201 + 1 + + 200.00 + 5 + + + Double-202 + 1 + + 200.00 + 5 + + + Double-203 + 1 + + 200.00 + 5 + + + Triple-101 + 1 + + 300.00 + 6 + + + Triple-102 + 1 + + 300.00 + 6 + + + + + + Internet + 1 + + 200.00 + + + Taxi + 1 + + 500.00 + + + Laundry + 1 + + 150.00 + + + + + + Toiletries + 1 + + + + Iron + 1 + + + + Irons Boards + 1 + + + + + diff --git a/hotel/data/menus.xml b/hotel/data/menus.xml new file mode 100644 index 000000000..4c008ddc2 --- /dev/null +++ b/hotel/data/menus.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + diff --git a/hotel/data/records.xml b/hotel/data/records.xml new file mode 100644 index 000000000..c6a7bf955 --- /dev/null +++ b/hotel/data/records.xml @@ -0,0 +1,26 @@ + + + + + Default Restrictions + + + + + + + + + + + + + diff --git a/hotel/date_utils.py b/hotel/date_utils.py new file mode 100644 index 000000000..f2624eda8 --- /dev/null +++ b/hotel/date_utils.py @@ -0,0 +1,206 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2018 Solucións Aloxa S.L. +# Alexandre Díaz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from datetime import datetime, timedelta +from dateutil import tz +from openerp.tools import ( + DEFAULT_SERVER_DATETIME_FORMAT, + DEFAULT_SERVER_DATE_FORMAT) +from openerp import fields, _ +from openerp.exceptions import ValidationError + + +# Generate a 'datetime' object from 'str_date' string with 'dtformat' format. +def _generate_datetime(str_date, dtformat, stz=False): + ndate = False + try: + ndate = datetime.strptime(str_date, dtformat) + ndate = ndate.replace(tzinfo=tz.gettz(stz and str(stz) or 'UTC')) + except ValueError: + return False + + return ndate + + +# Try generate a 'datetime' object from 'str_date' string +# using all odoo formats +def get_datetime(str_date, dtformat=False, hours=True, end_day=False, + stz=False): + if dtformat: + date_dt = _generate_datetime(str_date, dtformat, stz=stz) + else: + date_dt = _generate_datetime( + str_date, + DEFAULT_SERVER_DATETIME_FORMAT, + stz=stz) + if not date_dt: + date_dt = _generate_datetime( + str_date, + DEFAULT_SERVER_DATE_FORMAT, + stz=stz) + + if date_dt: + if end_day: + date_dt = dt_no_hours(date_dt, end_day=True) + elif not hours: + date_dt = dt_no_hours(date_dt) + + return date_dt + + +# Compare two dates +def date_compare(str_date_a, str_date_b, hours=True): + date_dt_a = get_datetime(str_date_a) + date_dt_b = get_datetime(str_date_b) + + if not hours: + date_dt_a = dt_no_hours(date_dt_a) + date_dt_b = dt_no_hours(date_dt_b) + + return date_dt_a == date_dt_b + + +# Set hours to zero +def dt_no_hours(new_start_date_dt, end_day=False): + if not end_day: + return new_start_date_dt.replace(hour=0, minute=0, second=0, + microsecond=0) + else: + return new_start_date_dt.replace(hour=23, minute=59, second=59, + microsecond=999999) + + +# Get now 'datetime' object +def now(hours=False): + now_utc_dt = fields.datetime.now().replace(tzinfo=tz.tzutc()) + + if not hours: + now_utc_dt = now_utc_dt.replace(hour=0, minute=0, second=0, + microsecond=0) + + return now_utc_dt + + +# Get the difference in days between 'str_date_start' and 'str_date_end' +def date_diff(date_start, date_end, hours=True, stz=False): + if not isinstance(date_start, datetime): + date_start_dt = get_datetime(date_start, stz=stz) + else: + date_start_dt = date_start + if not isinstance(date_end, datetime): + date_end_dt = get_datetime(date_end, stz=stz) + else: + date_end_dt = date_end + + if not date_start_dt or not date_end_dt: + raise ValidationError(_("Invalid date. Can't compare it!")) + + if not hours: + date_start_dt = dt_no_hours(date_start_dt) + date_end_dt = dt_no_hours(date_end_dt) + + return abs((date_end_dt - date_start_dt).days) + + +# Get a new 'datetime' object from 'date_dt' usign the 'tz' timezone +def dt_as_timezone(date_dt, stz): + return date_dt.astimezone(tz.gettz(stz and str(stz) or 'UTC')) + + +# Generate a list of days start in 'cdate' +def generate_dates_list(cdate, + num_days, + outformat=DEFAULT_SERVER_DATE_FORMAT, stz=False): + ndate = get_datetime(cdate, stz=stz) if not isinstance(cdate, datetime) \ + else cdate + return [(ndate + timedelta(days=i)).strftime(outformat) + for i in range(0, num_days)] + + +# Check if 'str_date' is between 'str_start_date' and 'str_end_date' +# 0 Inside +# -1 'str_date' is before 'str_start_date' +# 1 'str_date' is after 'str_end_date' +def date_in(str_date, str_start_date, str_end_date, hours=True, stz=False): + if not isinstance(str_date, datetime): + date_dt = get_datetime(str_date, stz=stz) + else: + date_dt = str_date + if not isinstance(str_start_date, datetime): + date_start_dt = get_datetime(str_date_start, stz=stz) + else: + date_start_dt = str_start_date + if not isinstance(str_end_date, datetime): + date_end_dt = get_datetime(str_end_date, stz=stz) + else: + date_end_dt = str_end_date + + if not date_start_dt or not date_end_dt or not date_dt: + raise ValidationError(_("Invalid date. Can't compare it!")) + + if not hours: + date_start_dt = dt_no_hours(date_start_dt) + date_end_dt = dt_no_hours(date_end_dt) + + res = -2 + if date_dt >= date_start_dt and date_dt <= date_end_dt: + res = 0 + elif date_dt > date_end_dt: + res = 1 + elif date_dt < date_start_dt: + res = -1 + + return res + + +# Check if 'str_start_date_a' and 'str_start_date_b' +# is between 'str_start_date_b' and 'str_end_date_b' +# 0 Inside +# -1 'str_date' is before 'str_start_date' +# 1 'str_date' is after 'str_end_date' +def range_dates_in(str_start_date_a, + str_end_date_a, + str_start_date_b, + str_end_date_b, + hours=True, stz=False): + date_start_dt_a = get_datetime(str_start_date_a, stz=stz) + date_end_dt_a = get_datetime(str_end_date_a, stz=stz) + date_start_dt_b = get_datetime(str_start_date_b, stz=stz) + date_end_dt_b = get_datetime(str_end_date_b, stz=stz) + + if not date_start_dt_a or not date_end_dt_a \ + or not date_start_dt_b or not date_end_dt_b: + raise ValidationError(_("Invalid date. Can't compare it!")) + + if not hours: + date_start_dt_b = dt_no_hours(date_start_dt_b) + date_end_dt_b = dt_no_hours(date_end_dt_b) + + res = -2 + if date_start_dt_a >= date_start_dt_b and date_end_dt_a <= date_end_dt_b: + res = 0 + elif date_start_dt_a < date_start_dt_b \ + and date_end_dt_a >= date_start_dt_b: + res = -1 + elif date_start_dt_a <= date_end_dt_b and date_end_dt_a > date_end_dt_b: + res = 1 + + return res diff --git a/hotel/i18n/es.mo b/hotel/i18n/es.mo new file mode 100644 index 000000000..fd94c1b4b Binary files /dev/null and b/hotel/i18n/es.mo differ diff --git a/hotel/i18n/es.po b/hotel/i18n/es.po new file mode 100644 index 000000000..a10548771 --- /dev/null +++ b/hotel/i18n/es.po @@ -0,0 +1,7673 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hotel +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-05-22 06:42+0000\n" +"PO-Revision-Date: 2018-06-03 23:32+0200\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"Language: es\n" +"X-Generator: Poedit 2.0.7\n" + +#. module: hotel +#: model:mail.template,body_html:hotel.mail_template_hotel_cancel +msgid "" +"\n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" \"Alda\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" www.aldahotels.com\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
Tu reserva se ha cancelado en ${object.company_id.property_name}
\n" +" \n" +" \n" +" \n" +" \n" +"
 \n" +"\n" +"
\n" +"
Hola ${object.partner_id.firstname}
\n" +" Tu reserva en ${object.company_id.property_name} se ha anulado correctamente. No es necesario que hagas nada más.\n" +" Si la cancelación conlleva la devolución de alguna cantidad, nos pondremos en contacto contigo.\n" +" En caso de que tengas alguna duda, estaremos encantados de atenderte.\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +"
Contactar\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"Cancelación\"\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
Datos de tu reserva cancelada
\n" +" ${object.partner_id.name}\n" +"
\n" +" % if object.partner_id.contact_address:\n" +" ${object.partner_id.contact_address}
\n" +" % endif\n" +"
\n" +" % for row in object.room_lines:\n" +" % if row.virtual_room_id.name:\n" +" ${row.virtual_room_id.name}\n" +" % else:\n" +" Habitación ${loop.index}\n" +" % endif\n" +"
\n" +" Día de entrada: ${row.checkin[8:10]}/${row.checkin[5:7]}/${row.checkin[0:4]}
\n" +" Día de salida: ${row.checkout[8:10]}/${row.checkout[5:7]}/${row.checkout[0:4]}
\n" +" Nº de noches: ${len(row.reservation_lines)}
\n" +" Número de huéspedes:\n" +" % if row.adults > 0:\n" +" ${row.adults} Adultos\n" +" % endif\n" +" % if row.children > 0:\n" +" / ${row.children} Menores\n" +" % endif\n" +"
\n" +"
\n" +" % endfor\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"Pago\"\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
IMPORTES
\n" +" Noches: ${len(object.room_lines[0].reservation_lines)}
\n" +" Base imponible: ${object.amount_untaxed} €
\n" +" I.V.A (10%): ${object.amount_tax} €
\n" +" Precio total: ${object.amount_total} €
\n" +" Coste de cancelación: [[importe]]
\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
NUESTRAS REDES SOCIALES 
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"Facebook\"\n" +" \n" +"
Facebook
\n" +" \n" +" \n" +" \n" +" \n" +"
 \n" +"
\n" +"
Toda la actualidad de nuestros alojamientos, así como ofertas y promociones.
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +"
Dale a Me gusta
\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"Instagram\"\n" +" \n" +"
Instagram
\n" +" \n" +" \n" +" \n" +" \n" +"
 \n" +"
\n" +"
Cada detalle cuenta, y es por eso que tratamos de reflejarlo en nuestras fotos.
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +"
#Entra\n" +"
\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"Twitter\"\n" +" \n" +"
Twitter
\n" +" \n" +" \n" +" \n" +" \n" +"
 \n" +"
\n" +"
Propuestas al minuto para hacer de tu viaje una experiencia inmejorable.
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +"
Síguenos\n" +"
\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
¡Esperamos verte pronto!
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" \"Alda\n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
En cumplimiento de la Ley 34/2002 de Servicios de la Sociedad de la Información y del Comercio Electrónico, así como de la Ley Orgánica 15/1999 del 13 de Diciembre de Protección de Datos de Carácter Personal y demás legislación concordante, se le informa que sus datos personales figuran en un fichero automatizado cuya responsabilidad es de ALDA COMPOSTELA S.L. Praza da Algalia de Arriba, 3 C.P. 15704 Santiago de Compostela. Los datos personales que existen en nuestro poder están protegidos por nuestra Política de Privacidad y solo serán utilizados para los fines propios de nuestra actividad. Para ejercer sus derechos de acceso, rectificación, cancelación u oposición debe enviar un correo electrónico a info@aldahotels.com indicándonos la opción a realizar. Este correo podría ser confidencial. Si recibe este e-mail por error, por favor elimínelo, así como cualquier documento adjunto, y notifíquelo a su emisor. Si usted no es el destinatario del mensaje, sepa que no está permitida ninguna difusión, copia o utilización no autorizada.
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" Antes de imprimir este mensaje, compruebe que es verdaderamente necesario. El medioambiente es cosa de todos. \n" +"
\n" +"
\n" +" \n" +"
\n" +"
\n" +" \n" +" " +msgstr "" + +#. module: hotel +#: model:mail.template,body_html:hotel.mail_template_hotel_reservation +msgid "" +"\n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" \"Alda\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" www.aldahotels.com\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
Confirmación de reserva en ${object.company_id.property_name}
\n" +"

__

\n" +"
Hola ${object.partner_id.firstname}
\n" +" Tu reserva en ${object.company_id.property_name} queda confirmada. Te esperamos el día ${object.room_lines[0].checkin[8:10]} del ${object.room_lines[0].checkin[5:7]} de ${object.room_lines[0].checkin[0:4]}. Si podemos ayudarte en cualquier tipo de gestión, no dudes en hacérnoslo saber.
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +"
Contactar\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
¿Llegarás más tarde de las 17:00 horas?
\n" +"

__

\n" +"
En ese caso te rogamos que te pongas en contacto con nosotros para facilitarte las instrucciones necesarias.
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +"
Contactar\n" +"
\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
Servicios
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"Info\"\n" +" Información turística
\n" +" \"Wifi\"\n" +" Wi-Fi gratuito
\n" +" \"Restauracion\"\n" +" Restauración
\n" +" \"Parking\"\n" +" Parking concertado
\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"Alda\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
Datos de tu reserva
\n" +" ${object.partner_id.name}\n" +"
\n" +" % if object.partner_id.contact_address:\n" +" ${object.partner_id.contact_address}
\n" +" % endif\n" +" % if object.partner_id.phone:\n" +" Tel.: ${object.partner_id.phone}
\n" +" % endif\n" +" % if object.partner_id.mobile:\n" +" Mov.: ${object.partner_id.mobile}
\n" +" % endif\n" +"
\n" +" Entrada: ${object.room_lines[0].checkin[8:10]} del ${object.room_lines[0].checkin[5:7]} de ${object.room_lines[0].checkin[0:4]}
\n" +" Salida: ${object.room_lines[0].checkout[8:10]} del ${object.room_lines[0].checkout[5:7]} de ${object.room_lines[0].checkout[0:4]}
\n" +" Nº de noches: ${len(object.room_lines[0].reservation_lines)}
\n" +"
\n" +" Recuerda que puedas cancelar gratuitamente esta reserva hasta las 12:00 h del día anterior a tu llegada.
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
Mapa
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"Ver\n" +"
\n" +"

\n" +"
\n" +" \n" +"

\n" +" \n" +"

\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"Importes\"\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
IMPORTES
\n" +" Noches: ${len(object.room_lines[0].reservation_lines)}
\n" +" Base imponible: ${object.amount_untaxed} €
\n" +" I.V.A (10%): ${object.amount_tax} €
\n" +" Precio total: ${object.amount_total} €
\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"Habitacion\"\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"\n" +"\n" +" % for row in object.room_lines:\n" +" \n" +" % if row.virtual_room_id.name:\n" +" \n" +" % else:\n" +" \n" +" % endif\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" % endfor\n" +"
Información de la habitación
\n" +" ${row.virtual_room_id.name}\n" +" \n" +" Habitación ${loop.index}\n" +"
Esta habitación cuenta con TV, Wi-Fi gratuita, calefacción y baño privado.
\n" +" Día de entrada: ${row.checkin[8:10]}/${row.checkin[5:7]}/${row.checkin[0:4]}
\n" +" Día de salida: ${row.checkout[8:10]}/${row.checkout[5:7]}/${row.checkout[0:4]}
\n" +" Nº de noches: ${len(row.reservation_lines)}
\n" +" Número de huéspedes:\n" +" % if row.adults > 0:\n" +" ${row.adults} Adultos\n" +" % endif\n" +" % if row.children > 0:\n" +" / ${row.children} Menores\n" +" % endif\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"Peticiones\"\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
Peticiones especiales
\n" +" Estamos a tu servicio\n" +"
\n" +" [[petición]]\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
Información adicional
\n" +" \n" +" \n" +"

__

\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"Coche\"\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
Cómo acceder
\n" +" En coche\n" +"
\n" +"

\n" +"
\n" +" Pulse en este enlace, para conocer como llegar desde su ubicación actual\n" +"

\n" +" Si vienes en coche, queremos informarte de que nos encontramos en una calle peatonal. Para aparcar, te recomendamos nuestro parking concertado, a tan sólo 3 minutos caminando. Es el Parking La Salle, en la calle Ramón del Valle Inclán. Tiene un coste de 10€/día por ser cliente de Alda Hotels.
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"Bus\"\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
Cómo acceder
\n" +" En autobús o tren\n" +"
Si vienes en autobús nos encontramos a 15 minutos caminando. Si prefieres coger un bus urbano, te recomendamos las líneas P1 y P2 y parar en la Praciña das Penas. Desde la parada solo tendrás que caminar 2 minutos.
\n" +"
\n" +" Si llegas a la ciudad en tren, puedes coger las líneas de bus C5, C6, 6 o 9, y parar en Praciña das Penas, muy cerca de nuestra ubicación.
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
${object.company_id.city}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ac lobortis sem. Donec in tincidunt diam, id ultrices risus. Fusce ultrices posuere lectus vitae commodo.
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +"
\n" +" Más información\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"\"\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"\"/\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
${object.company_id.property_name}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ac lobortis sem. Donec in tincidunt diam, id ultrices risus. Fusce ultrices posuere lectus vitae commodo. Nulla facilisi. Donec condimentum gravida ex et dapibus.
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
NUESTRAS REDES SOCIALES 
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"Facebook\"\n" +" \n" +"
Facebook
\n" +" \n" +" \n" +" \n" +" \n" +"
 \n" +"\n" +"
\n" +"
Toda la actualidad de nuestros alojamientos, así como ofertas y promociones.
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +"
Dale a Me gusta
\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"Instagram\"\n" +" \n" +"
Instagram
\n" +" \n" +" \n" +" \n" +" \n" +"
 \n" +"\n" +"
\n" +"
Cada detalle cuenta, y es por eso que tratamos de reflejarlo en nuestras fotos.
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +"
#Entra\n" +"
\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"Twitter\"\n" +" \n" +"
Twitter
\n" +" \n" +" \n" +" \n" +" \n" +"
 \n" +"\n" +"
\n" +"
Propuestas al minuto para hacer de tu viaje una experiencia inmejorable.
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +"
Síguenos\n" +"
\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
¡Muchas gracias por alojarte con nosotros!
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" \"Alda\n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
En cumplimiento de la Ley 34/2002 de Servicios de la Sociedad de la Información y del Comercio Electrónico, así como de la Ley Orgánica 15/1999 del 13 de Diciembre de Protección de Datos de Carácter Personal y demás legislación concordante, se le informa que sus datos personales figuran en un fichero automatizado cuya responsabilidad es de ALDA COMPOSTELA S.L. Praza da Algalia de Arriba, 3 C.P. 15704 Santiago de Compostela. Los datos personales que existen en nuestro poder están protegidos por nuestra Política de Privacidad y solo serán utilizados para los fines propios de nuestra actividad. Para ejercer sus derechos de acceso, rectificación, cancelación u oposición debe enviar un correo electrónico a info@aldahotels.com indicándonos la opción a realizar. Este correo podría ser confidencial. Si recibe este e-mail por error, por favor elimínelo, así como cualquier documento adjunto, y notifíquelo a su emisor. Si usted no es el destinatario del mensaje, sepa que no está permitida ninguna difusión, copia o utilización no autorizada.
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \"ECO\"\n" +" Antes de imprimir este mensaje, compruebe que es verdaderamente necesario. El medioambiente es cosa de todos. \n" +"
\n" +"
\n" +" \n" +"
\n" +"
\n" +" \n" +" " +msgstr "" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_product_variant_count +#: model:ir.model.fields,field_description:hotel.field_hotel_room_product_variant_count +#: model:ir.model.fields,field_description:hotel.field_hotel_services_product_variant_count +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_product_variant_count +msgid "# Product Variants" +msgstr "# Variantes de producto" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_product_count +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_product_count +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_product_count +msgid "# Products" +msgstr "# Productos" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_purchase_count +#: model:ir.model.fields,field_description:hotel.field_hotel_room_purchase_count +#: model:ir.model.fields,field_description:hotel.field_hotel_services_purchase_count +msgid "# Purchases" +msgstr "# Purchases" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_sales_count +#: model:ir.model.fields,field_description:hotel.field_hotel_room_sales_count +#: model:ir.model.fields,field_description:hotel.field_hotel_services_sales_count +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_sales_count +msgid "# Sales" +msgstr "# Ventas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_invoice_count +msgid "# of Invoices" +msgstr "# de Facturas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_count +msgid "# of Orders" +msgstr "# de Pedidos" + +#. module: hotel +#: code:addons/hotel/models/hotel_reservation.py:817 +#, python-format +msgid "%s people do not fit in this room! ;)" +msgstr "%s personas no caben en esta habitación!" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.report_currency_exchange +msgid "* Valid for three months from the date of purchase of foreign currency *" +msgstr "* Válido para tres meses desde la fecha del cambio de moneda" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_service_line_form +msgid "---Description---" +msgstr "---Descripción---" + +#. module: hotel +#: selection:currency.exchange,tax:0 +msgid "10%" +msgstr "10%" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "" +"Cancelled Reservation!\n" +" Reserva Cancelada!\n" +" Increase the price in 12.3\n" +" b) -1.45% \t> Substract 1.45%\n" +" c) 45 \t\t> Sets the price to 45" +msgstr "" +"Can use '+','-' or '%'...\n" +"Examples:\n" +" a) +12.3 \t> Increase the price in 12.3\n" +" b) -1.45% \t> Substract 1.45%\n" +" c) 45 \t\t> Sets the price to 45" + +#. module: hotel +#: code:addons/hotel/wizard/duplicate_reservation.py:45 +#, python-format +msgid "Can't duplicate splitted reservations" +msgstr "No se pueden duplicar las reservas divididas" + +#. module: hotel +#: selection:currency.exchange,state:0 +#: model:ir.ui.view,arch_db:hotel.checkin_wizard_form_2 +#: model:ir.ui.view,arch_db:hotel.view_account_payment_folio_form +#: model:ir.ui.view,arch_db:hotel.view_currency_exchange_form +#: model:ir.ui.view,arch_db:hotel.view_folio_advance_payment_inv +#: model:ir.ui.view,arch_db:hotel.view_hotel_config_settings +#: model:ir.ui.view,arch_db:hotel.view_hotel_duplicate_reservation_wizard +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio_wizard +#: model:ir.ui.view,arch_db:hotel.view_hotel_massive_changes_wizard +#: model:ir.ui.view,arch_db:hotel.view_hotel_massive_price_change_wizard +#: model:ir.ui.view,arch_db:hotel.view_hotel_split_reservation_wizard +msgid "Cancel" +msgstr "Cancelar" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Cancel Folio" +msgstr "Cancelar Ficha" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Cancel Reservation" +msgstr "Cancelar Reserva" + +#. module: hotel +#: model:mail.template,subject:hotel.mail_template_hotel_cancel +msgid "Cancelación de su reserva en ${object.company_id.property_name}" +msgstr "Cancelación de su reserva en ${object.company_id.property_name}" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_res_company_default_cancel_policy_days +msgid "Cancelation Days" +msgstr "Días de Cancelación" + +#. module: hotel +#: selection:hotel.reservation,state:0 +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Cancelled" +msgstr "Cancelado" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_capacity +msgid "Capacity" +msgstr "Capacidad" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_kanban +msgid "Capacity:" +msgstr "Capacidad:" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.menu_cardex +msgid "Cardex" +msgstr "Checkin" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_cardex_pending +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_cardex_pending_num +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_cardex_pending +msgid "Cardex Pending" +msgstr "Checkin Pendientes" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_cardex_pending_num +msgid "Cardex Pending Num" +msgstr "Nº de Checkin Pendientes" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_cardex_count +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_cardex_count +msgid "Cardex counter" +msgstr "Contador de Checkin" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_cardex_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_cardex_ids +msgid "Cardex ids" +msgstr "Checkin ids" + +#. module: hotel +#: code:addons/hotel/models/hotel_folio.py:333 +#: code:addons/hotel/models/hotel_reservation.py:359 +#, python-format +msgid "Cardexs" +msgstr "Checkin" + +#. module: hotel +#: selection:currency.exchange,type:0 +msgid "Cash" +msgstr "Efectivo" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.cash_daily_report_wizard +msgid "Cash Daily Report Wizard" +msgstr "Informe de caja diaria" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_aenities_search +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_search +msgid "Catagory" +msgstr "Categoría" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.action_room_cate +msgid "Category Items" +msgstr "Elementos de categoría" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_route_from_categ_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_route_from_categ_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_route_from_categ_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_route_from_categ_ids +msgid "Category Routes" +msgstr "Categoría Rutas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_type +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_type +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_type +msgid "Category Type" +msgstr "Tipo categoría" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_cancelled_reason +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_cancelled_reason +msgid "Cause of cancelled" +msgstr "Causa de cancelación" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_out_service_description +msgid "Cause of out of service" +msgstr "Causa de fuera de servicio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_change_avail +msgid "Change avail" +msgstr "Cambiar disponibilidad" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_change_closed +msgid "Change closed" +msgstr "Cambio cerrado" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_change_closed_arrival +msgid "Change closed arrival" +msgstr "Cambiar llegada cerrada" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_change_closed_departure +msgid "Change closed departure" +msgstr "Cambiar la salida cerrada" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_change_max_stay +msgid "Change max stay" +msgstr "Cambiar la estadía máxima" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_change_max_stay_arrival +msgid "Change max stay arrival" +msgstr "Cambio Llegada Max" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_change_min_stay +msgid "Change min stay" +msgstr "Cambiar la estadía mínima" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_change_min_stay_arrival +msgid "Change min stay arrival" +msgstr "Cambiar la llegada de la estancia mínima" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_change_no_ota +msgid "Change no ota" +msgstr "Cambiar no OTA" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_checkin +msgid "Check In" +msgstr "Check In" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_checkout +msgid "Check Out" +msgstr "Check Out" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_check_rooms +msgid "Check Rooms" +msgstr "Restringir habitación" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Checkin Date" +msgstr "Checkin Date" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_checkin_mode +msgid "Checkin mode" +msgstr "Checkin mode" + +#. module: hotel +#: code:addons/hotel/models/hotel_service_line.py:207 +#, python-format +msgid "Checkout must be greater or equal checkin date" +msgstr "El Check-out debe ser mayor o igual a la fecha de Check-in" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_child_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_child_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_child_id +msgid "Child Categories" +msgstr "Categorías hijas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_children +msgid "Children" +msgstr "Niños" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.checkin_wizard_form_2 +#: model:ir.ui.view,arch_db:hotel.view_tree_cardex +msgid "Client name" +msgstr "Nombre de Cliente" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_closed +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_closed +msgid "Closed" +msgstr "Cerrado" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_closed_arrival +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_closed_arrival +msgid "Closed Arrival" +msgstr "Cerrar Salida" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_closed_departure +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_closed_departure +msgid "Closed Departure" +msgstr "Cerrar Llegada" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_code_type +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_virtual_code +msgid "Code" +msgstr "Código" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_color +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_reserve_color +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_reserve_color_text +msgid "Color" +msgstr "Color" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_color +#: model:ir.model.fields,field_description:hotel.field_hotel_room_color +#: model:ir.model.fields,field_description:hotel.field_hotel_services_color +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_color +msgid "Color Index" +msgstr "Índice de Colores" + +#. module: hotel +#: model:ir.model,name:hotel.model_res_company +msgid "Companies" +msgstr "Compañías" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_company_id +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_company_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_company_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_company_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_company_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_company_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_company_id +msgid "Company" +msgstr "Compañía" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Compute" +msgstr "Calcular" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.configuration_others +#: model:ir.ui.menu,name:hotel.hotel_configuration_menu +msgid "Configuration" +msgstr "Configuración" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.action_hotel_config +msgid "Configure Hotel" +msgstr "Configurar Hotel" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Confirm" +msgstr "Confirmar" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Confirm Sale" +msgstr "Confirmar ficha" + +#. module: hotel +#: model:mail.template,subject:hotel.mail_template_hotel_reservation +msgid "Confirmación de los detalles de su reserva en ${object.company_id.property_name}" +msgstr "Confirmación de los detalles de su reserva en ${object.company_id.property_name}" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_confirmation_date +msgid "Confirmation Date" +msgstr "Fecha confirmación" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_purchase_method +#: model:ir.model.fields,field_description:hotel.field_hotel_room_purchase_method +#: model:ir.model.fields,field_description:hotel.field_hotel_services_purchase_method +msgid "Control Purchase Bills" +msgstr "Control Purchase Bills" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_standard_price +#: model:ir.model.fields,field_description:hotel.field_hotel_room_standard_price +#: model:ir.model.fields,field_description:hotel.field_hotel_services_standard_price +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_standard_price +msgid "Cost" +msgstr "Coste" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Cost Method" +msgstr "Método del costo" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_cost_method +#: model:ir.model.fields,field_description:hotel.field_hotel_room_cost_method +#: model:ir.model.fields,field_description:hotel.field_hotel_services_cost_method +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_cost_method +msgid "Cost method" +msgstr "Método de coste" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_standard_price +#: model:ir.model.fields,help:hotel.field_hotel_room_standard_price +#: model:ir.model.fields,help:hotel.field_hotel_services_standard_price +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_standard_price +msgid "Cost of the product template used for standard stock valuation in accounting and used as a base price on purchase orders. Expressed in the default unit of measure of the product." +msgstr "Coste para la plantilla de producto usada para la valoración de existencias estándar en contabilidad, y utilizada como precio de referencia en órdenes de compra. Se expresa en la unidad de medida por defecto del producto." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_property_cost_method +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_property_cost_method +#: model:ir.model.fields,field_description:hotel.field_hotel_room_property_cost_method +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_property_cost_method +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_property_cost_method +#: model:ir.model.fields,field_description:hotel.field_hotel_services_property_cost_method +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_property_cost_method +msgid "Costing Method" +msgstr "Método de coste" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Create Invoice" +msgstr "Crear Factura" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_folio_advance_payment_inv +msgid "Create Invoices" +msgstr "Crear facturas" + +#. module: hotel +#: selection:checkin.wizard,op_select_partner:0 +msgid "Create a new partner for checkin" +msgstr "Create a new partner for checkin" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_folio_advance_payment_inv +msgid "Create and View Invoices" +msgstr "Crear y ver facturas" + +#. module: hotel +#: code:addons/hotel/models/hotel_dashboard.py:219 +#, python-format +msgid "Create invoice/bill" +msgstr "Crear Factura/cuenta" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_cardex_create_uid +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_create_uid +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_create_uid +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_create_uid +#: model:ir.model.fields,field_description:hotel.field_folio_report_wizard_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_floor_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_line_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_room_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_services_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_availability_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_duplicate_reservation_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_price_reservation_days_create_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_split_reservation_create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_cardex_create_date +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_create_date +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_create_date +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_create_date +#: model:ir.model.fields,field_description:hotel.field_folio_report_wizard_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_floor_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_line_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_room_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_services_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_availability_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_duplicate_reservation_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_price_reservation_days_create_date +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_split_reservation_create_date +msgid "Created on" +msgstr "Creado el" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Creation Date" +msgstr "Fecha de creación" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_currency_id +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_currency_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_currency_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_currency_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_currency_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_currency_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_currency_id +msgid "Currency" +msgstr "Moneda" + +#. module: hotel +#: code:addons/hotel/models/hotel_folio.py:401 +#: model:ir.actions.act_window,name:hotel.open_currency_exchange_tree +#: model:ir.ui.view,arch_db:hotel.view_currency_exchange_form +#: model:ir.ui.view,arch_db:hotel.view_currency_exchange_tree +#, python-format +msgid "Currency Exchange" +msgstr "Cambio de Moneda" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Current Booking" +msgstr "Reservas Actuales" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_qty_available +#: model:ir.model.fields,help:hotel.field_hotel_room_qty_available +#: model:ir.model.fields,help:hotel.field_hotel_services_qty_available +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_qty_available +msgid "" +"Current quantity of products.\n" +"In a context with a single Stock Location, this includes goods stored at this Location, or any of its children.\n" +"In a context with a single Warehouse, this includes goods stored in the Stock Location of this Warehouse, or any of its children.\n" +"stored in the Stock Location of the Warehouse of this Shop, or any of its children.\n" +"Otherwise, this includes goods stored in any Stock Location with 'internal' type." +msgstr "" +"Cantidad actual de los productos.\n" +"En un contexto de una sola ubicación de existencias, esto incluye los bienes almacenados en esta ubicación, o cualquiera de sus hijas.\n" +"En un contexto de un solo almacén, esto incluye los bienes almacenados en la ubicación de existencias de ese almacén, o cualquiera de sus hijas.\n" +"En cualquier otro caso, esto incluye los bienes almacenados en cualquier ubicación de existencias de tipo 'Interna'." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_currrency_ids +msgid "Currrency ids" +msgstr "ids de moneda" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_partner_id +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_order_partner_id +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_partner_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_order_partner_id +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio_search +msgid "Customer" +msgstr "Cliente" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_sale_delay +#: model:ir.model.fields,field_description:hotel.field_hotel_room_sale_delay +#: model:ir.model.fields,field_description:hotel.field_hotel_services_sale_delay +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_sale_delay +msgid "Customer Lead Time" +msgstr "Plazo de entrega del cliente" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_partner_ref +#: model:ir.model.fields,field_description:hotel.field_hotel_room_partner_ref +#: model:ir.model.fields,field_description:hotel.field_hotel_services_partner_ref +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_partner_ref +msgid "Customer Ref" +msgstr "Ref. Cliente" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_client_order_ref +msgid "Customer Reference" +msgstr "Referencia cliente" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_deposit_taxes_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_taxes_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_taxes_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_taxes_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_taxes_id +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Customer Taxes" +msgstr "Impuestos cliente" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Customer taxes applied on the service." +msgstr "Impuestos de cliente aplicados en el servicio." + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +msgid "Customer taxes apply on the perticular room." +msgstr "Impuestos de cliente aplicados a una habitación particular" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.menu_hotel_customer +msgid "Customers" +msgstr "Clientes" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_line_date +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_availability_date +msgid "Date" +msgstr "Fecha" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_today_date +msgid "Date Ordered" +msgstr "Fecha de Orden" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_message_last_post +#: model:ir.model.fields,help:hotel.field_hotel_room_message_last_post +#: model:ir.model.fields,help:hotel.field_hotel_services_message_last_post +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_message_last_post +msgid "Date of the last message posted on the record." +msgstr "Date of the last message posted on the record." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_confirmation_date +msgid "Date on which the sale order is confirmed." +msgstr "Fecha en que se confirma el pedido de venta." + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Days" +msgstr "Días" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings_default_arrival_hour +msgid "Default Arrival Hour (GMT)" +msgstr "Hora por defecto de Llegada (GMT)" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings_default_departure_hour +msgid "Default Departure Hour (GMT)" +msgstr "Hora por defecto de Salida (GMT)" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_max_real_rooms +msgid "Default Max Room Allowed" +msgstr "Máx Habitaciones Permitidas por Defecto" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_uom_id +#: model:ir.model.fields,help:hotel.field_hotel_room_uom_id +#: model:ir.model.fields,help:hotel.field_hotel_services_uom_id +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_uom_id +msgid "Default Unit of Measure used for all stock operation." +msgstr "Unidad de medida por defecto utilizada para todas las operaciones de stock." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_uom_po_id +#: model:ir.model.fields,help:hotel.field_hotel_room_uom_po_id +#: model:ir.model.fields,help:hotel.field_hotel_services_uom_po_id +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_uom_po_id +msgid "Default Unit of Measure used for purchase orders. It must be in the same category than the default unit of measure." +msgstr "Unidad de medida por defecto utilizada para los pedidos de compra. Debe estar en la misma categoría que la unidad de medida por defecto." + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +msgid "Define supplier taxes if there any on the ty." +msgstr "Define supplier taxes if there any on the ty." + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_account_payment_folio_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_kanban +msgid "Delete" +msgstr "Borrar" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_qty_delivered +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_qty_delivered +msgid "Delivered" +msgstr "Entregado" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_delivery_count +#: model:ir.model.fields,field_description:hotel.field_hotel_room_delivery_count +#: model:ir.model.fields,field_description:hotel.field_hotel_services_delivery_count +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_delivery_count +msgid "Delivery" +msgstr "Entrega" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_partner_shipping_id +msgid "Delivery Address" +msgstr "Dirección de entrega" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_customer_lead +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_customer_lead +msgid "Delivery Lead Time" +msgstr "Tiempo inicial entrega" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_delivery_count +msgid "Delivery Orders" +msgstr "Pedidos de entrega" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_partner_shipping_id +msgid "Delivery address for current sales order." +msgstr "Dirección de entrega para el pedido de venta actual." + +#. module: hotel +#: code:addons/hotel/models/cardex.py:38 +#, python-format +msgid "Departure date (%s) is prior to arrival on %s" +msgstr "La fecha de salida (%s) es anterior a la llegada el %s" + +#. module: hotel +#: code:addons/hotel/models/cardex.py:80 +#, python-format +msgid "Departure date, is prior to arrival. Check it now. %s" +msgstr "La fecha de salida es anterior a la llegada. Revíselo ahora. %s" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_route_ids +#: model:ir.model.fields,help:hotel.field_hotel_room_route_ids +#: model:ir.model.fields,help:hotel.field_hotel_services_route_ids +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_route_ids +msgid "Depending on the modules installed, this will allow you to define the route of the product: whether it will be bought, manufactured, MTO/MTS,..." +msgstr "Dependiendo de los módulos instalados, este permite definir la ruta del producto: si será comprado, facturado, bajo pedido o desde existencias..." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_name +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_description +#: model:ir.model.fields,field_description:hotel.field_hotel_room_description +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_name +#: model:ir.model.fields,field_description:hotel.field_hotel_services_description +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_description +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Description" +msgstr "Descripción" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +msgid "Description Sales" +msgstr "Description Sales" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_description_picking +#: model:ir.model.fields,field_description:hotel.field_hotel_room_description_picking +#: model:ir.model.fields,field_description:hotel.field_hotel_services_description_picking +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_description_picking +msgid "Description on Picking" +msgstr "Descripción en albarán" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Descriptions" +msgstr "Descripciones" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_currency_exchange_form +msgid "Details" +msgstr "Detalles" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_account_invoice_dif_customer_payment +msgid "Dif customer payment" +msgstr "Dif customer payment" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_discount +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_discount +msgid "Discount (%)" +msgstr "Descuento (%)" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_discount_type +msgid "Discount Type" +msgstr "Tipo de Descuento" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_cardex_display_name +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_display_name +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_display_name +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_display_name +#: model:ir.model.fields,field_description:hotel.field_folio_report_wizard_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_floor_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_line_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_room_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_services_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_availability_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_duplicate_reservation_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_price_reservation_days_display_name +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_split_reservation_display_name +#: model:ir.model.fields,field_description:hotel.field_report_hotel_report_hotel_folio_display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: hotel +#: selection:currency.exchange,state:0 +#: model:ir.ui.view,arch_db:hotel.view_currency_exchange_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Done" +msgstr "Hecho" + +#. module: hotel +#: selection:hotel.folio,channel_type:0 +msgid "Door" +msgstr "Puerta" + +#. module: hotel +#: code:addons/hotel/wizard/folio_make_invoice_advance.py:87 +#, python-format +msgid "Down Payment" +msgstr "Down Payment" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_amount +msgid "Down Payment Amount" +msgstr "Cantidad del Depósito" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_product_id +msgid "Down Payment Product" +msgstr "Producto de Depósito" + +#. module: hotel +#: selection:folio.advance.payment.inv,advance_payment_method:0 +msgid "Down payment (fixed amount)" +msgstr "Down payment (fixed amount)" + +#. module: hotel +#: selection:folio.advance.payment.inv,advance_payment_method:0 +msgid "Down payment (percentage)" +msgstr "Down payment (percentage)" + +#. module: hotel +#: code:addons/hotel/wizard/folio_make_invoice_advance.py:84 +#, python-format +msgid "Down payment of %s%%" +msgstr "Down payment of %s%%" + +#. module: hotel +#: selection:currency.exchange,state:0 +msgid "Draft" +msgstr "Borrador" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_duplicate_reservation_wizard +msgid "Duplicate" +msgstr "Duplicar" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_duplicate_reservation_wizard +msgid "Duplicate Rerservation" +msgstr "Duplicar Reserva" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.action_hotel_duplicate_reservation +msgid "Duplicate Reservation" +msgstr "Duplicar Reserva" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_duration +msgid "Duration in Days" +msgstr "Duración en días" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_email_cardex +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_email +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_email +msgid "E-mail" +msgstr "Email" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_kanban +msgid "Edit" +msgstr "Editar" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_edit_room +msgid "Edit room" +msgstr "Editar habitacion" + +#. module: hotel +#: model:ir.actions.report.xml,name:hotel.report_hotel_currency +#: model:ir.ui.view,arch_db:hotel.report_currency_exchange +msgid "Encashment Certificate" +msgstr "Certificado de cobro" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_folio_report_wizard_date_end +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_date_end +msgid "End Date" +msgstr "Fecha finalización" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_cardex_enter_date +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_enter_date +msgid "Enter date" +msgstr "Fecha Entrada" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_cardex_exit_date +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_exit_date +msgid "Exit date" +msgstr "Fecha Salida" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_property_account_expense_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_property_account_expense_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_property_account_expense_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_property_account_expense_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_property_account_expense_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_property_account_expense_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_property_account_expense_id +msgid "Expense Account" +msgstr "Cuenta de gasto" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_validity_date +msgid "Expiration Date" +msgstr "Fecha de caducidad" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_tree +msgid "Final Price" +msgstr "Precio Final" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_fiscal_position_id +msgid "Fiscal Position" +msgstr "Posición fiscal" + +#. module: hotel +#: selection:hotel.reservation,discount_type:0 +msgid "Fixed" +msgstr "Cantidad" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_discount_fixed +msgid "Fixed Discount" +msgstr "Descuento sobre Fijo" + +#. module: hotel +#: selection:hotel.room,sale_price_type:0 +msgid "Fixed Price" +msgstr "Precio Fijo" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.open_hotel_floor_form_tree +msgid "Floor Structure" +msgstr "Estructura de Pisos" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_account_payment_folio_id +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_folio_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_folio_id +#: model:ir.model.fields,field_description:hotel.field_payment_return_folio_id +#: model:ir.ui.menu,name:hotel.menu_all_folio +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Folio" +msgstr "Ficha" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Folio Form" +msgstr "Folio Form" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_folio_no +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_name +msgid "Folio Number" +msgstr "Número de Ficha" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_tree +msgid "Folio Pending Amount" +msgstr "Pendiente en Ficha" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio_wizard +msgid "Folio Report" +msgstr "Informe de Fichas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_account_invoice_folio_ids +msgid "Folio ids" +msgstr "Fichas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_folio_name +msgid "Folio name" +msgstr "Referencia Ficha" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.hotel_partner_folios +#: model:ir.model.fields,field_description:hotel.field_res_partner_folios_count +#: model:ir.model.fields,field_description:hotel.field_res_users_folios_count +#: model:ir.ui.view,arch_db:hotel.hotel_folio_calendar_view +#: model:ir.ui.view,arch_db:hotel.view_partner_form +msgid "Folios" +msgstr "Fichas" + +#. module: hotel +#: model:ir.model,name:hotel.model_folio_advance_payment_inv +msgid "Folios Advance Payment Invoice" +msgstr "Folios Advance Payment Invoice" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_partner_form +msgid "Folios related with this contact" +msgstr "Fichas relacionadas con este cliente" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_message_follower_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_message_follower_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_message_follower_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_message_follower_ids +msgid "Followers" +msgstr "Followers" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_message_channel_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_message_channel_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_message_channel_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_message_channel_ids +msgid "Followers (Channels)" +msgstr "Followers (Channels)" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_message_partner_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_message_partner_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_message_partner_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_message_partner_ids +msgid "Followers (Partners)" +msgstr "Followers (Partners)" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_removal_strategy_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_removal_strategy_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_removal_strategy_id +msgid "Force Removal Strategy" +msgstr "Forzar estrategia de retirada" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_virtual_available +#: model:ir.model.fields,field_description:hotel.field_hotel_room_virtual_available +#: model:ir.model.fields,field_description:hotel.field_hotel_services_virtual_available +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_virtual_available +msgid "Forecast Quantity" +msgstr "Cantidad prevista" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_virtual_available +#: model:ir.model.fields,help:hotel.field_hotel_room_virtual_available +#: model:ir.model.fields,help:hotel.field_hotel_services_virtual_available +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_virtual_available +msgid "" +"Forecast quantity (computed as Quantity On Hand - Outgoing + Incoming)\n" +"In a context with a single Stock Location, this includes goods stored in this location, or any of its children.\n" +"In a context with a single Warehouse, this includes goods stored in the Stock Location of this Warehouse, or any of its children.\n" +"Otherwise, this includes goods stored in any Stock Location with 'internal' type." +msgstr "" +"Cantidad prevista (calculada como cantidad a mano - saliente + entrante)\n" +"En un contexto de una sola ubicación de existencias, esto incluye los bienes almacenados en esta ubicación, o cualquiera de sus hijas.\n" +"En un contexto de un solo almacén, esto incluye los bienes almacenados en la ubicación de existencias de ese almacén, o cualquiera de sus hijas.\n" +"En cualquier otro caso, esto incluye los bienes almacenados en cualquier ubicación de existencias de tipo 'Interna'." + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Foreign Exchange" +msgstr "Divisas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_dfr +msgid "Friday" +msgstr "Viernes" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_date_start +msgid "From" +msgstr "De" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "From " +msgstr "Desde " + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_ser_checkin +msgid "From Date" +msgstr "Fecha Desde" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_account_invoice_from_folio +msgid "From folio" +msgstr "Desde Ficha" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "General Info" +msgstr "General Info" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.menu_open_hotel_folio1_form_tree_all +msgid "Generate Folio" +msgstr "Fichas de Reserva" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_packaging_ids +#: model:ir.model.fields,help:hotel.field_hotel_room_packaging_ids +#: model:ir.model.fields,help:hotel.field_hotel_services_packaging_ids +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_packaging_ids +msgid "Gives the different ways to package the same product. This has no impact on the picking order and is mainly used if you use the EDI module." +msgstr "Indica las diferentes formas de empaquetar el mismo producto. Esto no tiene ningún impacto en la preparación de albaranes y se utiliza principalmente si utiliza el módulo EDI." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_sequence +#: model:ir.model.fields,help:hotel.field_hotel_services_sequence +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_sequence +msgid "Gives the sequence order when displaying a product list" +msgstr "Proporciona el orden de secuencia al mostrar una lista de productos" + +#. module: hotel +#: selection:hotel.virtual.room.restriction.item,applied_on:0 +#: selection:hotel.wizard.massive.changes,applied_on:0 +msgid "Global" +msgstr "Global" + +#. module: hotel +#: model:mail.template,subject:hotel.mail_template_hotel_exit +msgid "Gracias por alojarse con nosotros en ${object.company_id.property_name}" +msgstr "Gracias por alojarse con nosotros en ${object.company_id.property_name}" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio_search +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Group By" +msgstr "Agrupar por" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_aenities_search +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_search +msgid "Group By..." +msgstr "Agrupar por..." + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Guest" +msgstr "Huésped" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_guest_name +msgid "Guest Name" +msgstr "Nombre del Cliente" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_config_settings_default_arrival_hour +#: model:ir.model.fields,help:hotel.field_hotel_config_settings_default_departure_hour +msgid "HH:mm Format" +msgstr "Formato HH:mm" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.hotel_menu +#: model:ir.ui.view,arch_db:hotel.report_currency_exchange +msgid "Hotel" +msgstr "Hotel" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_config_settings +msgid "Hotel Default Hours" +msgstr "Horario por Defecto del Hotel" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.open_hotel_folio1_form_tree_all +#: model:ir.actions.report.xml,name:hotel.report_hotel_management +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_tree +msgid "Hotel Folio" +msgstr "Ficha de reservas" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.hotel_folio_wizard +msgid "Hotel Folio Report" +msgstr "Informe de la Ficha de reservas" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.hotel_management_menu +msgid "Hotel Management" +msgstr "Gestión del Hotel" + +#. module: hotel +#: model:res.groups,name:hotel.group_hotel_user +msgid "Hotel Management / User" +msgstr "Hotel Management / User" + +#. module: hotel +#: model:res.groups,name:hotel.group_hotel_manager +msgid "Hotel Management/ Manager" +msgstr "Hotel Management/ Manager" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.action_hotel_massive_change +msgid "Hotel Massive Change" +msgstr "Cambios Masivos" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_hotel_id +msgid "Hotel Name" +msgstr "Nombre del Hotel" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_config_settings +msgid "Hotel Parity" +msgstr "Emparejado" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_hotel_policy +msgid "Hotel Policy" +msgstr "Política del Hotel" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.open_hotel_reservation_form_tree_all +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_tree +msgid "Hotel Reservation" +msgstr "Reserva del hotel" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.action_hotel_room_form +#: model:ir.model,name:hotel.model_hotel_room +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_search +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_tree +msgid "Hotel Room" +msgstr "Habitaciones" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.action_hotel_room_amenities_view_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_aenities_search +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_list +msgid "Hotel Room Amenities" +msgstr "Características de las Habitaciones" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.action_hotel_room_amenities_type_view_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_type_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_type_list +msgid "Hotel Room Amenities Type" +msgstr "Tipos de características de las Habitaciones" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_type_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_type_tree +msgid "Hotel Room Type" +msgstr "TIpos de Habitaciones" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.action_hotel_services_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_search +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_tree +msgid "Hotel Services" +msgstr "Servicios" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_services +msgid "Hotel Services and its charges" +msgstr "Servicios del hotel y sus cargos" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_config_settings +msgid "Hotel Settings" +msgstr "Configuración del Hotel" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_floor_form +msgid "Hotel Ubication" +msgstr "Ubicación" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_floor_tree +msgid "Hotel Ubications" +msgstr "Ubicaciones" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_hotel_policy +msgid "Hotel policy for payment that either the guest has to payment at booking time or check-in check-out time." +msgstr "Política del hotel para el pago que el huésped debe abonar al momento de la reserva o al momento del check-in / check-out." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_room_lines +msgid "Hotel room reservation detail." +msgstr "Detalle de la reserva" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_service_lines +msgid "Hotel services detail provide tocustomer and it will include in main Invoice." +msgstr "Los detalles de servicios al cliente que se incluirán en la Factura principal." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_cardex_id +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_id +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_id +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_id +#: model:ir.model.fields,field_description:hotel.field_folio_report_wizard_id +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings_id +#: model:ir.model.fields,field_description:hotel.field_hotel_floor_id +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_id +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_id +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_line_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_availability_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_id +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_duplicate_reservation_id +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_id +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_price_reservation_days_id +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_split_reservation_id +#: model:ir.model.fields,field_description:hotel.field_report_hotel_report_hotel_folio_id +msgid "ID" +msgstr "ID" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "If a Hotel Folio is done, you cannot modify it manually anymore. However, you will still be able to invoice or deliver. This is used to freeze the Hotel Folio." +msgstr "Si la Ficha esta como checkout, tu no puedes modificarla a posteriori" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_message_unread +#: model:ir.model.fields,help:hotel.field_hotel_room_message_unread +#: model:ir.model.fields,help:hotel.field_hotel_services_message_unread +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_message_unread +msgid "If checked new messages require your attention." +msgstr "If checked new messages require your attention." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_message_needaction +#: model:ir.model.fields,help:hotel.field_hotel_room_message_needaction +#: model:ir.model.fields,help:hotel.field_hotel_services_message_needaction +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_message_needaction +msgid "If checked, new messages require your attention." +msgstr "If checked, new messages require your attention." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_type_property_valuation +#: model:ir.model.fields,help:hotel.field_hotel_room_type_property_valuation +#: model:ir.model.fields,help:hotel.field_hotel_service_type_property_valuation +msgid "If perpetual valuation is enabled for a product, the system will automatically create journal entries corresponding to stock moves, with product price as specified by the 'Costing Method'. The inventory variation account set on the product category will represent the current inventory value, and the stock input and stock output account will hold the counterpart moves for incoming and outgoing products." +msgstr "Si la valoración perpetua se activa para un producto, el sistema creará automáticamente asientos contables correspondientes a movimientos de stock, con el precio de producto indicado según el \"método de coste\". La cuenta de valoración de inventario establecida en la categoría de producto representará la cuenta de inventario actual, y las cuentas de entrada y salida de mercancía contendrán las contrapartidas de movimiento para los productos entrantes y salientes." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_property_valuation +#: model:ir.model.fields,help:hotel.field_hotel_room_property_valuation +#: model:ir.model.fields,help:hotel.field_hotel_services_property_valuation +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_property_valuation +msgid "If perpetual valuation is enabled for a product, the system will automatically create journal entries corresponding to stock moves, with product price as specified by the 'Costing Method'The inventory variation account set on the product category will represent the current inventory value, and the stock input and stock output account will hold the counterpart moves for incoming and outgoing products." +msgstr "Si la valoración perpetua está activada para un producto, el sistema creará automáticamente entradas de diario correspondientes a los movimientos de stock, con el precio del producto especificado por el método de cálculo de costes. La cuenta de variación de inventario establecida en la categoría de producto representará el valor de inventario actual. La entrada de stock y la cuenta de salida de existencias tendrán los movimientos de contrapartida para los productos entrantes y salientes." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_restriction_active +msgid "If unchecked, it will allow you to hide the restriction plan without removing it." +msgstr "Si no se selecciona, le permitirá ocultar el plan de restricción sin eliminarlo." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_active +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_active +#: model:ir.model.fields,help:hotel.field_hotel_services_active +msgid "If unchecked, it will allow you to hide the product without removing it." +msgstr "Si no está marcado, permitirá ocultar el producto sin eliminarlo." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_image +msgid "Image" +msgstr "Imagen" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_image +#: model:ir.model.fields,help:hotel.field_hotel_room_image +#: model:ir.model.fields,help:hotel.field_hotel_services_image +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_image +msgid "Image of the product variant (Big-sized image of product template if false). It is automatically resized as a 1024x1024px image, with aspect ratio preserved." +msgstr "Imagen de la variante del producto (Imagen grande de la plantilla del producto en caso de que esté vacía). Se redimensionará automáticamente como una imagen 1024x1024px, manteniendo la proporción." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_image_medium +#: model:ir.model.fields,help:hotel.field_hotel_room_image_medium +#: model:ir.model.fields,help:hotel.field_hotel_services_image_medium +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_image_medium +msgid "Image of the product variant (Medium-sized image of product template if false)." +msgstr "Imagen de la variante del producto (Imagen mediana de la plantilla del producto en caso de que esté vacía)." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_image_small +#: model:ir.model.fields,help:hotel.field_hotel_room_image_small +#: model:ir.model.fields,help:hotel.field_hotel_services_image_small +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_image_small +msgid "Image of the product variant (Small-sized image of product template if false)." +msgstr "Imagen de la variante del producto (Imagen pequeña de la plantilla del producto en caso de que esté vacía)." + +#. module: hotel +#: selection:hotel.reservation,cancelled_reason:0 +msgid "In time" +msgstr "A tiempo" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_service_ids +msgid "Included Services" +msgstr "Servicios Incluídos" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_deposit_account_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_property_account_income_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_property_account_income_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_property_account_income_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_property_account_income_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_property_account_income_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_property_account_income_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_property_account_income_id +msgid "Income Account" +msgstr "Cuenta de ingresos" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_incoming_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_room_incoming_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_services_incoming_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_incoming_qty +msgid "Incoming" +msgstr "Entrada" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_incoterm +msgid "Incoterms" +msgstr "Incoterms" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Information" +msgstr "Información" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_input_curr +msgid "Input Currency" +msgstr "Moneda de Entrada" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_categ_id +msgid "Internal Category" +msgstr "Categoría interna" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_internal_comment +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_folio_internal_comment +msgid "Internal Folio Notes" +msgstr "Notas Internas de la Ficha" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_partner_internal_comment +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_partner_internal_comment +msgid "Internal Partner Notes" +msgstr "Notas Internas sobre el Cliente" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_code +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_default_code +#: model:ir.model.fields,field_description:hotel.field_hotel_room_code +#: model:ir.model.fields,field_description:hotel.field_hotel_room_default_code +#: model:ir.model.fields,field_description:hotel.field_hotel_services_code +#: model:ir.model.fields,field_description:hotel.field_hotel_services_default_code +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_code +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_default_code +msgid "Internal Reference" +msgstr "Referencia interna" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_barcode +#: model:ir.model.fields,help:hotel.field_hotel_room_barcode +#: model:ir.model.fields,help:hotel.field_hotel_services_barcode +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_barcode +msgid "International Article Number used for product identification." +msgstr "Número de artículo internacional usado para la identificación de producto." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_incoterm +msgid "International Commercial Terms are a series of predefined commercial terms used in international transactions." +msgstr "Los términos de comercio internacional son una serie de condiciones comerciales usadas en las transacciones internacionales." + +#. module: hotel +#: code:addons/hotel/models/hotel_virtual_room_restriction_item.py:75 +#, python-format +msgid "Invalid Dates" +msgstr "Fechas no válidas" + +#. module: hotel +#: code:addons/hotel/wizard/split_reservation.py:51 +#, python-format +msgid "Invalid Nights! Max is '%d'" +msgstr "Noches inválidas! Max es '%d'" + +#. module: hotel +#: code:addons/hotel/models/res_config.py:95 +#, python-format +msgid "Invalid arrival hour (Format: HH:mm)" +msgstr "Hora de llegada no válida (Formato: HH:mm)" + +#. module: hotel +#: code:addons/hotel/date_utils.py:114 code:addons/hotel/date_utils.py:157 +#: code:addons/hotel/date_utils.py:191 +#, python-format +msgid "Invalid date. Can't compare it!" +msgstr "Fecha invalida. No puedo compararlo!" + +#. module: hotel +#: code:addons/hotel/models/res_config.py:97 +#, python-format +msgid "Invalid departure hour (Format: HH:mm)" +msgstr "Hora de salida no válida (Formato: HH:mm)" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_property_stock_inventory +#: model:ir.model.fields,field_description:hotel.field_hotel_room_property_stock_inventory +#: model:ir.model.fields,field_description:hotel.field_hotel_services_property_stock_inventory +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_property_stock_inventory +msgid "Inventory Location" +msgstr "Ubicación de inventario" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_property_valuation +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_property_valuation +#: model:ir.model.fields,field_description:hotel.field_hotel_room_property_valuation +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_property_valuation +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_property_valuation +#: model:ir.model.fields,field_description:hotel.field_hotel_services_property_valuation +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_property_valuation +msgid "Inventory Valuation" +msgstr "Valoración del inventario" + +#. module: hotel +#: model:ir.model,name:hotel.model_account_invoice +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_hotel_invoice_id +msgid "Invoice" +msgstr "Factura" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_partner_invoice_id +msgid "Invoice Address" +msgstr "Dirección de factura" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.action_view_folio_advance_payment_inv +msgid "Invoice Folio" +msgstr "Facturar Ficha" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_invoice_lines +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_invoice_lines +msgid "Invoice Lines" +msgstr "Líneas de factura" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_folio_advance_payment_inv +msgid "Invoice Sales Order" +msgstr "Facturar pedido de venta" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_invoice_status +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_invoice_status +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_invoice_status +msgid "Invoice Status" +msgstr "Estado factura" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_partner_invoice_id +msgid "Invoice address for current sales order." +msgstr "Dirección de facturación para el pedido de venta actual." + +#. module: hotel +#: selection:folio.advance.payment.inv,advance_payment_method:0 +msgid "Invoiceable lines" +msgstr "Invoiceable lines" + +#. module: hotel +#: selection:folio.advance.payment.inv,advance_payment_method:0 +msgid "Invoiceable lines (deduct down payments)" +msgstr "Invoiceable lines (deduct down payments)" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_qty_invoiced +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_qty_invoiced +msgid "Invoiced" +msgstr "Facturado" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_invoice_ids +#: model:ir.ui.view,arch_db:hotel.view_account_payment_folio_form +msgid "Invoices" +msgstr "Facturas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_invoices_amount +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_folio_pending_amount +msgid "Invoices amount" +msgstr "Cantidad Facturada" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_invoices_paid +msgid "Invoices paid" +msgstr "Facturas Pagadas" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_folio_advance_payment_inv +msgid "" +"Invoices will be created in draft so that you can review\n" +" them before validation." +msgstr "" +"Las facturas se crearán en borrador para que puedan ser revisadas\n" +" antes de su validación." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_invoice_policy +#: model:ir.model.fields,field_description:hotel.field_hotel_room_invoice_policy +#: model:ir.model.fields,field_description:hotel.field_hotel_services_invoice_policy +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_invoice_policy +msgid "Invoicing Policy" +msgstr "Política de Facturación" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_isamenitytype +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_isamenitytype +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_isamenitytype +#: model:ir.model.fields,field_description:hotel.field_product_category_isamenitytype +msgid "Is Amenities Type" +msgstr "Es un tipo de Característica" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_message_is_follower +#: model:ir.model.fields,field_description:hotel.field_hotel_room_message_is_follower +#: model:ir.model.fields,field_description:hotel.field_hotel_services_message_is_follower +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_message_is_follower +msgid "Is Follower" +msgstr "Is Follower" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_overbooking +msgid "Is Overbooking" +msgstr "Is Overbooking" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_isroom +#: model:ir.model.fields,field_description:hotel.field_hotel_room_isroom +#: model:ir.model.fields,field_description:hotel.field_hotel_services_isroom +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_isroom +#: model:ir.model.fields,field_description:hotel.field_product_product_isroom +msgid "Is Room" +msgstr "Es Habitación" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_isroomtype +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_isroomtype +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_isroomtype +#: model:ir.model.fields,field_description:hotel.field_product_category_isroomtype +msgid "Is Room Type" +msgstr "Es un tipo de Habitación" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_isservicetype +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_isservicetype +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_isservicetype +#: model:ir.model.fields,field_description:hotel.field_product_category_isservicetype +msgid "Is Service Type" +msgstr "Es un tipo d eServicio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_isservice +#: model:ir.model.fields,field_description:hotel.field_hotel_room_isservice +#: model:ir.model.fields,field_description:hotel.field_hotel_services_isservice +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_isservice +#: model:ir.model.fields,field_description:hotel.field_product_product_isservice +msgid "Is Service id" +msgstr "Es id de servicio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_iscategid +#: model:ir.model.fields,field_description:hotel.field_hotel_room_iscategid +#: model:ir.model.fields,field_description:hotel.field_hotel_services_iscategid +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_iscategid +#: model:ir.model.fields,field_description:hotel.field_product_product_iscategid +msgid "Is categ id" +msgstr "es id de categ" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_is_checkin +msgid "Is checkin" +msgstr "Es checkin" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_is_checkout +msgid "Is checkout" +msgstr "Es checkout" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +msgid "It allows several reservations on the same room simultaneously based on the capacity of people" +msgstr "Permite varias reservas en la misma habitación, de manera simultánea, en función de la capacidad" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_account_payment_folio_form +msgid "Journal Items" +msgstr "Apuntes contables" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_message_last_post +#: model:ir.model.fields,field_description:hotel.field_hotel_room_message_last_post +#: model:ir.model.fields,field_description:hotel.field_hotel_services_message_last_post +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_message_last_post +msgid "Last Message Date" +msgstr "Last Message Date" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_cardex___last_update +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard___last_update +#: model:ir.model.fields,field_description:hotel.field_currency_exchange___last_update +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv___last_update +#: model:ir.model.fields,field_description:hotel.field_folio_report_wizard___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_floor___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_folio___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_line___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_room___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_services___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_availability___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_duplicate_reservation___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_price_reservation_days___last_update +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_split_reservation___last_update +#: model:ir.model.fields,field_description:hotel.field_report_hotel_report_hotel_folio___last_update +msgid "Last Modified on" +msgstr "Última modificación el" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_last_updated_res +msgid "Last Updated" +msgstr "Actualizado el" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_cardex_write_uid +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_write_uid +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_write_uid +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_write_uid +#: model:ir.model.fields,field_description:hotel.field_folio_report_wizard_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_floor_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_line_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_room_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_services_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_availability_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_duplicate_reservation_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_price_reservation_days_write_uid +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_split_reservation_write_uid +msgid "Last Updated by" +msgstr "Última actualización de" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_cardex_write_date +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_write_date +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_write_date +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_write_date +#: model:ir.model.fields,field_description:hotel.field_folio_report_wizard_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_floor_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_line_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_room_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_services_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_availability_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_duplicate_reservation_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_price_reservation_days_write_date +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_split_reservation_write_date +msgid "Last Updated on" +msgstr "Última actualización en" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Lastname, Firstname" +msgstr "Apellidos, Nombre" + +#. module: hotel +#: selection:hotel.reservation,cancelled_reason:0 +msgid "Late" +msgstr "Tarde" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Late Payment" +msgstr "Pago Retrasado" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Lates and NoShows" +msgstr "Fuera de plazo y NoShows" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_layout_category_sequence +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_layout_category_sequence +msgid "Layout Sequence" +msgstr "Secuencia plantilla" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_parent_left +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_parent_left +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_parent_left +msgid "Left Parent" +msgstr "Padre izquierdo" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Lines" +msgstr "Líneas" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_reservation_adults +msgid "List of adults there in guest list. " +msgstr "Adultos en la lista de huéspedes." + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +msgid "List of customer taxes applied on the ty." +msgstr "List of customer taxes applied on the ty." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_room_amenities +msgid "List of room amenities. " +msgstr "Lista de Características de habitaciones" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "List of supplier taxes related to the service provided by hotel." +msgstr "Lista de impuestos a proveedores relacionados con el servicio provisto por el hotel." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_location_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_location_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_location_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_location_id +msgid "Location" +msgstr "Ubicación" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_packaging_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_packaging_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_packaging_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_packaging_ids +msgid "Logistical Units" +msgstr "Unidades de logística" + +#. module: hotel +#: selection:hotel.folio,channel_type:0 +msgid "Mail" +msgstr "Mail" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_service_line_form +msgid "Manual Description" +msgstr "Descripción Manual" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_track_service +#: model:ir.model.fields,help:hotel.field_hotel_room_track_service +#: model:ir.model.fields,help:hotel.field_hotel_services_track_service +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_track_service +msgid "" +"Manually set quantities on order: Invoice based on the manually entered quantity, without creating an analytic account.\n" +"Timesheets on contract: Invoice based on the tracked hours on the related timesheet.\n" +"Create a task and track hours: Create a task on the sale order validation and track the work hours." +msgstr "" +"Establecer la cantidad en el pedido de forma manual: La factura se crea según cantidad introducida manualmente en el pedido, sin crear una cuenta analítica\n" +"Partes de horas en contrato: La factura se crea según las horas registradas en el parte de horas relacionado.\n" +"Crear tarea y controlar horas: Crea una tarea a la hora de validar el pedido de venta y la factura se crea según las horas registradas en dicha tarea." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_validity_date +msgid "Manually set the expiration date of your quotation (offer), or it will set the date automatically based on the template if online quotation is installed." +msgstr "Indique manualmente la fecha de caducidad de su presupuesto (oferta), o se cargará la fecha automáticamente en función de la plantilla." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_prepaid_warning_days +msgid "Margin in days to create a notice if a payment advance has not been recorded" +msgstr "Margen en días para crear un aviso si no se ha registrado un adelanto de pago" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_massive_changes_wizard +#: model:ir.ui.view,arch_db:hotel.view_hotel_massive_price_change_wizard +msgid "Massive Change" +msgstr "Cambiar" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_massive_changes_wizard +msgid "Massive Change & Close" +msgstr "Cambios Masivos & Cerrar" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.hotel_massive_change +#: model:ir.ui.view,arch_db:hotel.view_hotel_massive_changes_wizard +msgid "Massive Changes" +msgstr "Cambios Masivos" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Massive Day Prices" +msgstr "Cambiar Masivo de Precios" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.action_hotel_massive_price_change_reservation_days +#: model:ir.ui.view,arch_db:hotel.view_hotel_massive_price_change_wizard +msgid "Massive Price Change" +msgstr "Massive Price Change" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_max_adult +msgid "Max Adult" +msgstr "Max. Adultos" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_max_child +msgid "Max Child" +msgstr "Max. Niños" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_max_stay +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_max_stay +msgid "Max. Stay" +msgstr "Max. Estancia" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_max_stay_arrival +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_max_stay_arrival +msgid "Max. Stay Arrival" +msgstr "Max. Estancia Llegada" + +#. module: hotel +#: code:addons/hotel/models/hotel_virtual_room_restriction_item.py:64 +#, python-format +msgid "Max. Stay Arrival can't be less than zero" +msgstr "Max. Estancia Llegada no puede ser menor que 0" + +#. module: hotel +#: code:addons/hotel/models/hotel_virtual_room_restriction_item.py:61 +#, python-format +msgid "Max. Stay can't be less than zero" +msgstr "Estancia máxima no puede ser menor que cero" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_image_medium +#: model:ir.model.fields,field_description:hotel.field_hotel_room_image_medium +#: model:ir.model.fields,field_description:hotel.field_hotel_services_image_medium +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_image_medium +msgid "Medium-sized image" +msgstr "Imagen de tamaño mediano" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_purchase_line_warn_msg +#: model:ir.model.fields,field_description:hotel.field_hotel_room_purchase_line_warn_msg +#: model:ir.model.fields,field_description:hotel.field_hotel_services_purchase_line_warn_msg +msgid "Message for Purchase Order Line" +msgstr "Message for Purchase Order Line" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_sale_line_warn_msg +#: model:ir.model.fields,field_description:hotel.field_hotel_room_sale_line_warn_msg +#: model:ir.model.fields,field_description:hotel.field_hotel_services_sale_line_warn_msg +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_sale_line_warn_msg +msgid "Message for Sales Order Line" +msgstr "Mensaje para la línea de pedido de venta" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_message_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_message_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_message_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_message_ids +msgid "Messages" +msgstr "Messages" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_min_stay +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_min_stay +msgid "Min. Stay" +msgstr "Min. Estancia" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_min_stay_arrival +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_min_stay_arrival +msgid "Min. Stay Arrival" +msgstr "Mín. Estancia Llegada" + +#. module: hotel +#: code:addons/hotel/models/hotel_virtual_room_restriction_item.py:59 +#, python-format +msgid "Min. Stay Arrival can't be less than zero" +msgstr "La llegada de la estancia mínima no puede ser inferior a cero" + +#. module: hotel +#: code:addons/hotel/models/hotel_virtual_room_restriction_item.py:56 +#, python-format +msgid "Min. Stay can't be less than zero" +msgstr "La estadía mínima no puede ser inferior a cero" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_orderpoint_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_orderpoint_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_orderpoint_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_orderpoint_ids +msgid "Minimum Stock Rules" +msgstr "Reglas de stock mínimo" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_mobile_cardex +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_mobile +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_mobile +msgid "Mobile" +msgstr "Móvil" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_account_payment_folio_form +msgid "Modify" +msgstr "Modificar" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_dmo +msgid "Monday" +msgstr "Lunes" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_name +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_name +#: model:ir.model.fields,field_description:hotel.field_hotel_room_name +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_name +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_name +#: model:ir.model.fields,field_description:hotel.field_hotel_services_name +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_name +#: model:ir.ui.view,arch_db:hotel.view_currency_exchange_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +msgid "Name" +msgstr "Nombre" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +msgid "Name in reports" +msgstr "Nombre mostrado en documentos (p.e. checkin)" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_price_reservation_days_new_price +msgid "New Price" +msgstr "Nuevo Precio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_nights +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_split_reservation_nights +msgid "Nights" +msgstr "Noches" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_availability_no_ota +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_no_ota +msgid "No OTA" +msgstr "No OTA" + +#. module: hotel +#: selection:hotel.reservation,cancelled_reason:0 +msgid "No Show" +msgstr "No Show" + +#. module: hotel +#: selection:hotel.folio,reservation_type:0 +msgid "Normal" +msgstr "Normal" + +#. module: hotel +#: code:addons/hotel/models/hotel_folio.py:455 +#, python-format +msgid "Not Any Order For %s " +msgstr "Sin pedido para %s" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_num_invoices +msgid "Num invoices" +msgstr "Num invoices" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_duplicate_reservation_num +msgid "Num. New Reservations" +msgstr "Num. Nuevas reservas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_message_needaction_counter +#: model:ir.model.fields,field_description:hotel.field_hotel_room_message_needaction_counter +#: model:ir.model.fields,field_description:hotel.field_hotel_services_message_needaction_counter +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_message_needaction_counter +msgid "Number of Actions" +msgstr "Number of Actions" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_reservation_children +msgid "Number of children there in guest list." +msgstr "Número de niños en la lista de huéspedes." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_reservation_customer_lead +#: model:ir.model.fields,help:hotel.field_hotel_service_line_customer_lead +msgid "Number of days between the order confirmation and the shipping of the products to the customer" +msgstr "Número de días entre la confirmación del pedido y la entrega de los productos al cliente" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_duration +msgid "Number of days which will automatically count from the check-in and check-out date. " +msgstr "Número de días que contarán automáticamente a partir de la fecha de entrada y salida." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_message_needaction_counter +#: model:ir.model.fields,help:hotel.field_hotel_room_message_needaction_counter +#: model:ir.model.fields,help:hotel.field_hotel_services_message_needaction_counter +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "Number of messages which requires an action" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_message_unread_counter +#: model:ir.model.fields,help:hotel.field_hotel_room_message_unread_counter +#: model:ir.model.fields,help:hotel.field_hotel_services_message_unread_counter +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_message_unread_counter +msgid "Number of unread messages" +msgstr "Number of unread messages" + +#. module: hotel +#: selection:hotel.reservation,state:0 +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "On Board" +msgstr "Dentro" + +#. module: hotel +#: selection:hotel.folio,hotel_policy:0 +msgid "On Booking" +msgstr "A Bordo" + +#. module: hotel +#: selection:hotel.folio,hotel_policy:0 +msgid "On Check In" +msgstr "Para Entrar" + +#. module: hotel +#: selection:hotel.folio,hotel_policy:0 +msgid "On Checkout" +msgstr "Para Salir" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_purchase_method +#: model:ir.model.fields,help:hotel.field_hotel_room_purchase_method +#: model:ir.model.fields,help:hotel.field_hotel_services_purchase_method +msgid "" +"On ordered quantities: control bills based on ordered quantities.\n" +"On received quantities: control bills based on received quantity." +msgstr "" +"On ordered quantities: control bills based on ordered quantities.\n" +"On received quantities: control bills based on received quantity." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_order_id +msgid "Order" +msgstr "Ordenar" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio_search +msgid "Order By Month" +msgstr "Ordenar por Mes" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_date_order +msgid "Order Date" +msgstr "Fecha de pedido" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_order_line_id +msgid "Order Line" +msgstr "Linea de pedido" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_order_line +msgid "Order Lines" +msgstr "Líneas del pedido" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_order_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_order_id +msgid "Order Reference" +msgstr "Referencia del pedido" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_state +msgid "Order Status" +msgstr "Estado del pedido" + +#. module: hotel +#: code:addons/hotel/models/hotel_folio.py:569 +#, python-format +msgid "Order id is not available" +msgstr "id de pedido no disponible" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Ordered Qty" +msgstr "Ctdad pedida" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_invoice_policy +#: model:ir.model.fields,help:hotel.field_hotel_room_invoice_policy +#: model:ir.model.fields,help:hotel.field_hotel_services_invoice_policy +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_invoice_policy +msgid "" +"Ordered Quantity: Invoice based on the quantity the customer ordered.\n" +"Delivered Quantity: Invoiced based on the quantity the vendor delivered (time or deliveries)." +msgstr "" +"Cantidad ordenada: Factura basada en la cantidad pedida por el cliente.\n" +"Cantidad entregada: Facturada en función de la cantidad entregada por el proveedor (tiempo o entregas)." + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Other data" +msgstr "Otra información" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Others" +msgstr "Otros" + +#. module: hotel +#: selection:hotel.reservation,state:0 +msgid "Out" +msgstr "Fuera" + +#. module: hotel +#: selection:hotel.folio,reservation_type:0 +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Out of Service" +msgstr "Fuera de Servicio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_outgoing_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_room_outgoing_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_services_outgoing_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_outgoing_qty +msgid "Outgoing" +msgstr "Saliente" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_out_curr +msgid "Output Currency" +msgstr "Moneda de salida" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Overbookings" +msgstr "Overbookings" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_product_packaging +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_product_packaging +msgid "Packaging" +msgstr "Empaquetado" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_parent_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_parent_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_parent_id +msgid "Parent Category" +msgstr "Categoría padre" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_parent_reservation +msgid "Parent Reservation" +msgstr "Reserva padre" + +#. module: hotel +#: model:ir.model,name:hotel.model_res_partner +msgid "Partner" +msgstr "Empresa" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Partner Note" +msgstr "Nota de Cliente" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_op_select_partner +msgid "Partner for checkin" +msgstr "Partner for checkin" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_cardex_partner_id +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_partner_id +msgid "Partner id" +msgstr "Id del cliente" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_payment_term_id +msgid "Payment Terms" +msgstr "Plazos de pago" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_payment_ids +msgid "Payment ids" +msgstr "Pagos" + +#. module: hotel +#: model:ir.model,name:hotel.model_payment_return +msgid "Payment return" +msgstr "Devolución de cobro" + +#. module: hotel +#: code:addons/hotel/models/hotel_folio.py:279 +#: code:addons/hotel/models/inherit_account_invoice.py:50 +#: model:ir.model,name:hotel.model_account_payment +#, python-format +msgid "Payments" +msgstr "Pagos" + +#. module: hotel +#: code:addons/hotel/models/hotel_folio.py:353 +#, python-format +msgid "Pending" +msgstr "Pendiente" + +#. module: hotel +#: selection:hotel.reservation,state:0 +msgid "Pending Entry" +msgstr "Por entrar" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_tree +msgid "Pending Pay" +msgstr "Pendiente de Pago" + +#. module: hotel +#: selection:hotel.reservation,discount_type:0 +msgid "Percent" +msgstr "Porcentaje" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_res_company_default_cancel_policy_percent +msgid "Percent to pay" +msgstr "Porcentaje a pagas" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_tree +msgid "Persons" +msgstr "Personas" + +#. module: hotel +#: selection:hotel.folio,channel_type:0 +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_phone +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_phone +msgid "Phone" +msgstr "Teléfono" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_picking_ids +msgid "Picking associated to this sale" +msgstr "Albarán asociado a esta venta" + +#. module: hotel +#: code:addons/hotel/models/currency_exchange.py:153 +#, python-format +msgid "Please Check Your Network Connectivity." +msgstr "Por favor comprueba tu Conexión a Internet." + +#. module: hotel +#: code:addons/hotel/models/hotel_folio.py:400 +#, python-format +msgid "Please Reserve Any Room." +msgstr "Reserva alguna habitación" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_account_payment_folio_form +msgid "Post Difference In" +msgstr "Contabilizar la diferencia en" + +#. module: hotel +#: selection:hotel.reservation,state:0 +msgid "Pre-reservation" +msgstr "Pre-reserva" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_prepaid_warning_days +msgid "Prepaid Warning Days" +msgstr "Días de aviso de Prepago" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_line_price +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_price +#: model:ir.model.fields,field_description:hotel.field_hotel_room_price +#: model:ir.model.fields,field_description:hotel.field_hotel_services_price +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_price +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_price +msgid "Price" +msgstr "Precio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_property_account_creditor_price_difference +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_property_account_creditor_price_difference_categ +#: model:ir.model.fields,field_description:hotel.field_hotel_room_property_account_creditor_price_difference +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_property_account_creditor_price_difference_categ +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_property_account_creditor_price_difference_categ +#: model:ir.model.fields,field_description:hotel.field_hotel_services_property_account_creditor_price_difference +msgid "Price Difference Account" +msgstr "Price Difference Account" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_price_reduce +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_price_reduce +msgid "Price Reduce" +msgstr "Descuento" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_price_reduce_taxexcl +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_price_reduce_taxexcl +msgid "Price Reduce Tax excl" +msgstr "Descuento excluido de Impuesto" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_price_reduce_taxinc +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_price_reduce_taxinc +msgid "Price Reduce Tax inc" +msgstr "Descuento incluido de Impuesto" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_sale_price_type +msgid "Price Type" +msgstr "Tipo de Precio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_price_virtual_room +msgid "Price Virtual Room" +msgstr "Precio Habitación Virtual" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_price_virtual_room +msgid "Price will be based on selected Virtual Room" +msgstr "Precio Basado en una Habitación Virtual" + +#. module: hotel +#: selection:hotel.wizard.massive.changes,section:0 +#: model:ir.model,name:hotel.model_product_pricelist +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_pricelist_id +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_pricelist_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_pricelist_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_pricelist_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_pricelist_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_pricelist_id +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_pricelist_id +msgid "Pricelist" +msgstr "Tarifas" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_restriction_item_applied_on +msgid "Pricelist Item applicable on selected option" +msgstr "Elemento de tarifa aplicable a la opción seleccionada" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_item_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_item_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_item_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_item_ids +#: model:ir.ui.view,arch_db:hotel.reservation_restriction_view_form +msgid "Pricelist Items" +msgstr "Elementos de tarifa" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_pricelist_id +#: model:ir.model.fields,help:hotel.field_hotel_reservation_pricelist_id +msgid "Pricelist for current sales order." +msgstr "Lista de precios para el pedido de venta actual." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_pricelist_item_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_pricelist_item_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_pricelist_item_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_pricelist_item_ids +msgid "Pricelist item ids" +msgstr "Elementos de Lista de precios" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_currency_exchange_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Print" +msgstr "Imprimir" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio_wizard +msgid "Print Folio" +msgstr "Imprimir Ficha" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Procurement" +msgstr "Abastecimiento" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_procurement_group_id +msgid "Procurement Group" +msgstr "Grupo de abastecimiento" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_property_stock_procurement +#: model:ir.model.fields,field_description:hotel.field_hotel_room_property_stock_procurement +#: model:ir.model.fields,field_description:hotel.field_hotel_services_property_stock_procurement +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_property_stock_procurement +msgid "Procurement Location" +msgstr "Ubicación de abastecimiento" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_procurement_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_procurement_ids +msgid "Procurements" +msgstr "Abastecimientos" + +#. module: hotel +#: model:ir.model,name:hotel.model_product_product +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_product_id +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_product_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_product_variant_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_product_variant_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_product_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_product_variant_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_product_variant_id +msgid "Product" +msgstr "Producto" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_attribute_line_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_attribute_line_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_attribute_line_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_attribute_line_ids +msgid "Product Attributes" +msgstr "Atributos del producto" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.product_category_tree_view +msgid "Product Categories" +msgstr "Categorías de productos" + +#. module: hotel +#: model:ir.model,name:hotel.model_product_category +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_room_categ_id +msgid "Product Category" +msgstr "Categoría de producto" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings_parity_pricelist_id +msgid "Product Pricelist" +msgstr "Lista de precios del producto" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_product_tmpl_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_product_tmpl_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_product_tmpl_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_product_tmpl_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_product_tmpl_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_product_tmpl_id +msgid "Product Template" +msgstr "Plantilla de producto" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type +#: model:ir.model.fields,field_description:hotel.field_hotel_services_type +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_type +msgid "Product Type" +msgstr "Tipo de producto" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_product_id +msgid "Product id" +msgstr "Producto id" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_product_id +msgid "Product_id" +msgstr "Product_id" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_property_stock_production +#: model:ir.model.fields,field_description:hotel.field_hotel_room_property_stock_production +#: model:ir.model.fields,field_description:hotel.field_hotel_services_property_stock_production +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_property_stock_production +msgid "Production Location" +msgstr "Ubicación de producción" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_product_variant_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_product_variant_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_product_variant_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_product_variant_ids +msgid "Products" +msgstr "Productos" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_res_company_additional_hours +msgid "Provide the min hours value for check in, checkout days, whatever the hours will be provided here based on that extra days will be calculated." +msgstr "Proporcione el valor de las horas mínimas para el check in, los días de salida, cualquiera que sea el horario que se proporcionará aquí en base a los días adicionales que se calcularán." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_description_purchase +#: model:ir.model.fields,field_description:hotel.field_hotel_room_description_purchase +#: model:ir.model.fields,field_description:hotel.field_hotel_services_description_purchase +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_description_purchase +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Purchase Description" +msgstr "Descripción de compra" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_purchase_line_warn +#: model:ir.model.fields,field_description:hotel.field_hotel_room_purchase_line_warn +#: model:ir.model.fields,field_description:hotel.field_hotel_services_purchase_line_warn +msgid "Purchase Order Line" +msgstr "Línea pedido de compra" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_uom_po_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_uom_po_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_uom_po_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_uom_po_id +msgid "Purchase Unit of Measure" +msgstr "Unidad de medida compra" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_product_uom_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_product_uom_qty +msgid "Quantity" +msgstr "Cantidad" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_qty_available +#: model:ir.model.fields,field_description:hotel.field_hotel_room_qty_available +#: model:ir.model.fields,field_description:hotel.field_hotel_services_qty_available +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_qty_available +msgid "Quantity On Hand" +msgstr "Stock real" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_incoming_qty +#: model:ir.model.fields,help:hotel.field_hotel_room_incoming_qty +#: model:ir.model.fields,help:hotel.field_hotel_services_incoming_qty +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_incoming_qty +msgid "" +"Quantity of products that are planned to arrive.\n" +"In a context with a single Stock Location, this includes goods arriving to this Location, or any of its children.\n" +"In a context with a single Warehouse, this includes goods arriving to the Stock Location of this Warehouse, or any of its children.\n" +"Otherwise, this includes goods arriving to any Stock Location with 'internal' type." +msgstr "" +"Cantidad de los productos que está planificado que llegue.\n" +"En un contexto de una sola ubicación de existencias, esto incluye los bienes almacenados en esta ubicación, o cualquiera de sus hijas.\n" +"En un contexto de un solo almacén, esto incluye los bienes almacenados en la ubicación de existencias de ese almacén, o cualquiera de sus hijas.\n" +"En cualquier otro caso, esto incluye los bienes almacenados en cualquier ubicación de existencias de tipo 'Interna'." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_outgoing_qty +#: model:ir.model.fields,help:hotel.field_hotel_room_outgoing_qty +#: model:ir.model.fields,help:hotel.field_hotel_services_outgoing_qty +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_outgoing_qty +msgid "" +"Quantity of products that are planned to leave.\n" +"In a context with a single Stock Location, this includes goods leaving this Location, or any of its children.\n" +"In a context with a single Warehouse, this includes goods leaving the Stock Location of this Warehouse, or any of its children.\n" +"Otherwise, this includes goods leaving any Stock Location with 'internal' type." +msgstr "" +"Cantidad de los productos que está planificado que salga.\n" +"En un contexto de una sola ubicación de existencias, esto incluye los bienes almacenados en esta ubicación, o cualquiera de sus hijas.\n" +"En un contexto de un solo almacén, esto incluye los bienes almacenados en la ubicación de existencias de ese almacén, o cualquiera de sus hijas.\n" +"En cualquier otro caso, esto incluye los bienes almacenados en cualquier ubicación de existencias de tipo 'Interna'." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_rate +msgid "Rate(per unit)" +msgstr "Ratio(por unidad)" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_kanban +msgid "Rate:" +msgstr "Ratio:" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_expense_policy +#: model:ir.model.fields,field_description:hotel.field_hotel_room_expense_policy +#: model:ir.model.fields,field_description:hotel.field_hotel_services_expense_policy +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_expense_policy +msgid "Re-Invoice Expenses" +msgstr "Gastos de Re-factura" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_reception_count +#: model:ir.model.fields,field_description:hotel.field_hotel_room_reception_count +#: model:ir.model.fields,field_description:hotel.field_hotel_services_reception_count +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_reception_count +msgid "Receipt" +msgstr "Tiquet" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_origin +msgid "Reference of the document that generated this sales order request." +msgstr "Referencia del documento que ha generado esta solicitud de pedido de venta." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_refund_amount +msgid "Refund amount" +msgstr "Cantidad devuelta" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_name +msgid "Reg Number" +msgstr "Numero de Reg." + +#. module: hotel +#: code:addons/hotel/models/hotel_folio.py:254 +#: code:addons/hotel/models/hotel_reservation.py:442 +#: model:ir.ui.view,arch_db:hotel.view_account_payment_folio_form +#, python-format +msgid "Register Payment" +msgstr "Registrar pago" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Rent(UOM)" +msgstr "" +"Alquiler (U.D.M.\n" +")" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_nbr_reordering_rules +#: model:ir.model.fields,field_description:hotel.field_hotel_room_nbr_reordering_rules +#: model:ir.model.fields,field_description:hotel.field_hotel_services_nbr_reordering_rules +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_nbr_reordering_rules +msgid "Reordering Rules" +msgstr "Reglas de reabastecimiento" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_reordering_max_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_room_reordering_max_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_services_reordering_max_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_reordering_max_qty +msgid "Reordering max qty" +msgstr "Cant.máx. reaprovisionamiento" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_reordering_min_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_room_reordering_min_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_services_reordering_min_qty +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_reordering_min_qty +msgid "Reordering min qty" +msgstr "Cant.mín. reaprovisionamiento" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.hotel_reports_menu +msgid "Reports" +msgstr "Informes" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_line_reservation_id +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Reservation" +msgstr "Reserva" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Reservation Detail" +msgstr "Detalle de Reserva" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Reservation Details" +msgstr "Detalles de Reserva" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_reservation_no +msgid "Reservation No" +msgstr "Nº de Reserva" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Reservation Notes" +msgstr "Nota interna de Reserva" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_tree +msgid "Reservation Price" +msgstr "Precio de Reserva" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.menu_open_hotel_reservation_form_tree_all +msgid "Reservation Rooms" +msgstr "Reservas" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Reservation Services" +msgstr "Servicios en la Reserva" + +#. module: hotel +#: code:addons/hotel/models/hotel_reservation.py:730 +#, python-format +msgid "Reservation has no adults" +msgstr "La reserva no tiene adultos" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_cardex_reservation_id +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_reservation_id +msgid "Reservation id" +msgstr "Reserva id" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_reservation_lines +msgid "Reservation lines" +msgstr "Líneas de Reserva" + +#. module: hotel +#: code:addons/hotel/models/hotel_reservation.py:728 +#, python-format +msgid "Reservation persons can't be higher than room capacity" +msgstr "Las personas de la reserva no pueden superiores a la capacidad de la habitación" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.reservation_restriction_action +msgid "Reservation restrictions" +msgstr "Restricciones de Reservas" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.hotel_partner_reservations +#: model:ir.model.fields,field_description:hotel.field_res_partner_reservations_count +#: model:ir.model.fields,field_description:hotel.field_res_users_reservations_count +#: model:ir.ui.view,arch_db:hotel.view_partner_form +msgid "Reservations" +msgstr "Reservas" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_partner_form +msgid "Reservations related with this contact" +msgstr "Reservas Relacionadas con este Contacto" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Reservations to 1 month" +msgstr "Reservas a un mes" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Reservations to 14 days" +msgstr "Reservas a 14 días" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Reservations to 7 days" +msgstr "Reservas a 7 días" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_tree +msgid "Reserved Room Type" +msgstr "Tipo Habitación Reservada" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_ids +#: model:ir.ui.view,arch_db:hotel.reservation_restriction_view_form +msgid "Restriction Items" +msgstr "Restricciones" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_restriction_id +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_restriction_id +msgid "Restriction Plan" +msgstr "Plan de Restricciones" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_name +msgid "Restriction Plan Name" +msgstr "Nombre del Plan de Restricciones" + +#. module: hotel +#: selection:hotel.wizard.massive.changes,section:0 +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings_parity_restrictions_id +#: model:ir.ui.menu,name:hotel.reservation_restriction_menu +#: model:ir.ui.view,arch_db:hotel.reservation_restriction_item_view_form +#: model:ir.ui.view,arch_db:hotel.reservation_restriction_item_view_tree +#: model:ir.ui.view,arch_db:hotel.reservation_restriction_view_form +#: model:ir.ui.view,arch_db:hotel.reservation_restriction_view_tree +#: model:ir.ui.view,arch_db:hotel.virtual_room_availability_view_tree +msgid "Restrictions" +msgstr "Restricciones" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_account_payment_folio_form +msgid "Return" +msgstr "Devolver" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_return_ids +msgid "Return ids" +msgstr "Return ids" + +#. module: hotel +#: code:addons/hotel/models/hotel_folio.py:320 +#, python-format +msgid "Returns" +msgstr "Devoluciones" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_parent_right +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_parent_right +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_parent_right +msgid "Right Parent" +msgstr "Padre derecho" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_ser_room_line +#: model:ir.ui.menu,name:hotel.menu_hotel_room +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_tree +msgid "Room" +msgstr "Habitación" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_room_amenities +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +msgid "Room Amenities" +msgstr "Caratacterísticas de Habitaciones" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Room Discount" +msgstr "Descuento Habitación" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Room Line" +msgstr "Habitaciones Rerservadas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_room_number +msgid "Room Number" +msgstr "Número de Habitación" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.open_hotel_room_type_form_tree +#: model:ir.model,name:hotel.model_hotel_room_type +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_room_type_id +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +msgid "Room Type" +msgstr "Tipo de Habitación" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_room_type_ids +#: model:ir.ui.menu,name:hotel.menu_open_hotel_room_type_form_tree +msgid "Room Types" +msgstr "Tipos de Habitación" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_room_amenities +msgid "Room amenities" +msgstr "Características de Habitaciones" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.menu_hotel_room_category_action +msgid "Room by Type" +msgstr "Habitaciones por Tipo" + +#. module: hotel +#: code:addons/hotel/models/hotel_reservation.py:1125 +#, python-format +msgid "Room line Check In Date Should be less than the Check Out Date!" +msgstr "La fecha de entrada debe ser menor que la fecha de salida!" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_room_lines +msgid "Room lines" +msgstr "Habitaciones Reservadas" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_search +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_tree +msgid "Room rate" +msgstr "Precio Base" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_amount_discount +msgid "Room with Discount" +msgstr "Habitación con Descuento" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_rooms_char +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_room_ids +#: model:ir.ui.menu,name:hotel.menu_open_hotel_room_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_tree +msgid "Rooms" +msgstr "Habitaciones" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.hotel_room_category_action +msgid "Rooms by Category" +msgstr "Habitacione por Categoría" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_route_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_route_id +msgid "Route" +msgstr "Ruta" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_route_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_route_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_route_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_route_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_route_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_route_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_route_ids +msgid "Routes" +msgstr "Rutas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_description_sale +#: model:ir.model.fields,field_description:hotel.field_hotel_room_description_sale +#: model:ir.model.fields,field_description:hotel.field_hotel_services_description_sale +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_description_sale +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Sale Description" +msgstr "Descripción de venta" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_account_invoice_sale_ids +msgid "Sale Orders" +msgstr "Pedido de Venta" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_list_price +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_lst_price +#: model:ir.model.fields,field_description:hotel.field_hotel_room_list_price +#: model:ir.model.fields,field_description:hotel.field_hotel_room_lst_price +#: model:ir.model.fields,field_description:hotel.field_hotel_services_list_price +#: model:ir.model.fields,field_description:hotel.field_hotel_services_lst_price +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_list_price +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_lst_price +msgid "Sale Price" +msgstr "Precio de venta" + +#. module: hotel +#: model:ir.model,name:hotel.model_sale_advance_payment_inv +msgid "Sales Advance Payment Invoice" +msgstr "Ventas. Anticipo pago factura" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_channel_type +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_channel_type +msgid "Sales Channel" +msgstr "Canal de venta" + +#. module: hotel +#: model:ir.model,name:hotel.model_sale_order_line +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_sale_line_warn +#: model:ir.model.fields,field_description:hotel.field_hotel_room_sale_line_warn +#: model:ir.model.fields,field_description:hotel.field_hotel_services_sale_line_warn +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_sale_line_warn +msgid "Sales Order Line" +msgstr "Línea de pedido de venta" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_team_id +msgid "Sales Team" +msgstr "Equipo de ventas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_user_id +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_salesman_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_salesman_id +msgid "Salesperson" +msgstr "Comercial" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_dsa +msgid "Saturday" +msgstr "Sábado" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.checkin_wizard_form_2 +msgid "Save Checkin and Print" +msgstr "Guardar registro e imprimir" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_layout_category_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_layout_category_id +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_section +msgid "Section" +msgstr "Sección" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_checkin_wizard_segmentation_id +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_segmentation_id +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_segmentation_id +msgid "Segmentation" +msgstr "Segmentación" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Segmentation..." +msgstr "Segmentación..." + +#. module: hotel +#: selection:checkin.wizard,op_select_partner:0 +msgid "Select a partner for checkin" +msgstr "Selecciona un contacto para el checkin" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_categ_id +#: model:ir.model.fields,help:hotel.field_hotel_room_categ_id +#: model:ir.model.fields,help:hotel.field_hotel_services_categ_id +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_categ_id +msgid "Select category for the current product" +msgstr "Seleccione la categoría para el producto actual." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_purchase_line_warn +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_sale_line_warn +#: model:ir.model.fields,help:hotel.field_hotel_room_purchase_line_warn +#: model:ir.model.fields,help:hotel.field_hotel_room_sale_line_warn +#: model:ir.model.fields,help:hotel.field_hotel_services_purchase_line_warn +#: model:ir.model.fields,help:hotel.field_hotel_services_sale_line_warn +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_sale_line_warn +msgid "Selecting the \"Warning\" option will notify user with the message, Selecting \"Blocking Message\" will throw an exception with the message and block the flow. The Message has to be written in the next field." +msgstr "Si selecciona la opción \"Aviso\" se notificará a los usuarios con el mensaje, si selecciona \"Mensaje de bloqueo\" se lanzará una excepción con el mensaje y se bloqueará el flujo. El mensaje debe escribirse en el siguiente campo." + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Send Cancel Email" +msgstr "Enviar Mail de Cancelación" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Send Confirmation Email" +msgstr "Enviar Mail de Confirmación" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Send Exit Email" +msgstr "Enviar Mail de Salida" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_floor_sequence +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_sequence +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_sequence +#: model:ir.model.fields,field_description:hotel.field_hotel_room_sequence +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_sequence +#: model:ir.model.fields,field_description:hotel.field_hotel_services_sequence +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_sequence +msgid "Sequence" +msgstr "Secuencia" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Service" +msgstr "Servicio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_service_line_id +#: model:ir.ui.view,arch_db:hotel.view_hotel_service_line_form +msgid "Service Line" +msgstr "Línea de Servicio" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Service Lines" +msgstr "Líneas de Servicios" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_service_type_form +msgid "Service Name" +msgstr "Nombre de Servicio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_tax +msgid "Service Tax" +msgstr "Impuesto de Servicio" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.open_hotel_service_type_form_tree +#: model:ir.model,name:hotel.model_hotel_service_type +#: model:ir.ui.view,arch_db:hotel.view_hotel_service_type_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_service_type_tree +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Service Type" +msgstr "Tipo de Servicio" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.menu_open_hotel_service_type_form_tree +msgid "Service Types" +msgstr "Tipos de Servicio" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Service and Days" +msgstr "Servicios y Días" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_service_line_ids +msgid "Service line ids" +msgstr "ID de línea de servicio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_service_lines +msgid "Service lines" +msgstr "Líneas de Servicio" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_search +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_tree +msgid "Service rate" +msgstr "Tasa de servicio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_services_service_id +msgid "Service_id" +msgstr "Service_id" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.menu_hotel_service +#: model:ir.ui.menu,name:hotel.menu_open_hotel_services_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Services" +msgstr "Servicios" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_amount_reservation_services +msgid "Services Amount" +msgstr "Importe Servicios" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.hotel_service_category_action +msgid "Services by Category" +msgstr "Servicios por Categoría" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.menu_hotel_service_category_action +msgid "Services by Type" +msgstr "Servicios por Tipo" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_type_removal_strategy_id +#: model:ir.model.fields,help:hotel.field_hotel_room_type_removal_strategy_id +#: model:ir.model.fields,help:hotel.field_hotel_service_type_removal_strategy_id +msgid "Set a specific removal strategy that will be used regardless of the source location for this product category" +msgstr "Establezca una estrategia de retirada específica que se usará independientemente de la ubicación origen para esta categoría de producto" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Set to Done" +msgstr "Hacer Checkout" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Set to Draft" +msgstr "Cambiar a borrador" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.hotel_settings_menu +msgid "Settings" +msgstr "Configuración" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_shared_room +msgid "Shared Room" +msgstr "Habitación Compartida" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_shared_folio +msgid "Shared folio" +msgstr "Ficha compartida" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_picking_policy +msgid "Shipping Policy" +msgstr "Política de entrega" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Show all reservations for which date enter is before than 14 days" +msgstr "Mostrar todas las reservas que entran en menos de 14 días" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Show all reservations for which date enter is before than 7 days" +msgstr "Mostrar todas las reservas que entran en menos de 7 días" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Show all reservations for which date enter is before than aprox. 1 month" +msgstr "Mostrar todas las reservas que entran en menos de aprox. un mes" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_image_small +#: model:ir.model.fields,field_description:hotel.field_hotel_room_image_small +#: model:ir.model.fields,field_description:hotel.field_hotel_services_image_small +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_image_small +msgid "Small-sized image" +msgstr "Imagen de tamaño pequeño" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_origin +msgid "Source Document" +msgstr "Documento origen" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_sale_ok +#: model:ir.model.fields,help:hotel.field_hotel_room_sale_ok +#: model:ir.model.fields,help:hotel.field_hotel_services_sale_ok +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_sale_ok +msgid "Specify if the product can be selected in a sales order line." +msgstr "Especifique si un producto puede ser seleccionado en un pedido de venta." + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_split_reservation_wizard +msgid "Split" +msgstr "Dividir" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.action_hotel_split_reservation +#: model:ir.ui.view,arch_db:hotel.view_hotel_split_reservation_wizard +msgid "Split Reservation" +msgstr "Dividir Reserva" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_splitted +msgid "Splitted" +msgstr "Dividida" + +#. module: hotel +#: selection:hotel.folio,reservation_type:0 +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Staff" +msgstr "Staff" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_property_cost_method +#: model:ir.model.fields,help:hotel.field_hotel_room_property_cost_method +#: model:ir.model.fields,help:hotel.field_hotel_services_property_cost_method +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_property_cost_method +msgid "" +"Standard Price: The cost price is manually updated at the end of a specific period (usually once a year).\n" +" Average Price: The cost price is recomputed at each incoming shipment and used for the product valuation.\n" +" Real Price: The cost price displayed is the price of the last outgoing product (will be use in case of inventory loss for example)." +msgstr "" +"Precio estándar: El precio de coste se actualiza manualmente al final de un período específico (generalmente una vez al año).\n" +" Precio medio: El precio de coste se recalcula con cada envío entrante y se utiliza para la valoración del producto.\n" +" Precio Real: El precio de coste es el precio del último producto saliente (se utilizará en caso de pérdida de inventario, por ejemplo)." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_type_property_cost_method +#: model:ir.model.fields,help:hotel.field_hotel_room_type_property_cost_method +#: model:ir.model.fields,help:hotel.field_hotel_service_type_property_cost_method +msgid "" +"Standard Price: The cost price is manually updated at the end of a specific period (usually once a year).\n" +"Average Price: The cost price is recomputed at each incoming shipment and used for the product valuation.\n" +"Real Price: The cost price displayed is the price of the last outgoing product (will be used in case of inventory loss for example)." +msgstr "" +"Precio estándar: El precio de coste se actualiza manualmente al final de un período específico (generalmente una vez al año).\n" +" Precio medio: El precio de coste se recalcula con cada envío entrante y se utiliza para la valoración del producto.\n" +" Precio Real: El precio de coste es el precio del último producto saliente (se utilizará en caso de pérdida de inventario, por ejemplo)." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_folio_report_wizard_date_start +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_date_start +msgid "Start Date" +msgstr "Fecha de inicio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_state +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_state +msgid "State" +msgstr "Estado" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_service_line_form +msgid "States" +msgstr "Estados" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_state +msgid "Status" +msgstr "Estado" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "Still to be paid" +msgstr "Pendiente de Pago" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_property_stock_account_input +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_property_stock_account_input_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_property_stock_account_input +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_property_stock_account_input_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_property_stock_account_input_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_property_stock_account_input +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_property_stock_account_input +msgid "Stock Input Account" +msgstr "Cuenta de entrada de stock" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_property_stock_journal +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_property_stock_journal +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_property_stock_journal +msgid "Stock Journal" +msgstr "Diario de Stock" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_property_stock_account_output +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_property_stock_account_output_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_property_stock_account_output +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_property_stock_account_output_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_property_stock_account_output_categ_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_property_stock_account_output +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_property_stock_account_output +msgid "Stock Output Account" +msgstr "Cuenta de salida de existencias" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_property_stock_valuation_account_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_property_stock_valuation_account_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_property_stock_valuation_account_id +msgid "Stock Valuation Account" +msgstr "Cuenta de valoración de existencias" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_stock_move_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_stock_move_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_stock_move_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_stock_move_ids +msgid "Stock move ids" +msgstr " IDs movimientos de stock" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_stock_quant_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_stock_quant_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_stock_quant_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_stock_quant_ids +msgid "Stock quant ids" +msgstr "IDs stock quant" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_out_amount +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_price_subtotal +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_price_subtotal +msgid "Subtotal" +msgstr "Subtotal" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_dsu +msgid "Sunday" +msgstr "Domingo" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Suplliers" +msgstr "Proveedores" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_services_form +msgid "Supplier Taxes" +msgstr "Impuestos a proveedores" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_form +msgid "Suppliers" +msgstr "Proveedores" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio_search +msgid "Tables Detail" +msgstr "Detalle de tablas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_amount_tax +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_price_tax +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_tax_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_price_tax +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_tax_id +msgid "Taxes" +msgstr "Impuestos" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_folio_advance_payment_inv_deposit_taxes_id +msgid "Taxes used for deposits" +msgstr "Impuestos usados para depósitos" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_pricelist_id +#: model:ir.model.fields,help:hotel.field_hotel_room_pricelist_id +#: model:ir.model.fields,help:hotel.field_hotel_services_pricelist_id +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_pricelist_id +msgid "Technical field. Used for searching on pricelists, not stored in database." +msgstr "Campo técnico. Se utiliza para buscar en tarifas, no almacenadas en la base de datos." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_stock_move_ids +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_stock_quant_ids +#: model:ir.model.fields,help:hotel.field_hotel_room_stock_move_ids +#: model:ir.model.fields,help:hotel.field_hotel_room_stock_quant_ids +#: model:ir.model.fields,help:hotel.field_hotel_services_stock_move_ids +#: model:ir.model.fields,help:hotel.field_hotel_services_stock_quant_ids +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_stock_move_ids +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_stock_quant_ids +msgid "Technical: used to compute quantities." +msgstr "Técnico: se utiliza para calcular las cantidades." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_note +msgid "Terms and conditions" +msgstr "Términos y condiciones" + +#. module: hotel +#: code:addons/hotel/models/virtual_room.py:74 +#, python-format +msgid "The Maxime rooms allowed can not be greate than total rooms count" +msgstr "Las habitaciones maximas permitidas no pueden ser mayores que el total de habitaciones" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_active +msgid "The active field allows you to hide the category without removing it." +msgstr "El campo activo le permite ocultar la categoría sin tener que eliminarla." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_folio_advance_payment_inv_amount +msgid "The amount to be invoiced in advance, taxes excluded." +msgstr "El importe a facturar por adelantado, impuestos excluidos." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_project_id +#: model:ir.model.fields,help:hotel.field_hotel_folio_related_project_id +msgid "The analytic account related to a sales order." +msgstr "La cuenta analítica relacionada con un pedido de venta." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_sale_delay +#: model:ir.model.fields,help:hotel.field_hotel_room_sale_delay +#: model:ir.model.fields,help:hotel.field_hotel_services_sale_delay +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_sale_delay +msgid "The average delay in days between the confirmation of the customer order and the delivery of the finished products. It's the time you promise to your customers." +msgstr "El retraso medio en días entre la confirmación del pedido de cliente y la entrega de los productos finales. Es el tiempo que promete a sus clientes." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_config_settings_tz_hotel +msgid "The hotel's timezone, used to manage date and time values in reservations It is important to set a value for this field." +msgstr "La zona horaria del hotel, utilizada para administrar los valores de fecha y hora en las reservas. Es importante establecer un valor para este campo." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_type_product_count +#: model:ir.model.fields,help:hotel.field_hotel_room_type_product_count +#: model:ir.model.fields,help:hotel.field_hotel_service_type_product_count +msgid "The number of products under this category (Does not consider the children categories)" +msgstr "El número de productos bajo esta categoría (No considera las categorías de hijas)" + +#. module: hotel +#: code:addons/hotel/wizard/folio_make_invoice_advance.py:154 +#, python-format +msgid "The product used to invoice a down payment should be of type 'Service'. Please use another product or update this product." +msgstr "The product used to invoice a down payment should be of type 'Service'. Please use another product or update this product." + +#. module: hotel +#: code:addons/hotel/wizard/folio_make_invoice_advance.py:152 +#, python-format +msgid "The product used to invoice a down payment should have an invoice policy set to \"Ordered quantities\". Please update your deposit product to be able to create a deposit invoice." +msgstr "The product used to invoice a down payment should have an invoice policy set to \"Ordered quantities\". Please update your deposit product to be able to create a deposit invoice." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_lst_price +#: model:ir.model.fields,help:hotel.field_hotel_room_lst_price +#: model:ir.model.fields,help:hotel.field_hotel_services_lst_price +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_lst_price +msgid "The sale price is managed from the product template. Click on the 'Variant Prices' button to set the extra attribute prices." +msgstr "El precio de venta se gestiona desde la plantilla del producto. Haga clic en el botón 'Precios variantes' para establecer los precios adicionales de los atributos." + +#. module: hotel +#: code:addons/hotel/wizard/folio_make_invoice_advance.py:80 +#, python-format +msgid "The value of the down payment amount must be positive." +msgstr "The value of the down payment amount must be positive." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_volume +#: model:ir.model.fields,help:hotel.field_hotel_room_volume +#: model:ir.model.fields,help:hotel.field_hotel_services_volume +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_volume +msgid "The volume in m3." +msgstr "El volumen en m3." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_weight +#: model:ir.model.fields,help:hotel.field_hotel_room_weight +#: model:ir.model.fields,help:hotel.field_hotel_services_weight +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_weight +msgid "The weight of the contents in Kg, not including any packaging, etc." +msgstr "El peso del contenido en Kg, sin incluir empaquetado, etc..." + +#. module: hotel +#: code:addons/hotel/wizard/folio_make_invoice_advance.py:76 +#, python-format +msgid "There is no income account defined for this product: \"%s\". You may have to install a chart of account from Accounting app, settings menu." +msgstr "There is no income account defined for this product: \"%s\". You may have to install a chart of account from Accounting app, settings menu." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_property_account_expense_id +#: model:ir.model.fields,help:hotel.field_hotel_room_property_account_expense_id +#: model:ir.model.fields,help:hotel.field_hotel_services_property_account_expense_id +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_property_account_expense_id +msgid "This account will be used for invoices instead of the default one to value expenses for the current product." +msgstr "Esta cuenta será usada para facturas en vez de la cuenta por defecto para valorar los gastos del producto vigente" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_property_account_income_id +#: model:ir.model.fields,help:hotel.field_hotel_room_property_account_income_id +#: model:ir.model.fields,help:hotel.field_hotel_services_property_account_income_id +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_property_account_income_id +msgid "This account will be used for invoices instead of the default one to value sales for the current product." +msgstr "Esta cuenta se utilizará en facturas, en lugar de la cuenta por defecto, para valorar los ingresos de este producto." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_type_property_account_expense_categ_id +#: model:ir.model.fields,help:hotel.field_hotel_room_type_property_account_expense_categ_id +#: model:ir.model.fields,help:hotel.field_hotel_service_type_property_account_expense_categ_id +msgid "This account will be used for invoices to value expenses." +msgstr "Esta cuenta se utilizará en facturas para valorar gastos." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_type_property_account_income_categ_id +#: model:ir.model.fields,help:hotel.field_hotel_room_type_property_account_income_categ_id +#: model:ir.model.fields,help:hotel.field_hotel_service_type_property_account_income_categ_id +msgid "This account will be used for invoices to value sales." +msgstr "Esta cuenta se utilizará en facturas para valorar ingresos." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_type_property_account_creditor_price_difference_categ +#: model:ir.model.fields,help:hotel.field_hotel_room_type_property_account_creditor_price_difference_categ +#: model:ir.model.fields,help:hotel.field_hotel_service_type_property_account_creditor_price_difference_categ +msgid "This account will be used to value price difference between purchase price and accounting cost." +msgstr "Esta cuenta se utilizará para valorar la diferencia de precios entre el precio de compra y precio contabilizado." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_property_account_creditor_price_difference +#: model:ir.model.fields,help:hotel.field_hotel_room_property_account_creditor_price_difference +#: model:ir.model.fields,help:hotel.field_hotel_services_property_account_creditor_price_difference +msgid "This account will be used to value price difference between purchase price and cost price." +msgstr "This account will be used to value price difference between purchase price and cost price." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_folio_image +msgid "This field holds the image used as avatar for this contact, limited to 1024x1024px" +msgstr "Este campo contiene la imagen utilizada como avatar para este contacto, limitada a 1024x1024 px" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_image_variant +#: model:ir.model.fields,help:hotel.field_hotel_room_image_variant +#: model:ir.model.fields,help:hotel.field_hotel_services_image_variant +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_image_variant +msgid "This field holds the image used as image for the product variant, limited to 1024x1024px." +msgstr "Este campo contiene la imagen usada como imagen de la variante del producto, limitada a 1024x1024px." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_account_invoice_sale_ids +msgid "This is the list of sale orders related to this invoice." +msgstr "Esta es la lista de pedidos de venta relacionados con esta factura." + +#. module: hotel +#: code:addons/hotel/models/hotel_reservation.py:583 +#, python-format +msgid "This is the parent reservation" +msgstr "Esta es la reserva padre" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_price_extra +#: model:ir.model.fields,help:hotel.field_hotel_room_price_extra +#: model:ir.model.fields,help:hotel.field_hotel_services_price_extra +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_price_extra +msgid "This is the sum of the extra price of all attributes" +msgstr "Ésta es la suma de los precios extra de todos los atributos" + +#. module: hotel +#: code:addons/hotel/models/inherit_account_payment.py:107 +#, python-format +msgid "This pay is related with more than one Reservation." +msgstr "Este pago está relacionado con más de una reserva." + +#. module: hotel +#: code:addons/hotel/models/hotel_reservation.py:610 +#, python-format +msgid "This reservation can't be unified" +msgstr "Esta reserva no se puede unificar" + +#. module: hotel +#: code:addons/hotel/models/hotel_reservation.py:627 +#, python-format +msgid "This reservation can't be unified: They all need to be in the same room" +msgstr "Esta reserva no se puede unificar: todos deben estar en la misma habitación" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "This reservation has other reservantions and/or services in the folio, you can check it in the" +msgstr "Esta reserva está en una ficha junto otras reservas y/o servicios, puedes comprobarlo en el" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "This reservation is part of splitted reservation!, you can check it in the" +msgstr "Esta reserva es parte de una reserva partida!, puedes revisarlo en el" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_property_stock_production +#: model:ir.model.fields,help:hotel.field_hotel_room_property_stock_production +#: model:ir.model.fields,help:hotel.field_hotel_services_property_stock_production +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_property_stock_production +msgid "This stock location will be used, instead of the default one, as the source location for stock moves generated by manufacturing orders." +msgstr "Se usará esta ubicación de existencias, en lugar de la de por defecto, como la ubicación origen para los movimientos de existencias generados por las órdenes de fabricación." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_property_stock_procurement +#: model:ir.model.fields,help:hotel.field_hotel_room_property_stock_procurement +#: model:ir.model.fields,help:hotel.field_hotel_services_property_stock_procurement +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_property_stock_procurement +msgid "This stock location will be used, instead of the default one, as the source location for stock moves generated by procurements." +msgstr "Se usará esta ubicación de existencias, en lugar de la de por defecto, como la ubicación origen para los movimientos de existencias generados por los abastecimientos." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_property_stock_inventory +#: model:ir.model.fields,help:hotel.field_hotel_room_property_stock_inventory +#: model:ir.model.fields,help:hotel.field_hotel_services_property_stock_inventory +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_property_stock_inventory +msgid "This stock location will be used, instead of the default one, as the source location for stock moves generated when you do an inventory." +msgstr "Se usará esta ubicación de existencias, en lugar de la de por defecto, como la ubicación origen para los movimientos de existencias generados cuando se realizan inventarios." + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_dth +msgid "Thursday" +msgstr "Jueves" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_config_settings_tz_hotel +msgid "Timezone" +msgstr "Zona horaria" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_date_end +msgid "To" +msgstr "Para" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_to_assign +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "To Assign" +msgstr "Por Asignar" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_ser_checkout +msgid "To Date" +msgstr "Hasta la fecha" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_qty_to_invoice +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_qty_to_invoice +msgid "To Invoice" +msgstr "A facturar" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_to_be_cleaned +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +msgid "To be Cleaned" +msgstr "Para ser limpiada" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_search +msgid "To enter" +msgstr "Por entrar" + +#. module: hotel +#: code:addons/hotel/models/hotel_dashboard.py:78 +#, python-format +msgid "Today" +msgstr "Hoy" + +#. module: hotel +#: code:addons/hotel/wizard/duplicate_reservation.py:75 +#, python-format +msgid "Too much duplicated reservations! There are no '%d' free rooms" +msgstr "¡Demasiadas reservas duplicadas! No hay habitaciones libres '%d'" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_amount_total +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_amount_reservation +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_price_total +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_price_total +#: model:ir.ui.view,arch_db:hotel.view_currency_exchange_tree +msgid "Total" +msgstr "Total" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_currency_exchange_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Total Amount" +msgstr "Total" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.report_hotel_folio +msgid "Total Collection" +msgstr "Colección total" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_tree +msgid "Total amount" +msgstr "Importe total" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_account_payment_amount_total_folio +msgid "Total amount in folio" +msgstr "Monto total en ficha de reserva" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_total_rooms_count +msgid "Total rooms count" +msgstr "Total Habitaciones" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_total_route_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_total_route_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_total_route_ids +msgid "Total routes" +msgstr "Todas las rutas aplicadas" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_track_service +#: model:ir.model.fields,field_description:hotel.field_hotel_room_track_service +#: model:ir.model.fields,field_description:hotel.field_hotel_services_track_service +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_track_service +msgid "Track Service" +msgstr "Seguimiento del Servicio" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_tracking +#: model:ir.model.fields,field_description:hotel.field_hotel_room_tracking +#: model:ir.model.fields,field_description:hotel.field_hotel_services_tracking +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_tracking +msgid "Tracking" +msgstr "Seguimiento" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_dtu +msgid "Tuesday" +msgstr "Martes" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_amenities_list +msgid "Ty rate" +msgstr "Ty rate" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_currency_exchange_type +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_reservation_type +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_reservation_type +msgid "Type" +msgstr "Tipo" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_floor +#: model:ir.model.fields,field_description:hotel.field_hotel_room_floor_id +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_form +msgid "Ubication" +msgstr "Ubicación" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_floor_name +msgid "Ubication Name" +msgstr "Nombre Ubicación" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.menu_open_hotel_floor_form_tree +msgid "Ubitacions" +msgstr "Ubicaciones" + +#. module: hotel +#: code:addons/hotel/wizard/duplicate_reservation.py:101 +#, python-format +msgid "Unexpected Error: Can't found a free room" +msgstr "Error inesperado: no se puede encontrar una habitación libre" + +#. module: hotel +#: code:addons/hotel/wizard/split_reservation.py:91 +#, python-format +msgid "Unexpected error copying record. Can't split reservation!" +msgstr "Error inesperado en la copia . No se puede dividir la reserva!" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "Unify" +msgstr "Unir" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_price_unit +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_price_unit +msgid "Unit Price" +msgstr "Precio unitario" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_product_uom +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_uom_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_uom_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_line_product_uom +#: model:ir.model.fields,field_description:hotel.field_hotel_services_uom_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_uom_id +msgid "Unit of Measure" +msgstr "Unidad de medida" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_message_unread +#: model:ir.model.fields,field_description:hotel.field_hotel_room_message_unread +#: model:ir.model.fields,field_description:hotel.field_hotel_services_message_unread +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_message_unread +msgid "Unread Messages" +msgstr "Unread Messages" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_message_unread_counter +#: model:ir.model.fields,field_description:hotel.field_hotel_room_message_unread_counter +#: model:ir.model.fields,field_description:hotel.field_hotel_services_message_unread_counter +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_message_unread_counter +msgid "Unread Messages Counter" +msgstr "Unread Messages Counter" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_amount_untaxed +msgid "Untaxed Amount" +msgstr "Base imponible" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +msgid "Untaxed amount" +msgstr "cantidad que no ha tributado" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_tree +msgid "Updated on" +msgstr "Actualizado el" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_account_payment_folio_form +msgid "Validate" +msgstr "Validar" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_valuation +#: model:ir.model.fields,field_description:hotel.field_hotel_room_valuation +#: model:ir.model.fields,field_description:hotel.field_hotel_services_valuation +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_valuation +msgid "Valuation" +msgstr "Valoración" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_image_variant +#: model:ir.model.fields,field_description:hotel.field_hotel_room_image_variant +#: model:ir.model.fields,field_description:hotel.field_hotel_services_image_variant +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_image_variant +msgid "Variant Image" +msgstr "Imagen de la variante" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_price_extra +#: model:ir.model.fields,field_description:hotel.field_hotel_room_price_extra +#: model:ir.model.fields,field_description:hotel.field_hotel_services_price_extra +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_price_extra +msgid "Variant Price Extra" +msgstr "Precio adicional de la variante " + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_supplier_taxes_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_supplier_taxes_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_supplier_taxes_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_supplier_taxes_id +msgid "Vendor Taxes" +msgstr "Impuestos de proveedor" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_seller_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_room_seller_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_services_seller_ids +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_seller_ids +msgid "Vendors" +msgstr "Proveedores" + +#. module: hotel +#: selection:hotel.room,sale_price_type:0 +#: selection:hotel.virtual.room.restriction.item,applied_on:0 +#: selection:hotel.wizard.massive.changes,applied_on:0 +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_availability_virtual_room_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_restriction_item_virtual_room_id +#: model:ir.ui.view,arch_db:hotel.virtual_room_view_form +msgid "Virtual Room" +msgstr "Habitación Virtual" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.virtual_room_availability_action +msgid "Virtual Room Availability" +msgstr "Disponibilidad Habitaciones Virtuales" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_reservation_virtual_room_id +msgid "Virtual Room Type" +msgstr "Tipos de Habitaciones Virtuales" + +#. module: hotel +#: model:ir.actions.act_window,name:hotel.virtual_room_action_form +#: model:ir.model.fields,field_description:hotel.field_hotel_room_virtual_rooms +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_virtual_room_ids +#: model:ir.ui.view,arch_db:hotel.virtual_room_view_tree +msgid "Virtual Rooms" +msgstr "Habitaciones Virtuales" + +#. module: hotel +#: model:ir.ui.menu,name:hotel.virtual_room_menu +msgid "Virtual rooms" +msgstr "Habitaciones Virtuales" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_volume +#: model:ir.model.fields,field_description:hotel.field_hotel_room_volume +#: model:ir.model.fields,field_description:hotel.field_hotel_services_volume +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_volume +msgid "Volume" +msgstr "Volumen" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_warehouse_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_warehouse_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_warehouse_id +#: model:ir.model.fields,field_description:hotel.field_hotel_services_warehouse_id +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_warehouse_id +msgid "Warehouse" +msgstr "Almacén" + +#. module: hotel +#: code:addons/hotel/models/currency_exchange.py:152 +#: code:addons/hotel/models/hotel_folio.py:400 +#: code:addons/hotel/models/inherit_account_payment.py:107 +#, python-format +msgid "Warning" +msgstr "Aviso" + +#. module: hotel +#: code:addons/hotel/models/hotel_folio.py:488 +#, python-format +msgid "Warning for %s" +msgstr "Aviso par %s" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_warranty +#: model:ir.model.fields,field_description:hotel.field_hotel_room_warranty +#: model:ir.model.fields,field_description:hotel.field_hotel_services_warranty +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_warranty +msgid "Warranty" +msgstr "Garantía" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.report_currency_exchange +msgid "We hereby certify that we have purchased today foreign currency from Mr./Mrs." +msgstr "Por la presente certificamos que hemos comprado la moneda extranjera actual de Mr./Mrs." + +#. module: hotel +#: code:addons/hotel/models/inherit_account_invoice.py:86 +#, python-format +msgid "We need the VAT of the following companies" +msgstr "Necesitamos el NIF de los siguientes Clientes:" + +#. module: hotel +#: selection:hotel.folio,channel_type:0 +msgid "Web" +msgstr "Web" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_wizard_massive_changes_dwe +msgid "Wednesday" +msgstr "Miércoles" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_weight +#: model:ir.model.fields,field_description:hotel.field_hotel_room_weight +#: model:ir.model.fields,field_description:hotel.field_hotel_services_weight +#: model:ir.model.fields,field_description:hotel.field_hotel_virtual_room_weight +msgid "Weight" +msgstr "Peso" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_folio_advance_payment_inv_advance_payment_method +msgid "What do you want to invoice?" +msgstr "What do you want to invoice?" + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_type_property_stock_account_input_categ_id +#: model:ir.model.fields,help:hotel.field_hotel_room_type_property_stock_account_input_categ_id +#: model:ir.model.fields,help:hotel.field_hotel_service_type_property_stock_account_input_categ_id +msgid "When doing real-time inventory valuation, counterpart journal items for all incoming stock moves will be posted in this account, unless there is a specific valuation account set on the source location. This is the default value for all products in this category. It can also directly be set on each product" +msgstr "Cuando se realiza una valoración de inventario en tiempo real, la contrapartida para todos los movimientos de entrada serán imputados en esta cuenta, a menos que se haya establecido una cuenta de valoración específica en la ubicación fuente. Éste es el valor por defecto para todos los productos en esta categoría. También se puede establecer directamente en cada producto." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_property_stock_account_input +#: model:ir.model.fields,help:hotel.field_hotel_room_property_stock_account_input +#: model:ir.model.fields,help:hotel.field_hotel_services_property_stock_account_input +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_property_stock_account_input +msgid "When doing real-time inventory valuation, counterpart journal items for all incoming stock moves will be posted in this account, unless there is a specific valuation account set on the source location. When not set on the product, the one from the product category is used." +msgstr "Cuando se realiza una valoración de inventario en tiempo real, la contrapartida para todos los movimientos de entrada serán imputados en esta cuenta, a menos que se haya establecido una cuenta de valoración específica en la ubicación fuente. Cuando no se establece en el producto, se usa la establecida en la categoría." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_type_property_stock_account_output_categ_id +#: model:ir.model.fields,help:hotel.field_hotel_room_type_property_stock_account_output_categ_id +#: model:ir.model.fields,help:hotel.field_hotel_service_type_property_stock_account_output_categ_id +msgid "When doing real-time inventory valuation, counterpart journal items for all outgoing stock moves will be posted in this account, unless there is a specific valuation account set on the destination location. This is the default value for all products in this category. It can also directly be set on each product" +msgstr "Cuando se realiza una valoración de inventario en tiempo real, la contrapartida para todos los movimientos de salida serán imputados en esta cuenta, a menos que se haya establecido una cuenta de valoración específica en la ubicación destino. Éste es el valor por defecto para todos los productos en esta categoría. También se puede establecer directamente en cada producto." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_property_stock_account_output +#: model:ir.model.fields,help:hotel.field_hotel_room_property_stock_account_output +#: model:ir.model.fields,help:hotel.field_hotel_services_property_stock_account_output +#: model:ir.model.fields,help:hotel.field_hotel_virtual_room_property_stock_account_output +msgid "When doing real-time inventory valuation, counterpart journal items for all outgoing stock moves will be posted in this account, unless there is a specific valuation account set on the destination location. When not set on the product, the one from the product category is used." +msgstr "Cuando se realiza una valoración de inventario en tiempo real, la contrapartida para todos los movimientos de salida serán imputados en esta cuenta, a menos que se haya establecido una cuenta de valoración específica en la ubicación destino. Cuando no se establece en el producto, se usa la establecida en la categoría." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_type_property_stock_journal +#: model:ir.model.fields,help:hotel.field_hotel_room_type_property_stock_journal +#: model:ir.model.fields,help:hotel.field_hotel_service_type_property_stock_journal +msgid "When doing real-time inventory valuation, this is the Accounting Journal in which entries will be automatically posted when stock moves are processed." +msgstr "Al hacer la valoración de inventario en tiempo real, éste es el diario contable donde los asientos se crearán automáticamente cuando los movimientos de existencias se procesen." + +#. module: hotel +#: model:ir.model.fields,help:hotel.field_hotel_room_amenities_type_property_stock_valuation_account_id +#: model:ir.model.fields,help:hotel.field_hotel_room_type_property_stock_valuation_account_id +#: model:ir.model.fields,help:hotel.field_hotel_service_type_property_stock_valuation_account_id +msgid "When real-time inventory valuation is enabled on a product, this account will hold the current value of the products." +msgstr "Cuando está activada una valoración de inventario en tiempo real de un producto, esta cuenta contiene el valor actual de los productos." + +#. module: hotel +#: model:ir.ui.menu,name:hotel.menu_account_finance_xls_reports +msgid "XLS Reports" +msgstr "XLS Reports" + +#. module: hotel +#: code:addons/hotel/models/virtual_room.py:65 +#, python-format +msgid "You can not enter the same room in duplicate (check the room types) %s" +msgstr "No puede ingresar a la misma habitación por duplicado (verifique los tipos de habitación) %s" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.invoice_form +msgid "" +"You have payments on the related folio associated with other customers than the current one on the invoice.\n" +" Make sure to" +msgstr "" +"Tienes pagos en la ficha asociados a un cliente diferente del de la factura.\n" +" Asegúrate de" + +#. module: hotel +#: code:addons/hotel/models/hotel_reservation.py:1039 +#, python-format +msgid "You tried to change reservation with room those already reserved in this reservation period" +msgstr "Estás intentando guardar una reserva con una habitación que ya está ocupada en esas fechas" + +#. module: hotel +#: code:addons/hotel/models/hotel_reservation.py:1136 +#, python-format +msgid "You tried to change/confirm reservation with room those already reserved in this reservation period: %s " +msgstr "You tried to change/confirm reservation with room those already reserved in this reservation period: %s " + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_room_amenities_type +msgid "amenities Type" +msgstr "tipo de servicios" + +#. module: hotel +#: code:addons/hotel/models/hotel_virtual_room_availability.py:63 +#, python-format +msgid "can't assign the same date to more than one virtual room" +msgstr "no puede asignar la misma fecha a más de una habitación virtual" + +#. module: hotel +#: model:ir.model,name:hotel.model_cardex +msgid "cardex" +msgstr "checkin" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_room_amenities_type_cat_id +#: model:ir.model.fields,field_description:hotel.field_hotel_room_type_cat_id +#: model:ir.model.fields,field_description:hotel.field_hotel_service_type_ser_id +msgid "category" +msgstr "categoria" + +#. module: hotel +#: model:ir.model,name:hotel.model_checkin_wizard +msgid "checkin.wizard" +msgstr "checkin.wizard" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_checkins_reservations +msgid "checkins reservations" +msgstr "checkins reservations" + +#. module: hotel +#: model:ir.model.fields,field_description:hotel.field_hotel_folio_checkouts_reservations +msgid "checkouts reservations" +msgstr "checkouts reservations" + +#. module: hotel +#: sql_constraint:hotel.room.type:0 +msgid "code must be unique!" +msgstr "el código debe ser único!" + +#. module: hotel +#: model:ir.model,name:hotel.model_currency_exchange +msgid "currency" +msgstr "moneda" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.report_currency_exchange +msgid "" +"currency .\n" +" Details are given below:" +msgstr "" +"moneda.\n" +" Los detalles se dan a continuación:" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.report_currency_exchange +msgid "currency and paid net amount in" +msgstr "moneda y monto neto pagado" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_currency_exchange_form +msgid "do_draft" +msgstr "do_draft" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "email" +msgstr "email" + +#. module: hotel +#: model:ir.model,name:hotel.model_folio_report_wizard +msgid "folio.report.wizard" +msgstr "ficha.report.wizard" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.invoice_form +msgid "from the folio if necessary before paying this invoice" +msgstr "de la ficha si es necesario antes de pagar esta factura" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_service_line +msgid "hotel Service line" +msgstr "Línea de servicio del hotel" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_folio +msgid "hotel folio new" +msgstr "nueva ficha de reserva" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_reservation +msgid "hotel reservation" +msgstr "Reserva" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_config_settings +msgid "hotel.config.settings" +msgstr "hotel.config.settings" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_dashboard +msgid "hotel.dashboard" +msgstr "hotel.dashboard" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_reservation_line +msgid "hotel.reservation.line" +msgstr "hotel.reservation.line" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_virtual_room +msgid "hotel.virtual.room" +msgstr "hotel.virtual.room" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_virtual_room_availability +msgid "hotel.virtual.room.availability" +msgstr "hotel.virtual.room.availability" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_virtual_room_availabity +msgid "hotel.virtual.room.availabity" +msgstr "hotel.virtual.room.availabity" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_virtual_room_restriction +msgid "hotel.virtual.room.restriction" +msgstr "hotel.virtual.room.restriction" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_virtual_room_restriction_item +msgid "hotel.virtual.room.restriction.item" +msgstr "hotel.virtual.room.restriction.item" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_wizard_duplicate_reservation +msgid "hotel.wizard.duplicate.reservation" +msgstr "hotel.wizard.duplicate.reservation" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_wizard_massive_changes +msgid "hotel.wizard.massive.changes" +msgstr "hotel.wizard.massive.changes" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_wizard_massive_price_reservation_days +msgid "hotel.wizard.massive.price.reservation.days" +msgstr "hotel.wizard.massive.price.reservation.days" + +#. module: hotel +#: model:ir.model,name:hotel.model_hotel_wizard_split_reservation +msgid "hotel.wizard.split.reservation" +msgstr "hotel.wizard.split.reservation" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.report_currency_exchange +msgid "in" +msgstr "en" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio1_form +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "mobile" +msgstr "móvil" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.invoice_form +msgid "modify the payment" +msgstr "Modificar el pago" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_duplicate_reservation_wizard +#: model:ir.ui.view,arch_db:hotel.view_hotel_folio_wizard +#: model:ir.ui.view,arch_db:hotel.view_hotel_massive_changes_wizard +#: model:ir.ui.view,arch_db:hotel.view_hotel_massive_price_change_wizard +#: model:ir.ui.view,arch_db:hotel.view_hotel_split_reservation_wizard +msgid "or" +msgstr "o" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "phone" +msgstr "teléfono" + +#. module: hotel +#: model:ir.model,name:hotel.model_report_hotel_report_hotel_folio +msgid "report.hotel.report_hotel_folio" +msgstr "report.hotel.report_hotel_folio" + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_reservation_form +msgid "" +"to \n" +" " +msgstr "" +"hasta \n" +" " + +#. module: hotel +#: model:ir.ui.view,arch_db:hotel.view_hotel_room_aenities_search +msgid "ty rate" +msgstr "ty rate" diff --git a/hotel/models/__init__.py b/hotel/models/__init__.py new file mode 100644 index 000000000..d7f5dd69a --- /dev/null +++ b/hotel/models/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Alexandre Díaz +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import currency_exchange +#~ from . import folio_room_line +from . import inherit_payment_return +from . import hotel_floor +from . import hotel_folio +from . import hotel_reservation +from . import hotel_room +from . import hotel_room_amenities +from . import hotel_room_amenities_type +from . import hotel_room_type +# from . import hotel_service_line +from . import hotel_service +# from . import hotel_service_type +from . import inherit_account_invoice +# from . import inherit_product_category +from . import inherit_product_product +from . import inherit_res_company +# from . import virtual_room +from . import inherit_account_payment +from . import hotel_virtual_room_restriction +from . import hotel_virtual_room_restriction_item +from . import hotel_reservation_line +from . import cardex +from . import hotel_virtual_room_availability +from . import inherit_product_pricelist +from . import res_config +from . import inherit_res_partner +from . import inherited_mail_compose_message +#~ from . import hotel_dashboard diff --git a/hotel/models/cardex.py b/hotel/models/cardex.py new file mode 100644 index 000000000..94de8cba6 --- /dev/null +++ b/hotel/models/cardex.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Dario Lodeiros <> +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +import datetime +from openerp import models, fields, api, _ +from openerp.exceptions import except_orm, ValidationError +from odoo.addons.hotel import date_utils + + +class Cardex(models.Model): + _name = 'cardex' + + # Validation for Departure date is after arrival date. + @api.constrains('exit_date') + def validation_dates(self): + if self.exit_date < self.enter_date: + raise models.ValidationError( + _('Departure date (%s) is prior to arrival on %s') % + (self.exit_date, self.enter_date)) + + def default_reservation_id(self): + if 'reservation_id' in self.env.context: + reservation = self.env['hotel.reservation'].search([ + ('id', '=', self.env.context['reservation_id']) + ]) + return reservation + return False + + def default_enter_date(self): + if 'reservation_id' in self.env.context: + reservation = self.env['hotel.reservation'].search([ + ('id', '=', self.env.context['reservation_id']) + ]) + return reservation.checkin + return False + + def default_exit_date(self): + if 'reservation_id' in self.env.context: + reservation = self.env['hotel.reservation'].search([ + ('id', '=', self.env.context['reservation_id']) + ]) + return reservation.checkout + return False + + def default_partner_id(self): + if 'reservation_id' in self.env.context: + reservation = self.env['hotel.reservation'].search([ + ('id', '=', self.env.context['reservation_id']) + ]) + return reservation.partner_id + return False + + @api.onchange('enter_date', 'exit_date') + def check_change_dates(self): + if self.exit_date <= self.enter_date: + date_1 = date_utils.get_datetime(self.enter_date) + date_2 = date_1 + datetime.timedelta(days=1) + self.update({'exit_date': date_2, }) + raise ValidationError( + _('Departure date, is prior to arrival. Check it now. %s') % + (date_2)) + + partner_id = fields.Many2one('res.partner', default=default_partner_id, + required=True) + reservation_id = fields.Many2one( + 'hotel.reservation', + default=default_reservation_id, readonly=True) + enter_date = fields.Date(default=default_enter_date, required=True) + exit_date = fields.Date(default=default_exit_date, required=True) diff --git a/hotel/models/currency_exchange.py b/hotel/models/currency_exchange.py new file mode 100644 index 000000000..ab1a2a0ac --- /dev/null +++ b/hotel/models/currency_exchange.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Alexandre Díaz +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from decimal import Decimal +# For Python 3.0 and later +from urllib.request import urlopen +from openerp import models, fields, api, _ + + +class CurrencyExchangeRate(models.Model): + + _name = "currency.exchange" + _description = "currency" + + name = fields.Char('Reg Number', readonly=True, default='New') + today_date = fields.Datetime('Date Ordered', + required=True, + default=(lambda *a: + time.strftime + (DEFAULT_SERVER_DATETIME_FORMAT))) + input_curr = fields.Many2one('res.currency', string='Input Currency', + track_visibility='always') + in_amount = fields.Float('Amount Taken', size=64, default=1.0) + out_curr = fields.Many2one('res.currency', string='Output Currency', + track_visibility='always') + out_amount = fields.Float('Subtotal', size=64) + folio_no = fields.Many2one('hotel.folio', 'Folio Number') + guest_name = fields.Many2one('res.partner', string='Guest Name') + room_number = fields.Char(string='Room Number') + state = fields.Selection([('draft', 'Draft'), ('done', 'Done'), + ('cancel', 'Cancel')], 'State', default='draft') + rate = fields.Float('Rate(per unit)', size=64) + hotel_id = fields.Many2one('stock.warehouse', 'Hotel Name') + type = fields.Selection([('cash', 'Cash')], 'Type', default='cash') + tax = fields.Selection([('2', '2%'), ('5', '5%'), ('10', '10%')], + 'Service Tax', default='2') + total = fields.Float('Amount Given') + + @api.model + def create(self, vals): + """ + Overrides orm create method. + @param self: The object pointer + @param vals: dictionary of fields value. + """ + if not vals: + vals = {} + if self._context is None: + self._context = {} + seq_obj = self.env['ir.sequence'] + vals['name'] = seq_obj.next_by_code('currency.exchange') or 'New' + return super(CurrencyExchangeRate, self).create(vals) + + @api.onchange('folio_no') + def get_folio_no(self): + ''' + When you change folio_no, based on that it will update + the guest_name,hotel_id and room_number as well + --------------------------------------------------------- + @param self: object pointer + ''' + for rec in self: + self.guest_name = False + self.hotel_id = False + self.room_number = False + if rec.folio_no and len(rec.folio_no.room_lines) != 0: + self.guest_name = rec.folio_no.partner_id.id + self.hotel_id = rec.folio_no.warehouse_id.id + self.room_number = rec.folio_no.room_lines[0].product_id.name + + @api.multi + def act_cur_done(self): + """ + This method is used to change the state + to done of the currency exchange + --------------------------------------- + @param self: object pointer + """ + self.write({'state': 'done'}) + return True + + @api.multi + def act_cur_cancel(self): + """ + This method is used to change the state + to cancel of the currency exchange + --------------------------------------- + @param self: object pointer + """ + self.write({'state': 'cancel'}) + return True + + @api.multi + def act_cur_cancel_draft(self): + """ + This method is used to change the state + to draft of the currency exchange + --------------------------------------- + @param self: object pointer + """ + self.write({'state': 'draft'}) + return True + + @api.model + def get_rate(self, a, b): + ''' + Calculate rate between two currency + ----------------------------------- + @param self: object pointer + ''' + try: + url = 'http://finance.yahoo.com/d/quotes.csv?s=%s%s=X&f=l1' % (a, + b) + rate = urllib2.urlopen(url).read().rstrip() + return Decimal(rate) + except: + return Decimal('-1.00') + + @api.onchange('input_curr', 'out_curr', 'in_amount') + def get_currency(self): + ''' + When you change input_curr, out_curr or in_amount + it will update the out_amount of the currency exchange + ------------------------------------------------------ + @param self: object pointer + ''' + self.out_amount = 0.0 + if self.input_curr: + for rec in self: + result = rec.get_rate(self.input_curr.name, + self.out_curr.name) + if self.out_curr: + self.rate = result + if self.rate == Decimal('-1.00'): + raise except_orm(_('Warning'), + _('Please Check Your \ + Network Connectivity.')) + self.out_amount = (float(result) * float(self.in_amount)) + + @api.onchange('out_amount', 'tax') + def tax_change(self): + ''' + When you change out_amount or tax + it will update the total of the currency exchange + ------------------------------------------------- + @param self: object pointer + ''' + if self.out_amount: + ser_tax = ((self.out_amount) * (float(self.tax))) / 100 + self.total = self.out_amount - ser_tax diff --git a/hotel/models/hotel_dashboard.py b/hotel/models/hotel_dashboard.py new file mode 100644 index 000000000..da94b4bc2 --- /dev/null +++ b/hotel/models/hotel_dashboard.py @@ -0,0 +1,251 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Alexandre Díaz +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import json +from datetime import datetime, timedelta +from babel.dates import format_datetime, format_date +from odoo import models, api, _, fields +from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF +from odoo.tools.misc import formatLang + +class HotelDashboard(models.Model): + _name = "hotel.dashboard" + + def _get_count(self): + resevations_count = self.env['hotel.reservation'].search( + [('sate', '=', 'confirm')]) + folios_count = self.env['hotel.folio'].search( + [('sate', '=', 'sales_order')]) + next_arrivals_count = self.env['hotel.reservation'].search( + [('is_checkin', '=', True)]) + + self.orders_count = len(orders_count) + self.quotations_count = len(quotations_count) + self.orders_done_count = len(orders_done_count) + @api.one + def _kanban_dashboard(self): + if self.graph_type == 'bar': + self.kanban_dashboard_graph = json.dumps(self.get_bar_graph_datas()) + elif self.graph_type == 'line': + self.kanban_dashboard_graph = json.dumps(self.get_line_graph_datas()) + + @api.one + def _kanban_dashboard_graph(self): + self.kanban_dashboard_graph = json.dumps(self.get_bar_graph_datas()) + #~ if (self.type in ['sale', 'purchase']): + #~ self.kanban_dashboard_graph = json.dumps(self.get_bar_graph_datas()) + #~ elif (self.type in ['cash', 'bank']): + #~ self.kanban_dashboard_graph = json.dumps(self.get_line_graph_datas()) + + color = fields.Integer(string='Color Index') + name = fields.Char(string="Name") + type = fields.Char(default="sale") + graph_type = fields.Selection([('line','Line'),('bar','Bar'),('none','None')]) + reservations_count = fields.Integer(compute = '_get_count') + folios_count = fields.Integer(compute= '_get_count') + next_arrivals_count = fields.Integer(compute= '_get_count') + kanban_dashboard = fields.Text(compute='_kanban_dashboard') + kanban_dashboard_graph = fields.Text(compute='_kanban_dashboard_graph') + show_on_dashboard = fields.Boolean(string='Show journal on dashboard', help="Whether this journal should be displayed on the dashboard or not", default=True) + + @api.multi + def get_bar_graph_datas(self): + data = [] + today = datetime.strptime(fields.Date.context_today(self), DF) + day_of_week = int(format_datetime(today, 'e', locale=self._context.get('lang') or 'en_US')) + for i in range(0,15): + if i==0: + label = _('Today') + else: + label = format_date(today + timedelta(days=i) , 'd', locale=self._context.get('lang') or 'en_US') + data.append({'label':label,'value':0.0, 'type': 'past' if i<0 else 'future'}) + # Build SQL query to find amount aggregated by week + select_sql_clause = """SELECT count(id) as total from hotel_reservation where state != 'cancelled'""" + query = "("+select_sql_clause+" and date(checkin) = '"+today.strftime(DF)+"')" + for i in range(1,15): + next_date = today + timedelta(days=i) + query += " UNION ALL ("+select_sql_clause+" and date(checkin) = '"+next_date.strftime(DF)+"')" + + self.env.cr.execute(query) + query_results = self.env.cr.dictfetchall() + for index in range(0, len(query_results)): + data[index]['value'] = query_results[index].get('total') + return [{'values': data}] + + @api.multi + def get_journal_dashboard_datas(self): + #~ currency = self.currency_id or self.company_id.currency_id + #~ number_to_reconcile = last_balance = account_sum = 0 + #~ ac_bnk_stmt = [] + #~ title = '' + #~ number_draft = number_waiting = number_late = 0 + #~ sum_draft = sum_waiting = sum_late = 0.0 + #~ if self.type in ['bank', 'cash']: + #~ last_bank_stmt = self.env['account.bank.statement'].search([('journal_id', 'in', self.ids)], order="date desc, id desc", limit=1) + #~ last_balance = last_bank_stmt and last_bank_stmt[0].balance_end or 0 + #~ #Get the number of items to reconcile for that bank journal + #~ self.env.cr.execute("""SELECT COUNT(DISTINCT(statement_line_id)) + #~ FROM account_move where statement_line_id + #~ IN (SELECT line.id + #~ FROM account_bank_statement_line AS line + #~ LEFT JOIN account_bank_statement AS st + #~ ON line.statement_id = st.id + #~ WHERE st.journal_id IN %s and st.state = 'open')""", (tuple(self.ids),)) + #~ already_reconciled = self.env.cr.fetchone()[0] + #~ self.env.cr.execute("""SELECT COUNT(line.id) + #~ FROM account_bank_statement_line AS line + #~ LEFT JOIN account_bank_statement AS st + #~ ON line.statement_id = st.id + #~ WHERE st.journal_id IN %s and st.state = 'open'""", (tuple(self.ids),)) + #~ all_lines = self.env.cr.fetchone()[0] + #~ number_to_reconcile = all_lines - already_reconciled + #~ # optimization to read sum of balance from account_move_line + #~ account_ids = tuple(filter(None, [self.default_debit_account_id.id, self.default_credit_account_id.id])) + #~ if account_ids: + #~ amount_field = 'balance' if (not self.currency_id or self.currency_id == self.company_id.currency_id) else 'amount_currency' + #~ query = """SELECT sum(%s) FROM account_move_line WHERE account_id in %%s AND date <= %%s;""" % (amount_field,) + #~ self.env.cr.execute(query, (account_ids, fields.Date.today(),)) + #~ query_results = self.env.cr.dictfetchall() + #~ if query_results and query_results[0].get('sum') != None: + #~ account_sum = query_results[0].get('sum') + #~ #TODO need to check if all invoices are in the same currency than the journal!!!! + #~ elif self.type in ['sale', 'purchase']: + #~ title = _('Bills to pay') if self.type == 'purchase' else _('Invoices owed to you') + #~ # optimization to find total and sum of invoice that are in draft, open state + #~ query = """SELECT state, amount_total, currency_id AS currency, type FROM account_invoice WHERE journal_id = %s AND state NOT IN ('paid', 'cancel');""" + #~ self.env.cr.execute(query, (self.id,)) + #~ query_results = self.env.cr.dictfetchall() + #~ today = datetime.today() + #~ query = """SELECT amount_total, currency_id AS currency, type FROM account_invoice WHERE journal_id = %s AND date < %s AND state = 'open';""" + #~ self.env.cr.execute(query, (self.id, today)) + #~ late_query_results = self.env.cr.dictfetchall() + #~ for result in query_results: + #~ if result['type'] in ['in_refund', 'out_refund']: + #~ factor = -1 + #~ else: + #~ factor = 1 + #~ cur = self.env['res.currency'].browse(result.get('currency')) + #~ if result.get('state') in ['draft', 'proforma', 'proforma2']: + #~ number_draft += 1 + #~ sum_draft += cur.compute(result.get('amount_total'), currency) * factor + #~ elif result.get('state') == 'open': + #~ number_waiting += 1 + #~ sum_waiting += cur.compute(result.get('amount_total'), currency) * factor + #~ for result in late_query_results: + #~ if result['type'] in ['in_refund', 'out_refund']: + #~ factor = -1 + #~ else: + #~ factor = 1 + #~ cur = self.env['res.currency'].browse(result.get('currency')) + #~ number_late += 1 + #~ sum_late += cur.compute(result.get('amount_total'), currency) * factor + + #~ difference = currency.round(last_balance-account_sum) + 0.0 + return { + 'graph': self.graph_type, + 'number_to_reconcile': 11, + 'account_balance': 4314, + 'last_balance': 252, + 'difference': 432, + 'number_draft': 32, + 'number_waiting': 44, + 'number_late': 23, + 'sum_draft': 2424245, + 'sum_waiting': 3124312, + 'sum_late': 23123, + 'currency_id': 1, + 'bank_statements_source': 'fonte', + 'title': 'titulo', + } + + @api.multi + def get_line_graph_datas(self): + data = [] + today = datetime.strptime(fields.Date.context_today(self), DF) + days=30 + + for i in range(-1, days + 1): + ndate = today + timedelta(days=i) + ndate_str = ndate.strftime(DF) + day_onboard = self.env['hotel.reservation.line'].search_count([('date','=',ndate)]) + locale = self._context.get('lang') or 'en_US' + short_name = format_date(ndate, 'd', locale=locale) + name = format_date(ndate, 'd LLLL Y', locale=locale) + data.append({'x':short_name,'y':day_onboard, 'name':name}) + return [{'values': data, 'area': True}] + + @api.multi + def action_create_new(self): + #~ ctx = self._context.copy() + #~ model = 'account.invoice' + #~ if self.type == 'sale': + #~ ctx.update({'journal_type': self.type, 'default_type': 'out_invoice', 'type': 'out_invoice', 'default_journal_id': self.id}) + #~ if ctx.get('refund'): + #~ ctx.update({'default_type':'out_refund', 'type':'out_refund'}) + #~ view_id = self.env.ref('account.invoice_form').id + #~ elif self.type == 'purchase': + #~ ctx.update({'journal_type': self.type, 'default_type': 'in_invoice', 'type': 'in_invoice', 'default_journal_id': self.id}) + #~ if ctx.get('refund'): + #~ ctx.update({'default_type': 'in_refund', 'type': 'in_refund'}) + #~ view_id = self.env.ref('account.invoice_supplier_form').id + #~ else: + #~ ctx.update({'default_journal_id': self.id}) + #~ view_id = self.env.ref('account.view_move_form').id + #~ model = 'account.move' + model = "hotel.folio" + view_id = self.env.ref('hotel.view_hotel_folio1_form').id + ctx='' + return { + 'name': _('Create invoice/bill'), + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': model, + 'view_id': view_id, + 'context': ctx, + } + + @api.multi + def open_action(self): + """return action based on type for related journals""" + #~ action_name = self._context.get('action_name', False) + #~ if not action_name: + #~ if self.type == 'bank': + #~ action_name = 'action_bank_statement_tree' + #~ elif self.type == 'cash': + #~ action_name = 'action_view_bank_statement_tree' + #~ elif self.type == 'sale': + #~ action_name = 'action_invoice_tree1' + #~ elif self.type == 'purchase': + #~ action_name = 'action_invoice_tree2' + #~ else: + #~ action_name = 'action_move_journal_line' + + #~ _journal_invoice_type_map = { + #~ ('sale', None): 'out_invoice', + #~ ('purchase', None): 'in_invoice', + #~ ('sale', 'refund'): 'out_refund', + #~ ('purchase', 'refund'): 'in_refund', + #~ ('bank', None): 'bank', + #~ ('cash', None): 'cash', + #~ ('general', None): 'general', + #~ } + #~ invoice_type = _journal_invoice_type_map[(self.type, self._context.get('invoice_type'))] + + #~ ctx = self._context.copy() + #~ ctx.pop('group_by', None) + #~ ctx.update({ + #~ 'journal_type': self.type, + #~ 'default_journal_id': self.id, + #~ 'search_default_journal_id': self.id, + #~ 'default_type': invoice_type, + #~ 'type': invoice_type + #~ }) + + #~ [action] = self.env.ref('account.%s' % action_name).read() + #~ action['context'] = ctx + #~ action['domain'] = self._context.get('use_domain', []) + #~ if action_name in ['action_bank_statement_tree', 'action_view_bank_statement_tree']: + #~ action['views'] = False + #~ action['view_id'] = False + return False diff --git a/hotel/models/hotel_floor.py b/hotel/models/hotel_floor.py new file mode 100644 index 000000000..8c6fb715a --- /dev/null +++ b/hotel/models/hotel_floor.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Dario Lodeiros <> +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from openerp import models, fields, api, _ + + +class HotelFloor(models.Model): + + _name = "hotel.floor" + _description = "Ubication" + + name = fields.Char('Ubication Name', size=64, required=True, index=True) + sequence = fields.Integer('Sequence', size=64) diff --git a/hotel/models/hotel_folio.py b/hotel/models/hotel_folio.py new file mode 100644 index 000000000..54dd4fbe8 --- /dev/null +++ b/hotel/models/hotel_folio.py @@ -0,0 +1,884 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import datetime +import time +import pytz +import logging +from decimal import Decimal +from dateutil.relativedelta import relativedelta +from odoo.exceptions import except_orm, UserError, ValidationError +from odoo.tools import ( + misc, + DEFAULT_SERVER_DATETIME_FORMAT, + DEFAULT_SERVER_DATE_FORMAT) +from odoo import models, fields, api, _ +from odoo.addons.hotel import date_utils +_logger = logging.getLogger(__name__) + +from odoo.addons import decimal_precision as dp + + +class HotelFolio(models.Model): + + @api.model + def name_search(self, name='', args=None, operator='ilike', limit=100): + if args is None: + args = [] + args += ([('name', operator, name)]) + mids = self.search(args, limit=100) + return mids.name_get() + + @api.model + def _needaction_count(self, domain=None): + """ + Show a count of draft state folio on the menu badge. + @param self: object pointer + """ + return self.search_count([('state', '=', 'draft')]) + + @api.multi + def copy(self, default=None): + ''' + @param self: object pointer + @param default: dict of default values to be set + ''' + return super(HotelFolio, self).copy(default=default) + + @api.multi + def _invoiced(self, name, arg): + ''' + @param self: object pointer + @param name: Names of fields. + @param arg: User defined arguments + ''' + pass + # return self.env['sale.order']._invoiced(name, arg) + + @api.multi + def _invoiced_search(self, obj, name, args): + ''' + @param self: object pointer + @param name: Names of fields. + @param arg: User defined arguments + ''' + pass + # return self.env['sale.order']._invoiced_search(obj, name, args) + + # @api.depends('invoice_lines.invoice_id.state', 'invoice_lines.quantity') + def _get_invoice_qty(self): + pass + # @api.depends('product_id.invoice_policy', 'order_id.state') + def _compute_qty_delivered_updateable(self): + pass + # @api.depends('state', 'order_line.invoice_status') + def _get_invoiced(self): + pass + # @api.depends('state', 'product_uom_qty', 'qty_delivered', 'qty_to_invoice', 'qty_invoiced') + def _compute_invoice_status(self): + pass + # @api.depends('product_uom_qty', 'discount', 'price_unit', 'tax_id') + def _compute_amount(self): + pass + # @api.depends('order_line.price_total') + def _amount_all(self): + pass + + _name = 'hotel.folio' + _description = 'Hotel Folio' + + _order = 'id' + _inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin'] + + name = fields.Char('Folio Number', readonly=True, index=True, + default='New') + partner_id = fields.Many2one('res.partner', + track_visibility='onchange') + # partner_invoice_id = fields.Many2one('res.partner', + # string='Invoice Address', + # readonly=True, required=True, + # states={'draft': [('readonly', False)], + # 'sent': [('readonly', False)]}, + # help="Invoice address for current sales order.") + + # For being used directly in the Folio views + email = fields.Char('E-mail', related='partner_id.email') + mobile = fields.Char('Mobile', related='partner_id.mobile') + phone = fields.Char('Phone', related='partner_id.phone') + + state = fields.Selection([('draft', 'Pre-reservation'), ('confirm', 'Pending Entry'), + ('booking', 'On Board'), ('done', 'Out'), + ('cancelled', 'Cancelled')], + 'State', readonly=True, + default=lambda *a: 'draft', + track_visibility='onchange') + + room_lines = fields.One2many('hotel.reservation', 'folio_id', + readonly=False, + states={'done': [('readonly', True)]}, + help="Hotel room reservation detail.",) + + service_line_ids = fields.One2many('hotel.service', 'folio_id', + readonly=False, + states={'done': [('readonly', True)]}, + help="Hotel services detail provide to " + "customer and it will include in " + "main Invoice.") + # service_line_ids = fields.One2many('hotel.service.line', 'folio_id', + # readonly=False, + # states={'done': [('readonly', True)]}, + # help="Hotel services detail provide to" + # "customer and it will include in " + # "main Invoice.") + # has no sense used as this way + hotel_invoice_id = fields.Many2one('account.invoice', 'Invoice') + + company_id = fields.Many2one('res.company', 'Company') + + # currency_id = fields.Many2one('res.currency', related='pricelist_id.currency_id', + # string='Currency', readonly=True, required=True) + + # pricelist_id = fields.Many2one('product.pricelist', + # string='Pricelist', + # required=True, + # readonly=True, + # states={'draft': [('readonly', False)], + # 'sent': [('readonly', False)]}, + # help="Pricelist for current sales order.") + # Monetary to Float + invoices_amount = fields.Float(compute='compute_invoices_amount', + store=True, + string="Pending in Folio") + # Monetary to Float + refund_amount = fields.Float(compute='compute_invoices_amount', + store=True, + string="Payment Returns") + # Monetary to Float + invoices_paid = fields.Float(compute='compute_invoices_amount', + store=True, track_visibility='onchange', + string="Payments") + + booking_pending = fields.Integer('Booking pending', + compute='_compute_cardex_count') + cardex_count = fields.Integer('Cardex counter', + compute='_compute_cardex_count') + cardex_pending = fields.Boolean('Cardex Pending', + compute='_compute_cardex_count') + cardex_pending_num = fields.Integer('Cardex Pending', + compute='_compute_cardex_count') + checkins_reservations = fields.Integer('checkins reservations') + checkouts_reservations = fields.Integer('checkouts reservations') + partner_internal_comment = fields.Text(string='Internal Partner Notes', + related='partner_id.comment') + internal_comment = fields.Text(string='Internal Folio Notes') + cancelled_reason = fields.Text('Cause of cancelled') + payment_ids = fields.One2many('account.payment', 'folio_id', + readonly=True) + return_ids = fields.One2many('payment.return', 'folio_id', + readonly=True) + prepaid_warning_days = fields.Integer( + 'Prepaid Warning Days', + help='Margin in days to create a notice if a payment \ + advance has not been recorded') + reservation_type = fields.Selection([('normal', 'Normal'), + ('staff', 'Staff'), + ('out', 'Out of Service')], + 'Type', default=lambda *a: 'normal') + channel_type = fields.Selection([('door', 'Door'), + ('mail', 'Mail'), + ('phone', 'Phone'), + ('web', 'Web')], 'Sales Channel', default='door') + num_invoices = fields.Integer(compute='_compute_num_invoices') + rooms_char = fields.Char('Rooms', compute='_computed_rooms_char') + segmentation_ids = fields.Many2many('res.partner.category', + string='Segmentation') + has_confirmed_reservations_to_send = fields.Boolean( + compute='_compute_has_confirmed_reservations_to_send') + has_cancelled_reservations_to_send = fields.Boolean( + compute='_compute_has_cancelled_reservations_to_send') + has_checkout_to_send = fields.Boolean( + compute='_compute_has_checkout_to_send') + # fix_price = fields.Boolean(compute='_compute_fix_price') + date_order = fields.Datetime( + string='Order Date', + required=True, readonly=True, index=True, + states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, + copy=False, default=fields.Datetime.now) + + invoice_ids = fields.Many2many('account.invoice', string='Invoices', + compute='_get_invoiced', readonly=True, copy=False) + invoice_status = fields.Selection([('upselling', 'Upselling Opportunity'), + ('invoiced', 'Fully Invoiced'), + ('to invoice', 'To Invoice'), + ('no', 'Nothing to Invoice')], + string='Invoice Status', + compute='_compute_invoice_status', + store=True, readonly=True, default='no') + client_order_ref = fields.Char(string='Customer Reference', copy=False) + note = fields.Text('Terms and conditions') + # layout_category_id = fields.Many2one('sale.layout_category', string='Section') + + user_id = fields.Many2one('res.users', string='Salesperson', index=True, + track_visibility='onchange', default=lambda self: self.env.user) + + sequence = fields.Integer(string='Sequence', default=10) + # sale.order + amount_total = fields.Float(string='Total', store=True, readonly=True, + track_visibility='always') + + + def _compute_fix_price(self): + for record in self: + for res in record.room_lines: + if res.fix_total == True: + record.fix_price = True + break + else: + record.fix_price = False + + def action_recalcule_payment(self): + for record in self: + for res in record.room_lines: + res.on_change_checkin_checkout_product_id() + + def _computed_rooms_char(self): + for record in self: + rooms = ', '.join(record.mapped('room_lines.room_id.name')) + record.rooms_char = rooms + + @api.model + def recompute_amount(self): + folios = self.env['hotel.folio'] + if folios: + folios = folios.filtered(lambda x: ( + x.name == folio_name)) + folios.compute_invoices_amount() + + @api.multi + def _compute_num_invoices(self): + pass + # for fol in self: + # fol.num_invoices = len(self.mapped('invoice_ids.id')) + + @api.model + def daily_plan(self): + _logger.info('daily_plan') + self._cr.execute("update hotel_folio set checkins_reservations = 0, \ + checkouts_reservations = 0 where checkins_reservations > 0 \ + or checkouts_reservations > 0") + folios_in = self.env['hotel.folio'].search([ + ('room_lines.is_checkin', '=', True) + ]) + folios_out = self.env['hotel.folio'].search([ + ('room_lines.is_checkout', '=', True) + ]) + for fol in folios_in: + count_checkin = fol.room_lines.search_count([ + ('is_checkin', '=', True), ('folio_id.id', '=', fol.id) + ]) + fol.write({'checkins_reservations': count_checkin}) + for fol in folios_out: + count_checkout = fol.room_lines.search_count([ + ('is_checkout', '=', True), + ('folio_id.id', '=', fol.id) + ]) + fol.write({'checkouts_reservations': count_checkout}) + return True + + # @api.depends('order_line.price_total', 'payment_ids', 'return_ids') + @api.multi + def compute_invoices_amount(self): + _logger.info('compute_invoices_amount') + + @api.multi + def action_pay(self): + self.ensure_one() + partner = self.partner_id.id + amount = self.invoices_amount + view_id = self.env.ref('hotel.view_account_payment_folio_form').id + return{ + 'name': _('Register Payment'), + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'account.payment', + 'type': 'ir.actions.act_window', + 'view_id': view_id, + 'context': { + 'default_folio_id': self.id, + 'default_amount': amount, + 'default_payment_type': 'inbound', + 'default_partner_type': 'customer', + 'default_partner_id': partner, + 'default_communication': self.name, + }, + 'target': 'new', + } + + @api.multi + def action_payments(self): + self.ensure_one() + payments_obj = self.env['account.payment'] + payments = payments_obj.search([('folio_id','=',self.id)]) + payment_ids = payments.mapped('id') + invoices = self.mapped('invoice_ids.id') + return{ + 'name': _('Payments'), + 'view_type': 'form', + 'view_mode': 'tree,form', + 'res_model': 'account.payment', + 'target': 'new', + 'type': 'ir.actions.act_window', + 'domain': [('id', 'in', payment_ids)], + } + + @api.multi + def open_invoices_folio(self): + invoices = self.mapped('invoice_ids') + action = self.env.ref('account.action_invoice_tree1').read()[0] + if len(invoices) > 1: + action['domain'] = [('id', 'in', invoices.ids)] + elif len(invoices) == 1: + action['views'] = [(self.env.ref('account.invoice_form').id, 'form')] + action['res_id'] = invoices.ids[0] + else: + action = {'type': 'ir.actions.act_window_close'} + return action + + @api.multi + def action_return_payments(self): + self.ensure_one() + return_move_ids = [] + acc_pay_obj = self.env['account.payment'] + payments = acc_pay_obj.search([ + '|', + ('invoice_ids', 'in', self.invoice_ids.ids), + ('folio_id', '=', self.id) + ]) + return_move_ids += self.invoice_ids.filtered( + lambda invoice: invoice.type == 'out_refund').mapped( + 'payment_move_line_ids.move_id.id') + return_lines = self.env['payment.return.line'].search([( + 'move_line_ids','in',payments.mapped( + 'move_line_ids.id'))]) + return_move_ids += return_lines.mapped('return_id.move_id.id') + + return{ + 'name': _('Returns'), + 'view_type': 'form', + 'view_mode': 'tree,form', + 'res_model': 'account.move', + 'type': 'ir.actions.act_window', + 'domain': [('id', 'in', return_move_ids)], + } + + @api.multi + def action_checks(self): + self.ensure_one() + rooms = self.mapped('room_lines.id') + return { + 'name': _('Cardexs'), + 'view_type': 'form', + 'view_mode': 'tree,form', + 'res_model': 'cardex', + 'type': 'ir.actions.act_window', + 'domain': [('reservation_id', 'in', rooms)], + 'target': 'new', + } + + @api.multi + def action_folios_amount(self): + now_utc_dt = date_utils.now() + now_utc_str = now_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + reservations = self.env['hotel.reservation'].search([ + ('checkout', '<=', now_utc_str) + ]) + folio_ids = reservations.mapped('folio_id.id') + folios = self.env['hotel.folio'].search([('id', 'in', folio_ids)]) + folios = folios.filtered(lambda r: r.invoices_amount > 0) + return { + 'name': _('Pending'), + 'view_type': 'form', + 'view_mode': 'tree,form', + 'res_model': 'hotel.folio', + 'type': 'ir.actions.act_window', + 'domain': [('id', 'in', folios.ids)] + } + + @api.depends('room_lines') + def _compute_has_confirmed_reservations_to_send(self): + has_to_send = False + for rline in self.room_lines: + if rline.splitted: + master_reservation = rline.parent_reservation or rline + has_to_send = self.env['hotel.reservation'].search_count([ + ('splitted', '=', True), + ('folio_id', '=', self.id), + ('to_send', '=', True), + ('state', 'in', ('confirm', 'booking')), + '|', + ('parent_reservation', '=', master_reservation.id), + ('id', '=', master_reservation.id), + ]) > 0 + elif rline.to_send and rline.state in ('confirm', 'booking'): + has_to_send = True + break + self.has_confirmed_reservations_to_send = has_to_send + + @api.depends('room_lines') + def _compute_has_cancelled_reservations_to_send(self): + has_to_send = False + for rline in self.room_lines: + if rline.splitted: + master_reservation = rline.parent_reservation or rline + has_to_send = self.env['hotel.reservation'].search_count([ + ('splitted', '=', True), + ('folio_id', '=', self.id), + ('to_send', '=', True), + ('state', '=', 'cancelled'), + '|', + ('parent_reservation', '=', master_reservation.id), + ('id', '=', master_reservation.id), + ]) > 0 + elif rline.to_send and rline.state == 'cancelled': + has_to_send = True + break + self.has_cancelled_reservations_to_send = has_to_send + + @api.depends('room_lines') + def _compute_has_checkout_to_send(self): + has_to_send = True + for rline in self.room_lines: + if rline.splitted: + master_reservation = rline.parent_reservation or rline + nreservs = self.env['hotel.reservation'].search_count([ + ('splitted', '=', True), + ('folio_id', '=', self.id), + ('to_send', '=', True), + ('state', '=', 'done'), + '|', + ('parent_reservation', '=', master_reservation.id), + ('id', '=', master_reservation.id), + ]) + if nreservs != len(self.room_lines): + has_to_send = False + elif not rline.to_send or rline.state != 'done': + has_to_send = False + break + self.has_checkout_to_send = has_to_send + + @api.multi + def _compute_cardex_count(self): + _logger.info('_compute_cardex_amount') + for fol in self: + num_cardex = 0 + pending = False + if fol.reservation_type == 'normal': + for reser in fol.room_lines: + if reser.state != 'cancelled' and \ + not reser.parent_reservation: + num_cardex += len(reser.cardex_ids) + fol.cardex_count = num_cardex + pending = 0 + for reser in fol.room_lines: + if reser.state != 'cancelled' and \ + not reser.parent_reservation: + pending += (reser.adults + reser.children) \ + - len(reser.cardex_ids) + if pending <= 0: + fol.cardex_pending = False + else: + fol.cardex_pending = True + fol.cardex_pending_num = pending + + @api.multi + def go_to_currency_exchange(self): + ''' + when Money Exchange button is clicked then this method is called. + ------------------------------------------------------------------- + @param self: object pointer + ''' + _logger.info('go_to_currency_exchange') + pass + # cr, uid, context = self.env.args + # context = dict(context) + # for rec in self: + # if rec.partner_id.id and len(rec.room_lines) != 0: + # context.update({'folioid': rec.id, 'guest': rec.partner_id.id, + # 'room_no': rec.room_lines[0].product_id.name}) + # self.env.args = cr, uid, misc.frozendict(context) + # else: + # raise except_orm(_('Warning'), _('Please Reserve Any Room.')) + # return {'name': _('Currency Exchange'), + # 'res_model': 'currency.exchange', + # 'type': 'ir.actions.act_window', + # 'view_id': False, + # 'view_mode': 'form,tree', + # 'view_type': 'form', + # 'context': {'default_folio_no': context.get('folioid'), + # 'default_hotel_id': context.get('hotel'), + # 'default_guest_name': context.get('guest'), + # 'default_room_number': context.get('room_no') + # }, + # } + + @api.model + def create(self, vals, check=True): + """ + Overrides orm create method. + @param self: The object pointer + @param vals: dictionary of fields value. + @return: new record set for hotel folio. + """ + _logger.info('create') + if not 'service_line_ids' and 'folio_id' in vals: + tmp_room_lines = vals.get('room_lines', []) + vals['order_policy'] = vals.get('hotel_policy', 'manual') + vals.update({'room_lines': []}) + for line in (tmp_room_lines): + line[2].update({'folio_id': folio_id}) + vals.update({'room_lines': tmp_room_lines}) + folio_id = super(HotelFolio, self).create(vals) + else: + if not vals: + vals = {} + vals['name'] = self.env['ir.sequence'].next_by_code('hotel.folio') + folio_id = super(HotelFolio, self).create(vals) + + return folio_id + + @api.multi + def write(self, vals): + if 'room_lines' in vals and vals['room_lines'][0][2] and 'reservation_line_ids' in vals['room_lines'][0][2] and vals['room_lines'][0][2]['reservation_line_ids'][0][0] == 5: + del vals['room_lines'] + return super(HotelFolio, self).write(vals) + + @api.multi + @api.onchange('partner_id') + def onchange_partner_id(self): + ''' + When you change partner_id it will update the partner_invoice_id, + partner_shipping_id and pricelist_id of the hotel folio as well + --------------------------------------------------------------- + @param self: object pointer + ''' + _logger.info('onchange_partner_id') + pass + # self.update({ + # 'currency_id': self.env.ref('base.main_company').currency_id, + # 'partner_invoice_id': self.partner_id and self.partner_id.id or False, + # 'partner_shipping_id': self.partner_id and self.partner_id.id or False, + # 'pricelist_id': self.partner_id and self.partner_id.property_product_pricelist.id or False, + # }) + # """ + # Warning messajes saved in partner form to folios + # """ + # if not self.partner_id: + # return + # warning = {} + # title = False + # message = False + # partner = self.partner_id + # + # # If partner has no warning, check its company + # if partner.sale_warn == 'no-message' and partner.parent_id: + # partner = partner.parent_id + # + # if partner.sale_warn != 'no-message': + # # Block if partner only has warning but parent company is blocked + # if partner.sale_warn != 'block' and partner.parent_id \ + # and partner.parent_id.sale_warn == 'block': + # partner = partner.parent_id + # title = _("Warning for %s") % partner.name + # message = partner.sale_warn_msg + # warning = { + # 'title': title, + # 'message': message, + # } + # if self.partner_id.sale_warn == 'block': + # self.update({ + # 'partner_id': False, + # 'partner_invoice_id': False, + # 'partner_shipping_id': False, + # 'pricelist_id': False + # }) + # return {'warning': warning} + # + # if warning: + # return {'warning': warning} + + @api.multi + def button_dummy(self): + ''' + @param self: object pointer + ''' + # for folio in self: + # folio.order_id.button_dummy() + return True + + @api.multi + def action_done(self): + for line in self.room_lines: + if line.state == "booking": + line.action_reservation_checkout() + + @api.multi + def action_invoice_create(self, grouped=False, states=None): + ''' + @param self: object pointer + ''' + pass + # if states is None: + # states = ['confirmed', 'done'] + # order_ids = [folio.order_id.id for folio in self] + # sale_obj = self.env['sale.order'].browse(order_ids) + # invoice_id = (sale_obj.action_invoice_create(grouped=False, + # states=['confirmed', + # 'done'])) + # for line in self: + # values = {'invoiced': True, + # 'state': 'progress' if grouped else 'progress', + # 'hotel_invoice_id': invoice_id + # } + # line.write(values) + # return invoice_id + + @api.multi + def advance_invoice(self): + pass + # order_ids = [folio.order_id.id for folio in self] + # sale_obj = self.env['sale.order'].browse(order_ids) + # invoices = action_invoice_create(self, grouped=True) + # return invoices + + @api.multi + def action_cancel(self): + ''' + @param self: object pointer + ''' + pass + # for sale in self: + # if not sale.order_id: + # raise ValidationError(_('Order id is not available')) + # for invoice in sale.invoice_ids: + # invoice.state = 'cancel' + # sale.room_lines.action_cancel() + # sale.order_id.action_cancel() + + + @api.multi + def action_confirm(self): + _logger.info('action_confirm') + + @api.multi + def print_quotation(self): + pass + # self.order_id.filtered(lambda s: s.state == 'draft').write({ + # 'state': 'sent', + # }) + # return self.env.ref('sale.report_saleorder').report_action(self, data=data) + + @api.multi + def action_cancel_draft(self): + _logger.info('action_confirm') + + @api.multi + def send_reservation_mail(self): + ''' + This function opens a window to compose an email, + template message loaded by default. + @param self: object pointer + ''' + # Debug Stop ------------------- + # import wdb; wdb.set_trace() + # Debug Stop ------------------- + self.ensure_one() + ir_model_data = self.env['ir.model.data'] + try: + template_id = (ir_model_data.get_object_reference + ('hotel', + 'mail_template_hotel_reservation')[1]) + except ValueError: + template_id = False + try: + compose_form_id = (ir_model_data.get_object_reference + ('mail', + 'email_compose_message_wizard_form')[1]) + except ValueError: + compose_form_id = False + ctx = dict() + ctx.update({ + 'default_model': 'hotel.folio', + 'default_res_id': self._ids[0], + 'default_use_template': bool(template_id), + 'default_template_id': template_id, + 'default_composition_mode': 'comment', + 'force_send': True, + 'mark_so_as_sent': True + }) + return { + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'mail.compose.message', + 'views': [(compose_form_id, 'form')], + 'view_id': compose_form_id, + 'target': 'new', + 'context': ctx, + 'force_send': True + } + + @api.multi + def send_exit_mail(self): + ''' + This function opens a window to compose an email, + template message loaded by default. + @param self: object pointer + ''' + # Debug Stop ------------------- + # import wdb; wdb.set_trace() + # Debug Stop ------------------- + self.ensure_one() + ir_model_data = self.env['ir.model.data'] + try: + template_id = (ir_model_data.get_object_reference + ('hotel', + 'mail_template_hotel_exit')[1]) + except ValueError: + template_id = False + try: + compose_form_id = (ir_model_data.get_object_reference + ('mail', + 'email_compose_message_wizard_form')[1]) + except ValueError: + compose_form_id = False + ctx = dict() + ctx.update({ + 'default_model': 'hotel.reservation', + 'default_res_id': self._ids[0], + 'default_use_template': bool(template_id), + 'default_template_id': template_id, + 'default_composition_mode': 'comment', + 'force_send': True, + 'mark_so_as_sent': True + }) + return { + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'mail.compose.message', + 'views': [(compose_form_id, 'form')], + 'view_id': compose_form_id, + 'target': 'new', + 'context': ctx, + 'force_send': True + } + + + @api.multi + def send_cancel_mail(self): + ''' + This function opens a window to compose an email, + template message loaded by default. + @param self: object pointer + ''' + # Debug Stop ------------------- + #import wdb; wdb.set_trace() + # Debug Stop ------------------- + self.ensure_one() + ir_model_data = self.env['ir.model.data'] + try: + template_id = (ir_model_data.get_object_reference + ('hotel', + 'mail_template_hotel_cancel')[1]) + except ValueError: + template_id = False + try: + compose_form_id = (ir_model_data.get_object_reference + ('mail', + 'email_compose_message_wizard_form')[1]) + except ValueError: + compose_form_id = False + ctx = dict() + ctx.update({ + 'default_model': 'hotel.reservation', + 'default_res_id': self._ids[0], + 'default_use_template': bool(template_id), + 'default_template_id': template_id, + 'default_composition_mode': 'comment', + 'force_send': True, + 'mark_so_as_sent': True + }) + return { + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'mail.compose.message', + 'views': [(compose_form_id, 'form')], + 'view_id': compose_form_id, + 'target': 'new', + 'context': ctx, + 'force_send': True + } + + @api.model + def reservation_reminder_24hrs(self): + """ + This method is for scheduler + every 1day scheduler will call this method to + find all tomorrow's reservations. + ---------------------------------------------- + @param self: The object pointer + @return: send a mail + """ + now_str = time.strftime(dt) + now_date = datetime.strptime(now_str, dt) + ir_model_data = self.env['ir.model.data'] + template_id = (ir_model_data.get_object_reference + ('hotel_reservation', + 'mail_template_reservation_reminder_24hrs')[1]) + template_rec = self.env['mail.template'].browse(template_id) + for reserv_rec in self.search([]): + checkin_date = (datetime.strptime(reserv_rec.checkin, dt)) + difference = relativedelta(now_date, checkin_date) + if(difference.days == -1 and reserv_rec.partner_id.email and + reserv_rec.state == 'confirm'): + template_rec.send_mail(reserv_rec.id, force_send=True) + return True + + @api.multi + def unlink(self): + # for record in self: + # record.order_id.unlink() + return super(HotelFolio, self).unlink() + + @api.multi + def get_grouped_reservations_json(self, state, import_all=False): + self.ensure_one() + info_grouped = [] + for rline in self.room_lines: + if (import_all or rline.to_send) and not rline.parent_reservation and rline.state == state: + dates = rline.get_real_checkin_checkout() + vals = { + 'num': len( + self.room_lines.filtered(lambda r: r.get_real_checkin_checkout()[0] == dates[0] and r.get_real_checkin_checkout()[1] == dates[1] and r.room_type_id.id == rline.room_type_id.id and (r.to_send or import_all) and not r.parent_reservation and r.state == rline.state) + ), + 'room_type': { + 'id': rline.room_type_id.id, + 'name': rline.room_type_id.name, + }, + 'checkin': dates[0], + 'checkout': dates[1], + 'nights': len(rline.reservation_line_ids), + 'adults': rline.adults, + 'childrens': rline.children, + } + founded = False + for srline in info_grouped: + if srline['num'] == vals['num'] and srline['room_type']['id'] == vals['room_type']['id'] and srline['checkin'] == vals['checkin'] and srline['checkout'] == vals['checkout']: + founded = True + break + if not founded: + info_grouped.append(vals) + return sorted(sorted(info_grouped, key=lambda k: k['num'], reverse=True), key=lambda k: k['room_type']['id']) diff --git a/hotel/models/hotel_reservation.py b/hotel/models/hotel_reservation.py new file mode 100644 index 000000000..97d050f84 --- /dev/null +++ b/hotel/models/hotel_reservation.py @@ -0,0 +1,1298 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo.exceptions import except_orm, UserError, ValidationError +from odoo.tools import ( + misc, + DEFAULT_SERVER_DATE_FORMAT, + DEFAULT_SERVER_DATETIME_FORMAT) +from odoo import models, fields, api, _ +from decimal import Decimal +from dateutil.relativedelta import relativedelta +from datetime import datetime, timedelta, date +from odoo.addons.hotel import date_utils +import pytz +import time +import logging +_logger = logging.getLogger(__name__) + +from odoo.addons import decimal_precision as dp + +class HotelReservation(models.Model): + + @api.multi + def _generate_color(self): + self.ensure_one() + now_utc_dt = date_utils.now() + # unused variables + # diff_checkin_now = date_utils.date_diff(now_utc_dt, self.checkin, + # hours=False) + # diff_checkout_now = date_utils.date_diff(now_utc_dt, self.checkout, + # hours=False) + + ir_values_obj = self.env['ir.default'] + reserv_color = '#FFFFFF' + reserv_color_text = '#000000' + # FIXME added for migration + return ('#4E9DC4', '#000000') + + if self.reservation_type == 'staff': + reserv_color = ir_values_obj.get('res.config.settings', + 'color_staff') + reserv_color_text = ir_values_obj.get( + 'res.config.settings', + 'color_letter_staff') + elif self.reservation_type == 'out': + reserv_color = ir_values_obj.get('res.config.settings', + 'color_dontsell') + reserv_color_text = ir_values_obj.get( + 'res.config.settings', + 'color_letter_dontsell') + elif self.to_assign: + reserv_color = ir_values_obj.get('res.config.settings', + 'color_to_assign') + reserv_color_text = ir_values_obj.get( + 'res.config.settings', + 'color_letter_to_assign') + elif self.state == 'draft': + reserv_color = ir_values_obj.get('res.config.settings', + 'color_pre_reservation') + reserv_color_text = ir_values_obj.get( + 'res.config.settings', + 'color_letter_pre_reservation') + elif self.state == 'confirm': + if self.folio_id.invoices_amount == 0: + reserv_color = ir_values_obj.get( + 'res.config.settings', 'color_reservation_pay') + reserv_color_text = ir_values_obj.get( + 'res.config.settings', 'color_letter_reservation_pay') + else: + reserv_color = ir_values_obj.get( + 'res.config.settings', 'color_reservation') + reserv_color_text = ir_values_obj.get( + 'res.config.settings', 'color_letter_reservation') + elif self.state == 'booking': + if self.folio_id.invoices_amount == 0: + reserv_color = ir_values_obj.get( + 'res.config.settings', 'color_stay_pay') + reserv_color_text = ir_values_obj.get( + 'res.config.settings', 'color_letter_stay_pay') + else: + reserv_color = ir_values_obj.get( + 'res.config.settings', 'color_stay') + reserv_color_text = ir_values_obj.get( + 'res.config.settings', 'color_letter_stay') + else: + if self.folio_id.invoices_amount == 0: + reserv_color = ir_values_obj.get( + 'res.config.settings', 'color_checkout') + reserv_color_text = ir_values_obj.get( + 'res.config.settings', 'color_letter_checkout') + else: + reserv_color = ir_values_obj.get( + 'res.config.settings', 'color_payment_pending') + reserv_color_text = ir_values_obj.get( + 'res.config.settings', 'color_letter_payment_pending') + return (reserv_color, reserv_color_text) + + @api.depends('state', 'reservation_type', 'folio_id.invoices_amount', 'to_assign') + def _compute_color(self): + _logger.info('_compute_color') + for rec in self: + colors = rec._generate_color() + rec.update({ + 'reserve_color': colors[0], + 'reserve_color_text': colors[1], + }) + rec.folio_id.color = colors[0] + + # hotel_reserv_obj = self.env['hotel.reservation'] + # if rec.splitted: + # master_reservation = rec.parent_reservation or rec + # splitted_reservs = hotel_reserv_obj.search([ + # ('splitted', '=', True), + # '|', ('parent_reservation', '=', master_reservation.id), + # ('id', '=', master_reservation.id), + # ('folio_id', '=', rec.folio_id.id), + # ('id', '!=', rec.id), + # ]) + # splitted_reservs.write({'reserve_color': rec.reserve_color}) + + @api.multi + def copy(self, default=None): + ''' + @param self: object pointer + @param default: dict of default values to be set + ''' + + return super(HotelReservation, self).copy(default=default) + + @api.multi + def _amount_line(self, field_name, arg): + ''' + @param self: object pointer + @param field_name: Names of fields. + @param arg: User defined arguments + ''' + return False + # return self.env['sale.order.line']._amount_line(field_name, arg) + + @api.multi + def _number_packages(self, field_name, arg): + ''' + @param self: object pointer + @param field_name: Names of fields. + @param arg: User defined arguments + ''' + return False + # return self.env['sale.order.line']._number_packages(field_name, arg) + + @api.multi + def set_call_center_user(self): + user = self.env['res.users'].browse(self.env.uid) + rec.call_center = user.has_group('hotel.group_hotel_call') + + @api.multi + def _get_default_checkin(self): + folio = False + default_arrival_hour = self.env['ir.default'].sudo().get( + 'res.config.settings', 'default_arrival_hour') + if 'folio_id' in self._context: + folio = self.env['hotel.folio'].search([ + ('id', '=', self._context['folio_id']) + ]) + if folio and folio.room_lines: + return folio.room_lines[0].checkin + else: + tz_hotel = self.env['ir.default'].sudo().get( + 'res.config.settings', 'tz_hotel') + now_utc_dt = date_utils.now() + ndate = "%s %s:00" % \ + (now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), + default_arrival_hour) + ndate_dt = date_utils.get_datetime(ndate, stz=tz_hotel) + ndate_dt = date_utils.dt_as_timezone(ndate_dt, 'UTC') + return ndate_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + + @api.model + def _get_default_checkout(self): + folio = False + default_departure_hour = self.env['ir.default'].sudo().get( + 'res.config.settings', 'default_departure_hour') + if 'folio_id' in self._context: + folio = self.env['hotel.folio'].search([ + ('id', '=', self._context['folio_id']) + ]) + if folio and folio.room_lines: + return folio.room_lines[0].checkout + else: + tz_hotel = self.env['ir.default'].sudo().get( + 'res.config.settings', 'tz_hotel') + now_utc_dt = date_utils.now() + timedelta(days=1) + ndate = "%s %s:00" % \ + (now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), + default_departure_hour) + ndate_dt = date_utils.get_datetime(ndate, stz=tz_hotel) + ndate_dt = date_utils.dt_as_timezone(ndate_dt, 'UTC') + return ndate_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + + # @api.constrains('checkin', 'checkout') #Why dont run api.depends?¿? + # def _computed_nights(self): + # for res in self: + # if res.checkin and res.checkout: + # nights = days_diff = date_utils.date_diff( + # self.checkin, + # self.checkout, hours=False) + # res.nights = nights + + @api.model + def name_search(self, name='', args=None, operator='ilike', limit=100): + if args is None: + args = [] + if not(name == '' and operator == 'ilike'): + args += [ + '|', + ('folio_id.name', operator, name) + # FIXME Remove product inheritance + # ('product_id.name', operator, name) + ] + return super(HotelReservation, self).name_search( + name='', args=args, operator='ilike', limit=limit) + + @api.multi + def name_get(self): + # FIXME Remove product inheritance + result = [] + for res in self: + name = u'%s (%s)' % (res.folio_id.name, res.room_id.name) + result.append((res.id, name)) + return result + + # FIXME added for migration + def _compute_qty_delivered_updateable(self): + pass + # FIXME added for migration + def _compute_invoice_status(self): + pass + + _name = 'hotel.reservation' + _description = 'Hotel Reservation' + _inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin'] + _order = "last_updated_res desc, name" + + # The record's name should now be used for description of the reservation ? + name = fields.Text('Reservation Description', required=True) + + # _defaults = { + # 'product_id': False + # } + + room_id = fields.Many2one('hotel.room', string='Room') + + + reservation_no = fields.Char('Reservation No', size=64, readonly=True) + adults = fields.Integer('Adults', size=64, readonly=False, + track_visibility='onchange', + help='List of adults there in guest list. ') + children = fields.Integer('Children', size=64, readonly=False, + track_visibility='onchange', + help='Number of children there in guest list.') + to_assign = fields.Boolean('To Assign', track_visibility='onchange') + state = fields.Selection([('draft', 'Pre-reservation'), ('confirm', 'Pending Entry'), + ('booking', 'On Board'), ('done', 'Out'), + ('cancelled', 'Cancelled')], + 'State', readonly=True, + default=lambda *a: 'draft', + track_visibility='onchange') + reservation_type = fields.Selection(related='folio_id.reservation_type', + default=lambda *a: 'normal') + cancelled_reason = fields.Selection([ + ('late', 'Late'), + ('intime', 'In time'), + ('noshow', 'No Show')], 'Cause of cancelled') + out_service_description = fields.Text('Cause of out of service') + + folio_id = fields.Many2one('hotel.folio', string='Folio', + ondelete='cascade') + + checkin = fields.Datetime('Check In', required=True, + default=_get_default_checkin, + track_visibility='onchange') + checkout = fields.Datetime('Check Out', required=True, + default=_get_default_checkout, + track_visibility='onchange') + room_type_id = fields.Many2one('hotel.room.type', string='Room Type', + required=True, track_visibility='onchange') + partner_id = fields.Many2one(related='folio_id.partner_id') + company_id = fields.Many2one('res.company', 'Company') + reservation_line_ids = fields.One2many('hotel.reservation.line', + 'reservation_id', + readonly=True, required=True, + states={ + 'draft': [('readonly', False)], + 'sent': [('readonly', False)], + 'confirm': [('readonly', False)], + 'booking': [('readonly', False)], + }) + reserve_color = fields.Char(compute='_compute_color', string='Color', + store=True) + reserve_color_text = fields.Char(compute='_compute_color', string='Color', + store=True) + service_line_ids = fields.One2many('hotel.service', 'ser_room_line') + + # pricelist_id = fields.Many2one('product.pricelist', + # related='folio_id.pricelist_id', + # readonly="1") + cardex_ids = fields.One2many('cardex', 'reservation_id') + # TODO: As cardex_count is a computed field, it can't not be used in a domain filer + # Non-stored field hotel.reservation.cardex_count cannot be searched + # searching on a computed field can also be enabled by setting the search parameter. + # The value is a method name returning a Domains + cardex_count = fields.Integer('Cardex counter', + compute='_compute_cardex_count') + cardex_pending = fields.Boolean('Cardex Pending', + compute='_compute_cardex_count', + search='_search_cardex_pending') + cardex_pending_num = fields.Integer('Cardex Pending Num', + compute='_compute_cardex_count') + # check_rooms = fields.Boolean('Check Rooms') + is_checkin = fields.Boolean() + is_checkout = fields.Boolean() + splitted = fields.Boolean('Splitted', default=False) + parent_reservation = fields.Many2one('hotel.reservation', + 'Parent Reservation') + overbooking = fields.Boolean('Is Overbooking', default=False) + # To show de total amount line in read_only mode + amount_reservation = fields.Float('Total', + compute='_computed_amount_reservation', + store=True) + amount_reservation_services = fields.Float('Services Amount', + compute='_computed_amount_reservation', + store=True) + amount_room = fields.Float('Amount Room', compute="_computed_amount_reservation", + store=True) + amount_discount = fields.Float('Room with Discount', compute="_computed_amount_reservation", + store=True) + discount_type = fields.Selection([ + ('percent', 'Percent'), + ('fixed', 'Fixed')], 'Discount Type', default=lambda *a: 'percent') + discount_fixed = fields.Float('Fixed Discount') + + nights = fields.Integer('Nights', compute='_computed_nights', store=True) + channel_type = fields.Selection([ + ('door', 'Door'), + ('mail', 'Mail'), + ('phone', 'Phone'), + ('call', 'Call Center'), + ('web', 'Web')], 'Sales Channel', default='door') + last_updated_res = fields.Datetime('Last Updated') + # Monetary to Float + folio_pending_amount = fields.Float(related='folio_id.invoices_amount') + segmentation_ids = fields.Many2many(related='folio_id.segmentation_ids') + shared_folio = fields.Boolean(compute='_computed_shared') + #Used to notify is the reservation folio has other reservations or services + email = fields.Char('E-mail', related='partner_id.email') + mobile = fields.Char('Mobile', related='partner_id.mobile') + phone = fields.Char('Phone', related='partner_id.phone') + partner_internal_comment = fields.Text(string='Internal Partner Notes', + related='partner_id.comment') + folio_internal_comment = fields.Text(string='Internal Folio Notes', + related='folio_id.internal_comment') + preconfirm = fields.Boolean('Auto confirm to Save', default=True) + call_center = fields.Boolean(compute='set_call_center_user') + to_send = fields.Boolean('To Send', default=True) + has_confirmed_reservations_to_send = fields.Boolean( + related='folio_id.has_confirmed_reservations_to_send', + readonly=True) + has_cancelled_reservations_to_send = fields.Boolean( + related='folio_id.has_cancelled_reservations_to_send', + readonly=True) + has_checkout_to_send = fields.Boolean( + related='folio_id.has_checkout_to_send', + readonly=True) + # fix_total = fields.Boolean(compute='_compute_fix_total') + # fix_folio_pending = fields.Boolean(related='folio_id.fix_price') + + # order_line = fields.One2many('sale.order.line', 'order_id', string='Order Lines', states={'cancel': [('readonly', True)], 'done': [('readonly', True)]}, copy=True, auto_join=True) + # product_id = fields.Many2one('product.product', related='order_line.product_id', string='Product') + # product_uom = fields.Many2one('product.uom', string='Unit of Measure', required=True) + # product_uom_qty = fields.Float(string='Quantity', digits=dp.get_precision('Product Unit of Measure'), required=True, default=1.0) + + # currency_id = fields.Many2one('res.currency', + # related='pricelist_id.currency_id', + # string='Currency', readonly=True, required=True) + # invoice_status = fields.Selection([ + # ('upselling', 'Upselling Opportunity'), + # ('invoiced', 'Fully Invoiced'), + # ('to invoice', 'To Invoice'), + # ('no', 'Nothing to Invoice') + # ], string='Invoice Status', compute='_compute_invoice_status', store=True, readonly=True, default='no') + tax_id = fields.Many2many('account.tax', string='Taxes', domain=['|', ('active', '=', False), ('active', '=', True)]) + # qty_to_invoice = fields.Float( + # string='To Invoice', store=True, readonly=True, + # digits=dp.get_precision('Product Unit of Measure')) + # qty_invoiced = fields.Float( + # compute='_get_invoice_qty', string='Invoiced', store=True, readonly=True, + # digits=dp.get_precision('Product Unit of Measure')) + # qty_delivered = fields.Float(string='Delivered', copy=False, digits=dp.get_precision('Product Unit of Measure'), default=0.0) + # qty_delivered_updateable = fields.Boolean(compute='_compute_qty_delivered_updateable', string='Can Edit Delivered', readonly=True, default=True) + price_unit = fields.Float('Unit Price', required=True, digits=dp.get_precision('Product Price'), default=0.0) + # Monetary to Float + price_subtotal = fields.Float(compute='_compute_amount', string='Subtotal', readonly=True, store=True) + # Monetary to Float + price_total = fields.Float(compute='_compute_amount', string='Total', readonly=True, store=True) + + # FIXME discount per night + # discount = fields.Float(string='Discount (%)', digits=dp.get_precision('Discount'), default=0.0) + + # analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tags') + + + def action_recalcule_payment(self): + for record in self: + for res in record.folio_id.room_lines: + res.on_change_checkin_checkout_product_id() + + def _computed_folio_name(self): + for res in self: + res.folio_name = res.folio_id.name + '-' + \ + res.folio_id.date_order + + @api.multi + def send_reservation_mail(self): + return self.folio_id.send_reservation_mail() + + @api.multi + def send_exit_mail(self): + return self.folio_id.send_exit_mail() + + @api.multi + def send_cancel_mail(self): + return self.folio_id.send_cancel_mail() + + @api.multi + def action_checks(self): + self.ensure_one() + return { + 'name': _('Cardexs'), + 'view_type': 'form', + 'view_mode': 'tree,form', + 'res_model': 'cardex', + 'type': 'ir.actions.act_window', + 'domain': [('reservation_id', '=', self.id)], + 'target': 'new', + } + + @api.multi + def _computed_shared(self): + for record in self: + if record.folio_id: + if len(record.folio_id.room_lines) > 1 or \ + record.folio_id.service_line_ids.filtered(lambda x: ( + x.ser_room_line != record.id)): + record.shared_folio = True + else: + record.shared_folio = False + + @api.depends('checkin', 'checkout') + def _computed_nights(self): + for res in self: + if res.checkin and res.checkout: + nights = days_diff = date_utils.date_diff( + res.checkin, + res.checkout, hours=False) + res.nights = nights + + @api.model + def recompute_reservation_totals(self): + reservations = self.env['hotel.reservation'].search([]) + for res in reservations: + if res.folio_id.state not in ('done','cancel'): + _logger.info('---------BOOK-----------') + _logger.info(res.amount_reservation) + _logger.info(res.id) + res._computed_amount_reservation() + _logger.info(res.amount_reservation) + _logger.info('---------------------------') + + @api.depends('reservation_line_ids.price') + def _computed_amount_reservation(self): + _logger.info('_computed_amount_reservation') + # FIXME commented during migration + # import wdb; wdb.set_trace() + # for res in self: + # amount_service = amount_room = 0 + # for line in res.reservation_line_ids: + # amount_room += line.price + # for service in res.service_line_ids: + # # We must calc the line to can show the price in edit mode + # # on smartbutton whithout having to wait to save. + # total_line = service.price_unit * service.product_uom_qty + # discount = (service.discount * total_line) / 100 + # amount_service += total_line - discount + # res.amount_room = amount_room #To view price_unit with read_only + # if res.discount_type == 'fixed' and amount_room > 0: + # res.discount = (res.discount_fixed * 100) / amount_room # WARNING Posible division by zero + # else: + # res.discount_fixed = (res.discount * amount_room) / 100 + # res.amount_discount = amount_room - res.discount_fixed + # res.price_unit = amount_room + # res.amount_reservation_services = amount_service + # res.amount_reservation = res.amount_discount + amount_service #To the smartbutton + + @api.multi + def _compute_cardex_count(self): + _logger.info('_compute_cardex_count') + for res in self: + res.cardex_count = len(res.cardex_ids) + res.cardex_pending_num = (res.adults + res.children) \ + - len(res.cardex_ids) + if (res.adults + res.children - len(res.cardex_ids)) <= 0: + res.cardex_pending = False + else: + res.cardex_pending = True + + # https://www.odoo.com/es_ES/forum/ayuda-1/question/calculated-fields-in-search-filter-possible-118501 + @api.multi + def _search_cardex_pending(self, operator, value): + recs = self.search([]).filtered(lambda x: x.cardex_pending is True) + if recs: + return [('id', 'in', [x.id for x in recs])] + + @api.multi + def action_pay_folio(self): + self.ensure_one() + return self.folio_id.action_pay() + + @api.multi + def action_pay_reservation(self): + self.ensure_one() + partner = self.partner_id.id + amount = min(self.amount_reservation, self.folio_pending_amount) + note = self.folio_id.name + ' (' + self.name + ')' + view_id = self.env.ref('hotel.view_account_payment_folio_form').id + return{ + 'name': _('Register Payment'), + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'account.payment', + 'type': 'ir.actions.act_window', + 'view_id': view_id, + 'context': { + 'default_folio_id': self.folio_id.id, + 'default_room_id': self.id, + 'default_amount': amount, + 'default_payment_type': 'inbound', + 'default_partner_type': 'customer', + 'default_partner_id': partner, + 'default_communication': note, + }, + 'target': 'new', + } + + @api.model + def daily_plan(self): + _logger.info('daily_plan') + today_utc_dt = date_utils.now() + yesterday_utc_dt = today_utc_dt - timedelta(days=1) + hotel_tz = self.env['ir.default'].sudo().get('res.config.settings', + 'tz_hotel') + today_dt = date_utils.dt_as_timezone(today_utc_dt, hotel_tz) + yesterday_dt = date_utils.dt_as_timezone(yesterday_utc_dt, hotel_tz) + + today_str = today_dt.strftime(DEFAULT_SERVER_DATE_FORMAT) + yesterday_str = yesterday_dt.strftime(DEFAULT_SERVER_DATE_FORMAT) + reservations_to_checkout = self.env['hotel.reservation'].search([ + ('state', 'not in', ['done']), + ('checkout', '<', today_str) + ]) + for res in reservations_to_checkout: + res.action_reservation_checkout() + + reservations = self.env['hotel.reservation'].search([ + ('reservation_line_ids.date', 'in', [today_str, + yesterday_str]), + ('state', 'in', ['confirm', 'booking']) + ]) + self._cr.execute("update hotel_reservation set is_checkin = False, \ + is_checkout = False where is_checkin = True or \ + is_checkout = True") + checkins_res = reservations.filtered(lambda x: ( + x.state in ('confirm','draft') + and date_utils.date_compare(x.checkin, today_str, hours=False) + and x.reservation_type == 'normal')) + checkins_res.write({'is_checkin': True}) + checkouts_res = reservations.filtered(lambda x: ( + x.state not in ('done','cancelled') + and date_utils.date_compare(x.checkout, today_str, + hours=False) + and x.reservation_type == 'normal')) + checkouts_res.write({'is_checkout': True}) + self.env['hotel.folio'].daily_plan() + return True + + @api.model + def checkin_is_today(self): + self.ensure_one() + date_now_str = date_utils.now().strftime( + DEFAULT_SERVER_DATE_FORMAT) + return date_utils.date_compare(self.checkin, date_now_str, hours=False) + + @api.model + def checkout_is_today(self): + self.ensure_one() + date_now_str = date_utils.now().strftime( + DEFAULT_SERVER_DATE_FORMAT) + return date_utils.date_compare(self.checkout, date_now_str, + hours=False) + + @api.multi + def action_cancel(self): + for record in self: + record.write({ + 'state': 'cancelled', + 'discount': 100.0, + }) + if record.checkin_is_today: + record.is_checkin = False + folio = self.env['hotel.folio'].browse(record.folio_id.id) + folio.checkins_reservations = folio.room_lines.search_count([ + ('folio_id', '=', folio.id), + ('is_checkin', '=', True) + ]) + + if record.splitted: + master_reservation = record.parent_reservation or record + splitted_reservs = self.env['hotel.reservation'].search([ + ('splitted', '=', True), + '|', ('parent_reservation', '=', master_reservation.id), + ('id', '=', master_reservation.id), + ('folio_id', '=', record.folio_id.id), + ('id', '!=', record.id), + ('state', '!=', 'cancelled') + ]) + splitted_reservs.action_cancel() + record.folio_id.compute_invoices_amount() + + @api.multi + def draft(self): + for record in self: + record.write({'state': 'draft'}) + + if record.splitted: + master_reservation = record.parent_reservation or record + splitted_reservs = self.env['hotel.reservation'].search([ + ('splitted', '=', True), + '|', ('parent_reservation', '=', master_reservation.id), + ('id', '=', master_reservation.id), + ('folio_id', '=', record.folio_id.id), + ('id', '!=', record.id), + ('state', '!=', 'draft') + ]) + splitted_reservs.draft() + + @api.multi + def action_reservation_checkout(self): + for record in self: + record.state = 'done' + if record.checkout_is_today(): + record.is_checkout = False + folio = self.env['hotel.folio'].browse(self.folio_id.id) + folio.checkouts_reservations = folio.room_lines.search_count([ + ('folio_id', '=', folio.id), + ('is_checkout', '=', True) + ]) + + @api.multi + def overbooking_button(self): + self.ensure_one() + return self.write({'overbooking': not self.overbooking}) + + @api.multi + def open_master(self): + self.ensure_one() + if not self.parent_reservation: + raise ValidationError(_("This is the parent reservation")) + action = self.env.ref('hotel.open_hotel_reservation_form_tree_all').read()[0] + action['views'] = [(self.env.ref('hotel.view_hotel_reservation_form').id, 'form')] + action['res_id'] = self.parent_reservation.id + return action + + @api.multi + def open_folio(self): + action = self.env.ref('hotel.open_hotel_folio1_form_tree_all').read()[0] + if self.folio_id: + action['views'] = [(self.env.ref('hotel.view_hotel_folio1_form').id, 'form')] + action['res_id'] = self.folio_id.id + else: + action = {'type': 'ir.actions.act_window_close'} + return action + + @api.multi + def open_reservation_form(self): + action = self.env.ref('hotel.open_hotel_reservation_form_tree_all').read()[0] + action['views'] = [(self.env.ref('hotel.view_hotel_reservation_form').id, 'form')] + action['res_id'] = self.id + return action + + @api.multi + def get_real_checkin_checkout(self): + self.ensure_one() + if not self.splitted: + return (self.checkin, self.checkout) + + master_reservation = self.parent_reservation or self + splitted_reservs = self.env['hotel.reservation'].search([ + ('splitted', '=', True), + ('folio_id', '=', self.folio_id.id), + '|', + ('parent_reservation', '=', master_reservation.id), + ('id', '=', master_reservation.id) + ]) + last_checkout = splitted_reservs[0].checkout + first_checkin = splitted_reservs[0].checkin + for reserv in splitted_reservs: + if last_checkout < reserv.checkout: + last_checkout = reserv.checkout + if first_checkin > reserv.checkin: + first_checkin = reserv.checkin + return (first_checkin, last_checkout) + + @api.multi + def unify(self): + # FIXME Remove product inheritance + pass + # self.ensure_one() + # if not self.splitted: + # raise ValidationError(_("This reservation can't be unified")) + # + # master_reservation = self.parent_reservation or self + # self_is_master = (master_reservation == self) + # + # splitted_reservs = self.env['hotel.reservation'].search([ + # ('splitted', '=', True), + # ('folio_id', '=', self.folio_id.id), + # '|', + # ('parent_reservation', '=', master_reservation.id), + # ('id', '=', master_reservation.id) + # ]) + # + # rooms_products = splitted_reservs.mapped('product_id.id') + # if len(rooms_products) > 1 or \ + # (len(rooms_products) == 1 + # and master_reservation.product_id.id != rooms_products[0]): + # raise ValidationError(_("This reservation can't be unified: They \ + # all need to be in the same room")) + # + # # Search checkout + # last_checkout = splitted_reservs[0].checkout + # for reserv in splitted_reservs: + # if last_checkout < reserv.checkout: + # last_checkout = reserv.checkout + # + # # Agrupate reservation lines + # reservation_line_ids = splitted_reservs.mapped('reservation_line_ids') + # reservation_line_ids.sorted(key=lambda r: r.date) + # rlines = [(5, False, False)] + # tprice = 0.0 + # for rline in reservation_line_ids: + # rlines.append((0, False, { + # 'date': rline.date, + # 'price': rline.price, + # })) + # tprice += rline.price + # + # # Unify + # folio = self.folio_id # FIX: To Allow Unify confirm reservations + # state = folio.state # FIX + # folio.state = 'draft' # FIX + # osplitted_reservs = splitted_reservs - master_reservation + # osplitted_reservs.sudo().unlink() + # folio.state = state # FIX + # + # # FIXME: Two writes because checkout regenerate reservation lines + # master_reservation.write({ + # 'checkout': last_checkout, + # 'splitted': False, + # }) + # master_reservation.write({ + # 'reservation_line_ids': rlines, + # 'price_unit': tprice, + # }) + # if not self_is_master: + # return {'type': 'ir.actions.act_window_close'} + # return True + # + # ''' + # Created this because "copy()" function create a new record + # and collide with date restrictions. + # This function generate a usable dictionary with reservation values + # for copy purposes. + # ''' + @api.multi + def generate_copy_values(self, checkin=False, checkout=False): + self.ensure_one() + return { + 'name': self.name, + 'adults': self.adults, + 'children': self.children, + 'checkin': checkin or self.checkin, + 'checkout': checkout or self.checkout, + 'folio_id': self.folio_id.id, + # 'product_id': self.product_id.id, + 'parent_reservation': self.parent_reservation.id, + 'state': self.state, + 'overbooking': self.overbooking, + 'price_unit': self.price_unit, + 'splitted': self.splitted, + # 'virtual_room_id': self.virtual_room_id.id, + 'room_type_id': self.room_type_id.id, + } + + @api.model + def create(self, vals): + """ + Overrides orm create method. + @param self: The object pointer + @param vals: dictionary of fields value. + @return: new record set for hotel folio line. + """ + # import wdb; wdb.set_trace() + if not 'reservation_type' in vals or not vals.get('reservation_type'): + vals.update({'reservation_type': 'normal'}) + if 'folio_id' in vals: + folio = self.env["hotel.folio"].browse(vals['folio_id']) + # vals.update({'order_id': folio.order_id.id, + # 'channel_type': folio.channel_type}) + vals.update({'channel_type': folio.channel_type}) + elif 'partner_id' in vals: + folio_vals = {'partner_id':int(vals.get('partner_id')), + 'channel_type': vals.get('channel_type')} + folio = self.env["hotel.folio"].create(folio_vals) + # vals.update({'order_id': folio.order_id.id, + # 'folio_id': folio.id, + # 'reservation_type': vals.get('reservation_type'), + # 'channel_type': vals.get('channel_type')}) + vals.update({'folio_id': folio.id, + 'reservation_type': vals.get('reservation_type'), + 'channel_type': vals.get('channel_type')}) + user = self.env['res.users'].browse(self.env.uid) + if user.has_group('hotel.group_hotel_call'): + vals.update({'to_assign': True, + 'channel_type': 'call'}) + vals.update({ + 'last_updated_res': date_utils.now(hours=True).strftime(DEFAULT_SERVER_DATETIME_FORMAT) + }) + if folio: + record = super(HotelReservation, self).create(vals) + # Check Capacity + # NOTE the room is not a product anymore + # room = self.env['hotel.room'].search([ + # ('product_id', '=', record.product_id.id) + # ]) + #persons = record.adults # Not count childrens + if record.adults > record.room_id.capacity: + raise ValidationError( + _("Reservation persons can't be higher than room capacity")) + if record.adults == 0: + raise ValidationError(_("Reservation has no adults")) + if (record.state == 'draft' and record.folio_id.state == 'sale') or \ + record.preconfirm: + record.confirm() + record._compute_color() + return record + + @api.multi + def write(self, vals): + for record in self: + if ('checkin' in vals and record.checkin != vals['checkin']) or \ + ('checkout' in vals and record.checkout != vals['checkout']) or \ + ('state' in vals and record.state != vals['state']) or \ + ('amount_discount' in vals and record.amount_discount != vals['amount_discount']): + vals.update({'to_send': True}) + + pricesChanged = ('checkin' in vals or \ + 'checkout' in vals or \ + 'discount' in vals) + # vals.update({ + # 'edit_room': False, + # }) + # if pricesChanged or 'state' in vals or 'virtual_room_id' in vals or 'to_assign' in vals: + if pricesChanged or 'state' in vals or 'room_type_id' in vals or 'to_assign' in vals: + vals.update({ + 'last_updated_res': date_utils.now(hours=True).strftime(DEFAULT_SERVER_DATETIME_FORMAT) + }) + user = self.env['res.users'].browse(self.env.uid) + if user.has_group('hotel.group_hotel_call'): + vals.update({ + 'to_read': True, + 'to_assign': True, + }) + res = super(HotelReservation, self).write(vals) + if pricesChanged: + for record in self: + if record.reservation_type in ('staff', 'out'): + record.update({'price_unit': 0}) + record.folio_id.compute_invoices_amount() + checkin = vals.get('checkin', record.checkin) + checkout = vals.get('checkout', record.checkout) + days_diff = date_utils.date_diff(checkin, + checkout, hours=False) + rlines = record.prepare_reservation_lines(checkin, days_diff) + record.update({ + 'reservation_line_ids': rlines['commands'], + 'price_unit': rlines['total_price'], + }) + return res + + # @api.multi + # def uos_change(self, product_uos, product_uos_qty=0, product_id=None): + # ''' + # @param self: object pointer + # ''' + # # for folio in self: + # # line = folio.order_line_id + # # line.uos_change(product_uos, product_uos_qty=0, + # # product_id=None) + # return True + + # FIXME add room.id to on change after removing inheritance + @api.onchange('adults', 'children') + def check_capacity(self): + if self.room_id: + persons = self.adults + self.children + if self.room_id.capacity < persons: + self.adults = self.room_id.capacity + self.children = 0 + raise UserError( + _('%s people do not fit in this room! ;)') % (persons)) + + @api.onchange('room_type_id') + # def on_change_virtual_room_id(self): + def on_change_room_type_id(self): + if not self.checkin: + self.checkin = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + if not self.checkout: + self.checkout = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + days_diff = date_utils.date_diff( + self.checkin, self.checkout, hours=False) + rlines = self.prepare_reservation_lines( + self.checkin, + days_diff, + update_old_prices=True) + self.reservation_line_ids = rlines['commands'] + + if self.reservation_type in ['staff', 'out']: + self.price_unit = 0.0 + self.cardex_pending = 0 + else: + self.price_unit = rlines['total_price'] + + @api.onchange('checkin', 'checkout', 'room_id', + 'reservation_type', 'room_type_id') + def on_change_checkin_checkout_product_id(self): + _logger.info('on_change_checkin_checkout_product_id') + # import wdb; wdb.set_trace() + if not self.checkin: + self.checkin = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + if not self.checkout: + self.checkout = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + # WARNING Need a review + # if self.product_id: + # self.tax_id = [(6, False, self.virtual_room_id.product_id.taxes_id.ids)] + # room = self.env['hotel.room'].search([ + # ('product_id', '=', self.product_id.id) + # ]) + # if self.adults == 0: + # self.adults = room.capacity + # if not self.virtual_room_id and room.price_virtual_room: + # self.virtual_room_id = room.price_virtual_room.id + if self.room_id: + # self.tax_id = [(6, False, self.room_type_id.product_id.taxes_id.ids)] + if self.adults == 0: + self.adults = self.room_id.capacity + if not self.room_type_id: + self.room_type_id = self.room_id.room_type_id + self.tax_id = [(6, False, self.room_id.room_type_id.taxes_id.ids)] + + # UTC -> Hotel tz + tz = self.env['ir.default'].sudo().get('res.config.settings', + 'tz_hotel') + chkin_utc_dt = date_utils.get_datetime(self.checkin) + chkout_utc_dt = date_utils.get_datetime(self.checkout) + + if self.room_type_id: + checkin_str = chkin_utc_dt.strftime('%d/%m/%Y') + checkout_str = chkout_utc_dt.strftime('%d/%m/%Y') + self.name = self.room_type_id.name + ': ' + checkin_str + ' - '\ + + checkout_str + # self.product_uom = self.product_id.uom_id + + if chkin_utc_dt >= chkout_utc_dt: + dpt_hour = self.env['ir.default'].sudo().get( + 'res.config.settings', 'default_departure_hour') + checkout_str = (chkin_utc_dt + timedelta(days=1)).strftime( + DEFAULT_SERVER_DATE_FORMAT) + checkout_str = "%s %s:00" % (checkout_str, dpt_hour) + checkout_dt = date_utils.get_datetime(checkout_str, stz=tz) + checkout_utc_dt = date_utils.dt_as_timezone(checkout_dt, 'UTC') + self.checkout = checkout_utc_dt.strftime( + DEFAULT_SERVER_DATETIME_FORMAT) + + if self.state == 'confirm' and self.checkin_is_today(): + self.is_checkin = True + folio = self.env['hotel.folio'].browse(self.folio_id.id) + if folio: + folio.checkins_reservations = folio.room_lines.search_count([ + ('folio_id', '=', folio.id), ('is_checkin', '=', True) + ]) + + if self.state == 'booking' and self.checkout_is_today(): + self.is_checkout = False + folio = self.env['hotel.folio'].browse(self.folio_id.id) + if folio: + folio.checkouts_reservations = folio.room_lines.search_count([ + ('folio_id', '=', folio.id), ('is_checkout', '=', True) + ]) + + days_diff = date_utils.date_diff( + self.checkin, self.checkout, hours=False) + rlines = self.prepare_reservation_lines( + self.checkin, + days_diff, + update_old_prices=False) + self.reservation_line_ids = rlines['commands'] + + if self.reservation_type in ['staff', 'out']: + self.price_unit = 0.0 + self.cardex_pending = 0 + else: + self.price_unit = rlines['total_price'] + + # FIXME add room.id to on change after removing inheritance + @api.model + def get_availability(self, checkin, checkout, dbchanged=True, + dtformat=DEFAULT_SERVER_DATE_FORMAT): + date_start = date_utils.get_datetime(checkin) + date_end = date_utils.get_datetime(checkout) + # Not count end day of the reservation + date_diff = date_utils.date_diff(date_start, date_end, hours=False) + + hotel_vroom_obj = self.env['hotel.room.type'] + # virtual_room_avail_obj = self.env['hotel.room.type.availability'] + + rooms_avail = [] + # FIXME con una relacion Many2one, cada habitacion está en un solo tipo + # por lo que la disponibilidad para la habitación se tiene que buscar + # directamente en ese tipo + # vrooms = hotel_vroom_obj.search([ + # ('room_ids.product_id', '=', self.room_id) + # ]) + # FIXME Si lo de arriba es cierto, este bucle sobra. Sólo hay un room_type_id + for vroom in self.room_type_id: + rdays = [] + for i in range(0, date_diff): + ndate_dt = date_start + timedelta(days=i) + ndate_str = ndate_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + avail = len(hotel_vroom_obj.check_availability_virtual_room( + ndate_str, + ndate_str, + room_type_id=vroom.id)) + if not dbchanged: + avail = avail - 1 + # Can be less than zero because 'avail' can not equal + # with the real 'avail' (ex. Online Limits) + avail = max(min(avail, vroom.total_rooms_count), 0) + rdays.append({ + 'date': ndate_dt.strftime(dtformat), + 'avail': avail, + }) + ravail = {'id': vroom.id, 'days': rdays} + rooms_avail.append(ravail) + + return rooms_avail + + @api.multi + def prepare_reservation_lines(self, str_start_date_utc, days, + update_old_prices=False): + self.ensure_one() + total_price = 0.0 + cmds = [(5, False, False)] + # TO-DO: Redesign relation between hotel.reservation + # and sale.order.line to allow manage days by units in order + #~ if self.invoice_status == 'invoiced' and not self.splitted: + #~ raise ValidationError(_("This reservation is already invoiced. \ + #~ To expand it you must create a new reservation.")) + hotel_tz = self.env['ir.default'].sudo().get( + 'res.config.settings', 'hotel_tz') + start_date_utc_dt = date_utils.get_datetime(str_start_date_utc) + start_date_dt = date_utils.dt_as_timezone(start_date_utc_dt, hotel_tz) + + # import wdb; wdb.set_trace() + + # room = self.env['hotel.room'].search([ + # ('product_id', '=', self.product_id.id) + # ]) + # product_id = self.room_id.sale_price_type == 'vroom' and self.room_id.price_virtual_room.product_id + product_id = self.room_type_id + pricelist_id = self.env['ir.default'].sudo().get( + 'res.config.settings', 'parity_pricelist_id') + if pricelist_id: + pricelist_id = int(pricelist_id) + old_lines_days = self.mapped('reservation_line_ids.date') + for i in range(0, days): + ndate = start_date_dt + timedelta(days=i) + ndate_str = ndate.strftime(DEFAULT_SERVER_DATE_FORMAT) + _logger.info('ndate_str: %s', ndate_str) + if update_old_prices or ndate_str not in old_lines_days: + # prod = product_id.with_context( + # lang=self.partner_id.lang, + # partner=self.partner_id.id, + # quantity=1, + # date=ndate_str, + # pricelist=pricelist_id, + # uom=self.product_uom.id) + prod = product_id.with_context( + lang=self.partner_id.lang, + partner=self.partner_id.id, + quantity=1, + date=ndate_str, + pricelist=pricelist_id) + line_price = prod.price + else: + line = self.reservation_line_ids.filtered(lambda r: r.date == ndate_str) + line_price = line.price + cmds.append((0, False, { + 'date': ndate_str, + 'price': line_price + })) + total_price += line_price + return {'total_price': total_price, 'commands': cmds} + + @api.constrains('adults') + def check_adults(self): + if self.adults == 0 and self.room_id: + # room = self.env['hotel.room'].search([ + # ('product_id', '=', self.product_id.id) + # ], limit=1) + self.adults = self.room_id.capacity + + @api.multi + @api.onchange('checkin', 'checkout', 'room_type_id', 'room_id') + def on_change_checkout(self): + ''' + When you change checkin or checkout it will checked it + and update the qty of hotel folio line + ----------------------------------------------------------------- + @param self: object pointer + ''' + _logger.info('on_change_checkout') + self.ensure_one() + now_utc_dt = date_utils.now() + if not self.checkin: + self.checkin = now_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + if not self.checkout: + now_utc_dt = date_utils.get_datetime(self.checkin)\ + + timedelta(days=1) + self.checkout = now_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + if self.overbooking: + return + checkout_dt = date_utils.get_datetime(self.checkout) + occupied = self.env['hotel.reservation'].occupied( + self.checkin, + checkout_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)).filtered( + lambda r: r.id != self._origin.id) + rooms_occupied = occupied.mapped('room_id.id') + if self.room_id and self.room_id.id in rooms_occupied: + warning_msg = _('You tried to change \ + reservation with room those already reserved in this \ + reservation period') + raise ValidationError(warning_msg) + domain_rooms = [ + # ('isroom', '=', True), + ('id', 'not in', rooms_occupied) + ] + # if self.check_rooms: + # if self.room_type_id: + # domain_rooms.append( + # ('categ_id.id', '=', self.room_type_id.cat_id.id) + # ) + # if self.virtual_room_id: + # room_categories = self.virtual_room_id.room_type_ids.mapped( + # 'cat_id.id') + # link_virtual_rooms = self.virtual_room_id.room_ids\ + # | self.env['hotel.room'].search([ + # ('categ_id.id', 'in', room_categories)]) + # room_ids = link_virtual_rooms.mapped('room_id.id') + # domain_rooms.append(('id', 'in', room_ids)) + return {'domain': {'room_id': domain_rooms}} + + @api.multi + def confirm(self): + ''' + @param self: object pointer + ''' + _logger.info('confirm') + hotel_folio_obj = self.env['hotel.folio'] + hotel_reserv_obj = self.env['hotel.reservation'] + for r in self: + vals = {} + if r.cardex_ids: + vals.update({'state': 'booking'}) + else: + vals.update({'state': 'confirm'}) + if r.checkin_is_today(): + vals.update({'is_checkin': True}) + folio = hotel_folio_obj.browse(r.folio_id.id) + folio.checkins_reservations = folio.room_lines.search_count([ + ('folio_id', '=', folio.id), ('is_checkin', '=', True)]) + r.write(vals) + + if r.splitted: + master_reservation = r.parent_reservation or r + splitted_reservs = hotel_reserv_obj.search([ + ('splitted', '=', True), + '|', ('parent_reservation', '=', master_reservation.id), + ('id', '=', master_reservation.id), + ('folio_id', '=', r.folio_id.id), + ('id', '!=', r.id), + ('state', '!=', 'confirm') + ]) + splitted_reservs.confirm() + return True + + @api.multi + def button_done(self): + ''' + @param self: object pointer + ''' + for res in self: + res.action_reservation_checkout() + return True + + @api.one + def copy_data(self, default=None): + ''' + @param self: object pointer + @param default: dict of default values to be set + ''' + return False + # FIXME added for migration + # line_id = self.order_line_id.id + # sale_line_obj = self.env['sale.order.line'].browse(line_id) + # return sale_line_obj.copy_data(default=default) + + @api.constrains('checkin', 'checkout', 'state', 'room_id', 'overbooking') + def check_dates(self): + """ + 1.-When date_order is less then checkin date or + Checkout date should be greater than the checkin date. + 3.-Check the reservation dates are not occuped + """ + chkin_utc_dt = date_utils.get_datetime(self.checkin) + chkout_utc_dt = date_utils.get_datetime(self.checkout) + if chkin_utc_dt >= chkout_utc_dt: + raise ValidationError(_('Room line Check In Date Should be \ + less than the Check Out Date!')) + if not self.overbooking and not self._context.get("ignore_avail_restrictions", False): + occupied = self.env['hotel.reservation'].occupied( + self.checkin, + chkout_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)) + occupied = occupied.filtered( + lambda r: r.room_id.id == self.room_id.id + and r.id != self.id) + occupied_name = ','.join(str(x.room_id.name) for x in occupied) + if occupied: + warning_msg = _('You tried to change/confirm \ + reservation with room those already reserved in this \ + reservation period: %s ') % occupied_name + raise ValidationError(warning_msg) + + @api.multi + def unlink(self): + # for record in self: + # record.order_line_id.unlink() + return super(HotelReservation, self).unlink() + + @api.model + def occupied(self, str_checkin_utc, str_checkout_utc): + """ + Return a RESERVATIONS array between in and out parameters + IMPORTANT: This function should receive the dates in UTC datetime zone, + as String format + """ + tz_hotel = self.env['ir.default'].sudo().get( + 'res.config.settings', 'tz_hotel') + checkin_utc_dt = date_utils.get_datetime(str_checkin_utc) + checkin_dt = date_utils.dt_as_timezone(checkin_utc_dt, tz_hotel) + days_diff = date_utils.date_diff(str_checkin_utc, str_checkout_utc, + hours=False) + dates_list = date_utils.generate_dates_list(checkin_dt, days_diff or 1, + stz=tz_hotel) + reservations = self.env['hotel.reservation'].search([ + ('reservation_line_ids.date', 'in', dates_list), + ('state', '!=', 'cancelled'), + ('overbooking', '=', False) + ]) + return reservations diff --git a/hotel/models/hotel_reservation_line.py b/hotel/models/hotel_reservation_line.py new file mode 100644 index 000000000..256b44cad --- /dev/null +++ b/hotel/models/hotel_reservation_line.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from odoo import models, fields, api, _ +from odoo.addons import decimal_precision as dp + +class HotelReservationLine(models.Model): + _name = "hotel.reservation.line" + _order = "date" + + reservation_id = fields.Many2one('hotel.reservation', string='Reservation', + ondelete='cascade', required=True, + copy=False) + date = fields.Date('Date') + price = fields.Float('Price') + discount = fields.Float( + string='Discount (%)', + digits=dp.get_precision('Discount'), default=0.0) diff --git a/hotel/models/hotel_room.py b/hotel/models/hotel_room.py new file mode 100644 index 000000000..3c6cd26a8 --- /dev/null +++ b/hotel/models/hotel_room.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import models, fields, api, _ + + +class HotelRoom(models.Model): + """ The rooms for lodging can be for sleeping, usually called rooms, and also + for speeches (conference rooms), parking, relax with cafe con leche, spa... + """ + _name = 'hotel.room' + _description = 'Hotel Room' + # The record's name + name = fields.Char('Room Name', required=True) + # Used for activate records + active = fields.Boolean('Active', default=True) + # Used for ordering + sequence = fields.Integer('Sequence', default=0) + + _order = "sequence, room_type_id, name" + + # each room has only one type (Many2one) + room_type_id = fields.Many2one('hotel.room.type', 'Hotel Room Type') + + floor_id = fields.Many2one('hotel.floor', 'Ubication', + help='At which floor the room is located.') + # TODO Q. Should the amenities be on the Room Type ? - + room_amenities = fields.Many2many('hotel.room.amenities', 'temp_tab', + 'room_amenities', 'rcateg_id', + string='Room Amenities', + help='List of room amenities.') + + # default price for this room + list_price = fields.Float(store=True, + string='Room Rate', + help='The room rate is fixed unless a room type' + ' is selected, in which case the rate is taken from' + ' the room type.') + # how to manage the price + # sale_price_type = fields.Selection([ + # ('fixed', 'Fixed Price'), + # ('vroom', 'Room Type'), + # ], 'Price Type', default='fixed', required=True) + # max number of adults and children per room + max_adult = fields.Integer('Max Adult') + max_child = fields.Integer('Max Child') + # maximum capacity of the room + capacity = fields.Integer('Capacity') + # FIXME not used + to_be_cleaned = fields.Boolean('To be Cleaned', default=False) + + shared_room = fields.Boolean('Shared Room', default=False) + + description_sale = fields.Text( + 'Sale Description', translate=True, + help="A description of the Product that you want to communicate to " + " your customers. This description will be copied to every Sales " + " Order, Delivery Order and Customer Invoice/Credit Note") + + + # In case the price is managed from a specific type of room + # price_virtual_room = fields.Many2one( + # 'hotel.virtual.room', + # 'Price Virtual Room', + # help='Price will be based on selected Virtual Room') + + # virtual_rooms = fields.Many2many('hotel.virtual.room', + # string='Virtual Rooms') + # categ_id = fields.Selection([('room', 'Room '), + # ('shared_room', 'Shared Room'), + # ('parking', 'Parking')], + # string='Hotel Lodging Type', + # store=True, default='room') + +# price_virtual_room_domain = fields.Char( +# compute=_compute_price_virtual_room_domain, +# readonly=True, +# store=False, +# ) + +# @api.multi +# @api.depends('categ_id') +# def _compute_price_virtual_room_domain(self): +# for rec in self: +# rec.price_virtual_room_domain = json.dumps( +# ['|', ('room_ids.id', '=', rec.id), ('room_type_ids.cat_id.id', '=', rec.categ_id.id)] +# ) + + # @api.onchange('categ_id') + # def price_virtual_room_domain(self): + # return { + # 'domain': { + # 'price_virtual_room': [ + # '|', ('room_ids.id', '=', self._origin.id), + # ('room_type_ids.cat_id.id', '=', self.categ_id.id) + # ] + # } + # } + + # @api.multi + # def unlink(self): + # for record in self: + # record.product_id.unlink() + # return super(HotelRoom, self).unlink() diff --git a/hotel/models/hotel_room_amenities.py b/hotel/models/hotel_room_amenities.py new file mode 100644 index 000000000..94cb23f25 --- /dev/null +++ b/hotel/models/hotel_room_amenities.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import models, fields, api, _ + + +class HotelRoomAmenities(models.Model): + + _name = 'hotel.room.amenities' + _description = 'Room amenities' + # The record's name + name = fields.Char('Amenity Name', required=True) + # Used for activate records + active = fields.Boolean('Active', default=True) + + default_code = fields.Char('Internal Reference', store=True) + + # room_categ_id = fields.Many2one('product.product', 'Product Category', + # required=True, delegate=True, + # ondelete='cascade') + room_amenities_type_id = fields.Many2one('hotel.room.amenities.type', + 'Amenity Catagory') + + # room_ids = fields.Many2man('hotel.room','Rooms') + + # @api.multi + # def unlink(self): + # # self.room_categ_id.unlink() + # return super(HotelRoomAmenities, self).unlink() diff --git a/hotel/models/hotel_room_amenities_type.py b/hotel/models/hotel_room_amenities_type.py new file mode 100644 index 000000000..878014a44 --- /dev/null +++ b/hotel/models/hotel_room_amenities_type.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import models, fields, api, _ + + +class HotelRoomAmenitiesType(models.Model): + + _name = 'hotel.room.amenities.type' + _description = 'Amenities Type' + # The record's name + name = fields.Char('Amenity Name', required=True) + # Used for activate records + active = fields.Boolean('Active', default=True) + + room_amenities_ids = fields.One2many('hotel.room.amenities', + 'room_amenities_type_id', + 'Amenities in this category') + + # cat_id = fields.Many2one('product.category', 'category', required=True, + # delegate=True, ondelete='cascade') + + # @api.multi + # def unlink(self): + # # self.cat_id.unlink() + # return super(HotelRoomAmenitiesType, self).unlink() diff --git a/hotel/models/hotel_room_type.py b/hotel/models/hotel_room_type.py new file mode 100644 index 000000000..3a889593a --- /dev/null +++ b/hotel/models/hotel_room_type.py @@ -0,0 +1,141 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from decimal import Decimal +from datetime import datetime, timedelta +import dateutil.parser +# For Python 3.0 and later +from urllib.request import urlopen +import time +from odoo.exceptions import except_orm, UserError, ValidationError +from odoo.tools import ( + misc, + DEFAULT_SERVER_DATE_FORMAT, + DEFAULT_SERVER_DATETIME_FORMAT) +from odoo import models, fields, api, _ +from odoo.addons.hotel import date_utils + +from odoo.addons import decimal_precision as dp + +class HotelRoomType(models.Model): + """ Before creating a 'room type', you need to consider the following: + With the term 'room type' is meant a type of residential accommodation: for + example, a Double Room, a Economic Room, an Apartment, a Tent, a Caravan... + """ + _name = "hotel.room.type" + _description = "Room Type" + + _inherits = {'product.product': 'product_id'} + # Relationship between models + product_id = fields.Many2one('product.product', 'Product Room Type', + required=True, delegate=True, + ondelete='cascade') + # cat_id = fields.Many2one('product.category', 'category', required=True, + # delegate=True, index=True, ondelete='cascade') + room_ids = fields.One2many('hotel.room', 'room_type_id', 'Rooms') + + # TODO Hierarchical relationship for parent-child tree ? + # parent_id = fields.Many2one ... + + # Used for activate records + active = fields.Boolean('Active', default=True, + help="The active field allows you to hide the \ + category without removing it.") + # Used for ordering + sequence = fields.Integer('Sequence', default=0) + + code_type = fields.Char('Code') + + _order = "sequence, code_type, name" + + _sql_constraints = [('code_type_unique', 'unique(code_type)', + 'code must be unique!')] + # total number of rooms in this type + total_rooms_count = fields.Integer(compute='_compute_total_rooms') + # FIXING rename to default rooms ? + max_real_rooms = fields.Integer('Default Max Room Allowed') + + @api.depends('room_ids') + def _compute_total_rooms(self): + for record in self: + count = 0 + count += len(record.room_ids) # Rooms linked directly + # room_categories = r.room_type_ids.mapped('room_ids.id') + # count += self.env['hotel.room'].search_count([ + # ('categ_id.id', 'in', room_categories) + # ]) # Rooms linked through room type + record.total_rooms_count = count + + def _check_duplicated_rooms(self): + # FIXME Using a Many2one relationship duplicated should not been possible + pass + + @api.constrains('max_real_rooms', 'room_ids') + def _check_max_rooms(self): + warning_msg = "" + # for r in self: + if self.max_real_rooms > self.total_rooms_count: + warning_msg += _('The Maxime rooms allowed can not be greate \ + than total rooms count') + raise models.ValidationError(warning_msg) + + @api.multi + def get_capacity(self): + # WARNING use selg.capacity directly ? + pass + # self.ensure_one() + # hotel_room_obj = self.env['hotel.room'] + # room_categories = self.room_type_ids.mapped('room_ids.id') + # room_ids = self.room_ids + hotel_room_obj.search([ + # ('categ_id.id', 'in', room_categories) + # ]) + # capacities = room_ids.mapped('capacity') + # return any(capacities) and min(capacities) or 0 + + @api.model + def check_availability_virtual_room(self, checkin, checkout, + room_type_id=False, notthis=[]): + """ + Check the avalability for an specific type of room + @return: A recordset of free rooms ? + """ + occupied = self.env['hotel.reservation'].occupied(checkin, checkout) + rooms_occupied = occupied.mapped('product_id.id') + free_rooms = self.env['hotel.room'].search([ + ('product_id.id', 'not in', rooms_occupied), + ('id', 'not in', notthis) + ]) + if room_type_id: + # hotel_room_obj = self.env['hotel.room'] + room_type_id = self.env['hotel.room.type'].search([ + ('id', '=', room_type_id) + ]) + # room_categories = virtual_room.room_type_ids.mapped('room_ids.id') + # rooms_linked = virtual_room.room_ids | hotel_room_obj.search([ + # ('categ_id.id', 'in', room_categories)]) + # rooms_linked = room_type_id.room_ids + rooms_linked = self.room_ids + free_rooms = free_rooms & rooms_linked + return free_rooms.sorted(key=lambda r: r.sequence) + + @api.model + def create(self, vals): + """ + Overrides orm create method. + @param self: The object pointer + @param vals: dictionary of fields value. + @return: new record set for hotel room type. + """ + vals.update({'is_room_type': True}) + vals.update({'purchase_ok': False}) + vals.update({'type': 'service'}) + return super().create(vals) + + @api.multi + def unlink(self): + for record in self: + # Set fixed price to rooms with price from this virtual rooms + # Remove product.product + record.product_id.unlink() + return super().unlink() diff --git a/hotel/models/hotel_service.py b/hotel/models/hotel_service.py new file mode 100644 index 000000000..c5470435f --- /dev/null +++ b/hotel/models/hotel_service.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import time +import datetime +import logging +from odoo import models, fields, api, _ +from odoo.tools import misc, DEFAULT_SERVER_DATETIME_FORMAT +from odoo.addons.hotel import date_utils +from odoo.addons import decimal_precision as dp +_logger = logging.getLogger(__name__) + +class HotelService(models.Model): + + @api.model + def _service_checkin(self): + if 'checkin' in self._context: + return self._context['checkin'] + return time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + + @api.model + def _service_checkout(self): + if 'checkout' in self._context: + return self._context['checkout'] + return time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + + @api.model + def _default_ser_room_line(self): + if 'room_lines' in self.env.context and self.env.context['room_lines']: + ids = [item[1] for item in self.env.context['room_lines']] + return self.env['hotel.reservation'].search([('id', 'in', ids)], + limit=1) + return False + + _name = 'hotel.service' + _description = 'Hotel Services and its charges' + + name = fields.Char('Service description') + # services in the hotel are products + product_id = fields.Many2one('product.product', 'Service', required=True) + + folio_id = fields.Many2one('hotel.folio', 'Folio', ondelete='cascade') + + ser_room_line = fields.Many2one('hotel.reservation', 'Room', + default=_default_ser_room_line) + + list_price = fields.Float( + related='product_id.list_price') + + channel_type = fields.Selection([ + ('door', 'Door'), + ('mail', 'Mail'), + ('phone', 'Phone'), + ('call', 'Call Center'), + ('web', 'Web')], 'Sales Channel') + + ser_checkin = fields.Datetime('From Date', required=True, + default=_service_checkin) + ser_checkout = fields.Datetime('To Date', required=True, + default=_service_checkout) + + + # TODO Hierarchical relationship for parent-child tree + # parent_id = fields.Many2one ... + + # service_id = fields.Many2one('product.product', 'Service_id', + # required=True, ondelete='cascade', + # delegate=True) + # service_type_id = fields.Many2one('hotel.service.type', + # 'Service Catagory') + # service_line_id = fields.Many2one('hotel.service.line', + # 'Service Line') + # @api.multi + # def unlink(self): + # # for record in self: + # # record.service_id.unlink() + # return super(HotelServices, self).unlink() diff --git a/hotel/models/hotel_service_line.py b/hotel/models/hotel_service_line.py new file mode 100644 index 000000000..eee5e85e5 --- /dev/null +++ b/hotel/models/hotel_service_line.py @@ -0,0 +1,246 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import time +import datetime +import logging +from odoo import models, fields, api, _ +from odoo.tools import misc, DEFAULT_SERVER_DATETIME_FORMAT +from odoo.addons.hotel import date_utils +_logger = logging.getLogger(__name__) + +from odoo.addons import decimal_precision as dp + + +class HotelServiceLine(models.Model): + + @api.one + def copy(self, default=None): + ''' + @param self: object pointer + @param default: dict of default values to be set + ''' + line_id = self.service_line_id.id + sale_line_obj = self.env['sale.order.line'].browse(line_id) + return sale_line_obj.copy(default=default) + + @api.multi + def _amount_line(self, field_name, arg): + ''' + @param self: object pointer + @param field_name: Names of fields. + @param arg: User defined arguments + ''' + for folio in self: + line = folio.service_line_id + x = line._amount_line(field_name, arg) + return x + + @api.multi + def _number_packages(self, field_name, arg): + ''' + @param self: object pointer + @param field_name: Names of fields. + @param arg: User defined arguments + ''' + for folio in self: + line = folio.service_line_id + x = line._number_packages(field_name, arg) + return x + + @api.model + def _service_checkin(self): + if 'checkin' in self._context: + return self._context['checkin'] + return time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + + @api.model + def _service_checkout(self): + if 'checkout' in self._context: + return self._context['checkout'] + return time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + + @api.model + def _default_ser_room_line(self): + if 'room_lines' in self.env.context and self.env.context['room_lines']: + ids = [item[1] for item in self.env.context['room_lines']] + return self.env['hotel.reservation'].search([('id', 'in', ids)], + limit=1) + return False + + _name = 'hotel.service.line' + _description = 'hotel Service line' + # The record's name + name = fields.Char('Service line', required=True) + # services in the hotel are products + product_id = fields.Many2one('product.product', 'Service') + + list_price = fields.Float( + related='product_id.list_price') + + # TODO refactor to services_ids + # services_line_id = fields.Many2one('hotel.services', 'Service Line', + # ondelete='cascade') + # FIXME You can add services to a folio ? + folio_id = fields.Many2one('hotel.folio', 'Folio', ondelete='cascade') + + channel_type = fields.Selection([ + ('door', 'Door'), + ('mail', 'Mail'), + ('phone', 'Phone'), + ('call', 'Call Center'), + ('web','Web')], 'Sales Channel') + + ser_checkin = fields.Datetime('From Date', required=True, + default=_service_checkin) + ser_checkout = fields.Datetime('To Date', required=True, + default=_service_checkout) + ser_room_line = fields.Many2one('hotel.reservation','Room', default=_default_ser_room_line) + + @api.model + def create(self, vals, check=True): + """ + Overrides orm create method. + @param self: The object pointer + @param vals: dictionary of fields value. + @return: new record set for hotel service line. + """ + if 'folio_id' in vals: + folio = self.env['hotel.folio'].browse(vals['folio_id']) + vals.update({'order_id': folio.order_id.id}) + user = self.env['res.users'].browse(self.env.uid) + if user.has_group('hotel.group_hotel_call'): + vals.update({'channel_type': 'call'}) + return super(HotelServiceLine, self).create(vals) + + # ~ @api.multi + # ~ def unlink(self): + # ~ """ + # ~ Overrides orm unlink method. + # ~ @param self: The object pointer + # ~ @return: True/False. + # ~ """ + # ~ s_line_obj = self.env['sale.order.line'] + # ~ for line in self: + # ~ if line.service_line_id: + # ~ sale_unlink_obj = s_line_obj.browse([line.service_line_id.id]) + # ~ sale_unlink_obj.unlink() + # ~ return super(HotelServiceLine, self).unlink() + + @api.onchange('product_id') + def product_id_change_hotel(self): + ''' + @param self: object pointer + ''' + if self.product_id: + if not (self.folio_id and self.folio_id.partner_id) and \ + self.ser_room_line: + self.folio_id = self.ser_room_line.folio_id + + self.name = self.product_id.name + self.price_unit = self.product_id.lst_price + self.product_uom = self.product_id.uom_id + self.price_unit = self.product_id.price + + #~ self.price_unit = tax_obj._fix_tax_included_price(prod.price, + #~ prod.taxes_id, + #~ self.tax_id) + + # ~ _logger.info(self._context) + # ~ if 'folio_id' in self._context: + # ~ _logger.info(self._context) + # ~ domain_rooms = [] + # ~ rooms_lines = self.env['hotel.reservation'].search([('folio_id','=',folio_id)]) + # ~ room_ids = room_lines.mapped('id') + # ~ domain_rooms.append(('id','in',room_ids)) + # ~ return {'domain': {'ser_room_line': domain_rooms}} + # + # ~ @api.onchange('folio_id') + # ~ def folio_id_change(self): + # ~ self.ensure_one() + # ~ _logger.info(self.mapped('folio_id.room_lines')) + # ~ rooms = self.mapped('folio_id.room_lines.id') + # ~ return {'domain': {'ser_room_line': rooms}} + + #~ @api.onchange('product_uom') + #~ def product_uom_change(self): + #~ ''' + #~ @param self: object pointer + #~ ''' + # ~ if not self.product_uom: + # ~ self.price_unit = 0.0 + # ~ return + # ~ self.price_unit = self.product_id.lst_price + # ~ if self.folio_id.partner_id: + # ~ prod = self.product_id.with_context( + # ~ lang=self.folio_id.partner_id.lang, + # ~ partner=self.folio_id.partner_id.id, + # ~ quantity=1, + # ~ date_order=self.folio_id.date_order, + # ~ pricelist=self.folio_id.pricelist_id.id, + # ~ uom=self.product_uom.id + # ~ ) + # ~ tax_obj = self.env['account.tax'] + # ~ self.price_unit = tax_obj._fix_tax_included_price(prod.price, + # ~ prod.taxes_id, + # ~ self.tax_id) + + @api.onchange('ser_checkin', 'ser_checkout') + def on_change_checkout(self): + ''' + When you change checkin or checkout it will checked it + and update the qty of hotel service line + ----------------------------------------------------------------- + @param self: object pointer + ''' + now_utc_dt = date_utils.now() + if not self.ser_checkin: + self.ser_checkin = now_utc_dt.strftime( + DEFAULT_SERVER_DATETIME_FORMAT) + if not self.ser_checkout: + self.ser_checkout = now_utc_dt.strftime( + DEFAULT_SERVER_DATETIME_FORMAT) + chkin_utc_dt = date_utils.get_datetime(self.ser_checkin) + chkout_utc_dt = date_utils.get_datetime(self.ser_checkout) + if chkout_utc_dt < chkin_utc_dt: + raise UserError(_('Checkout must be greater or equal checkin date')) + if self.ser_checkin and self.ser_checkout: + diffDate = date_utils.date_diff(self.ser_checkin, + self.ser_checkout, hours=False) + 1 + + @api.multi + def button_confirm(self): + ''' + @param self: object pointer + ''' + for folio in self: + line = folio.service_line_id + x = line.button_confirm() + return x + + @api.multi + def button_done(self): + ''' + @param self: object pointer + ''' + for folio in self: + line = folio.service_line_id + x = line.button_done() + return x + + @api.one + def copy_data(self, default=None): + ''' + @param self: object pointer + @param default: dict of default values to be set + ''' + sale_line_obj = self.env['sale.order.line' + ].browse(self.service_line_id.id) + return sale_line_obj.copy_data(default=default) + + @api.multi + def unlink(self): + for record in self: + record.service_line_id.unlink() + return super(HotelServiceLine, self).unlink() diff --git a/hotel/models/hotel_service_type.py b/hotel/models/hotel_service_type.py new file mode 100644 index 000000000..7d946bd1c --- /dev/null +++ b/hotel/models/hotel_service_type.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import models, fields, api, _ + + +class HotelServiceType(models.Model): + + _name = "hotel.service.type" + _description = "Service Type" + # The record's name + name = fields.Char('Service Type', required=True) + # Used for activate records + active = fields.Boolean('Active?', default=True) + + # ser_id = fields.Many2one('product.category', 'category', required=True, + # delegate=True, index=True, ondelete='cascade') + service_ids = fields.One2many('hotel.services', 'service_type_id', + 'Services in this category') + + @api.multi + def unlink(self): + # self.ser_id.unlink() + return super(HotelServiceType, self).unlink() diff --git a/hotel/models/hotel_virtual_room_availability.py b/hotel/models/hotel_virtual_room_availability.py new file mode 100644 index 000000000..b55533772 --- /dev/null +++ b/hotel/models/hotel_virtual_room_availability.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +import logging +from odoo import models, fields, api, _ +from odoo.exceptions import ValidationError +_logger = logging.getLogger(__name__) + + +class HotelVirtualRoomAvailability(models.Model): + _inherit = 'mail.thread' + _name = 'hotel.virtual.room.availability' + + # virtual_room_id = fields.Many2one('hotel.virtual.room', 'Virtual Room', + # required=True, track_visibility='always', + # ondelete='cascade') + room_type_id = fields.Many2one('hotel.room.type', 'Room Type', + required=True, track_visibility='always', + ondelete='cascade') + avail = fields.Integer('Avail', default=0, track_visibility='always') + no_ota = fields.Boolean('No OTA', default=False, track_visibility='always') + booked = fields.Boolean('Booked', default=False, readonly=True, + track_visibility='always') + date = fields.Date('Date', required=True, track_visibility='always') + + _sql_constraints = [('vroom_registry_unique', 'unique(room_type_id, date)', + 'Only can exists one availability in the same day for the same room type!')] + + @api.constrains('avail') + def _check_avail(self): + if self.avail < 0: + self.avail = 0 + + vroom_obj = self.env['hotel.room.type'] + cavail = len(vroom_obj.check_availability_virtual_room( + self.date, + self.date, + room_type_id=self.room_type_id.id)) + max_avail = min(cavail, + self.room_type_id.total_rooms_count) + if self.avail > max_avail: + self.avail = max_avail + + @api.constrains('date', 'room_type_id') + def _check_date_virtual_room_id(self): + count = self.search_count([ + ('date', '=', self.date), + ('room_type_id', '=', self.room_type_id.id) + ]) + if count > 1: + raise ValidationError(_("can't assign the same date to more than \ + one room type")) diff --git a/hotel/models/hotel_virtual_room_restriction.py b/hotel/models/hotel_virtual_room_restriction.py new file mode 100644 index 000000000..ed725cd32 --- /dev/null +++ b/hotel/models/hotel_virtual_room_restriction.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from odoo import models, fields, api + + +class VirtualRoomRestriction(models.Model): + _name = 'hotel.virtual.room.restriction' + + name = fields.Char('Restriction Plan Name', required=True) + item_ids = fields.One2many('hotel.virtual.room.restriction.item', + 'restriction_id', string='Restriction Items', + copy=True) + active = fields.Boolean('Active', + help='If unchecked, it will allow you to hide the \ + restriction plan without removing it.', + default=True) + + @api.multi + @api.depends('name') + def name_get(self): + restriction_id = self.env['ir.default'].sudo().get( + 'res.config.settings', 'parity_restrictions_id') + if restriction_id: + restriction_id = int(restriction_id) + names = [] + for record in self: + if record.id == restriction_id: + names.append((record.id, '%s (Parity)' % record.name)) + else: + names.append((record.id, record.name)) + return names diff --git a/hotel/models/hotel_virtual_room_restriction_item.py b/hotel/models/hotel_virtual_room_restriction_item.py new file mode 100644 index 000000000..6fd837c57 --- /dev/null +++ b/hotel/models/hotel_virtual_room_restriction_item.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from datetime import datetime +from odoo import models, fields, api, _ +from odoo.exceptions import ValidationError +from odoo.tools import DEFAULT_SERVER_DATE_FORMAT +from odoo.addons.hotel import date_utils + + +class HotelVirtualRoomRestrictionItem(models.Model): + _name = 'hotel.virtual.room.restriction.item' + + restriction_id = fields.Many2one('hotel.virtual.room.restriction', + 'Restriction Plan', ondelete='cascade', + index=True) + # virtual_room_id = fields.Many2one('hotel.virtual.room', 'Virtual Room', + # required=True, ondelete='cascade') + room_type_id = fields.Many2one('hotel.room.type', 'Room Type', + required=True, ondelete='cascade') + date_start = fields.Date('From') + date_end = fields.Date("To") + applied_on = fields.Selection([ + ('1_global', 'Global'), + # ('0_virtual_room', 'Virtual Room')], string="Apply On", required=True, + # default='0_virtual_room', + ('0_room_type', 'Room Type')], string="Apply On", required=True, + default='0_room_type', + help='Pricelist Item applicable on selected option') + + min_stay = fields.Integer("Min. Stay") + min_stay_arrival = fields.Integer("Min. Stay Arrival") + max_stay = fields.Integer("Max. Stay") + max_stay_arrival = fields.Integer("Max. Stay Arrival") + closed = fields.Boolean('Closed') + closed_departure = fields.Boolean('Closed Departure') + closed_arrival = fields.Boolean('Closed Arrival') + + _sql_constraints = [('vroom_registry_unique', + 'unique(restriction_id, room_type_id, date_start, date_end)', + 'Only can exists one restriction in the same day for the same room type!')] + + @api.constrains('min_stay', 'min_stay_arrival', 'max_stay', + 'max_stay_arrival') + def _check_min_stay_min_stay_arrival_max_stay(self): + if self.min_stay < 0: + raise ValidationError(_("Min. Stay can't be less than zero")) + elif self.min_stay_arrival < 0: + raise ValidationError( + ("Min. Stay Arrival can't be less than zero")) + elif self.max_stay < 0: + raise ValidationError(_("Max. Stay can't be less than zero")) + elif self.max_stay_arrival < 0: + raise ValidationError( + ("Max. Stay Arrival can't be less than zero")) + + @api.constrains('date_start', 'date_end') + def _check_date_start_date_end(self): + if self.applied_on == '1_global': + self.date_start = False + self.date_end = False + elif self.date_start and self.date_end: + date_start_dt = date_utils.get_datetime(self.date_start) + date_end_dt = date_utils.get_datetime(self.date_end) + if date_end_dt < date_start_dt: + raise ValidationError(_("Invalid Dates")) + + @api.constrains('applied_on') + def _check_applied_on(self): + count = self.search_count([('applied_on', '=', '1_global')]) + if count > 1: + raise ValidationError(_("Already exists an global rule")) diff --git a/hotel/models/inherit_account_invoice.py b/hotel/models/inherit_account_invoice.py new file mode 100644 index 000000000..4ac55df53 --- /dev/null +++ b/hotel/models/inherit_account_invoice.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from openerp import models, fields, api, _ +from openerp.exceptions import UserError, ValidationError + +import logging +_logger = logging.getLogger(__name__) + + +class AccountInvoice(models.Model): + + _inherit = 'account.invoice' + + @api.model + def create(self, vals): + cr, uid, context = self.env.args + context = dict(context) + if context.get('invoice_origin', False): + vals.update({'origin': context['invoice_origin']}) + return super(AccountInvoice, self).create(vals) + + @api.multi + def action_folio_payments(self): + self.ensure_one() + sales = self.mapped('invoice_line_ids.sale_line_ids.order_id') + folios = self.env['hotel.folio'].search([('order_id.id','in',sales.ids)]) + payments_obj = self.env['account.payment'] + payments = payments_obj.search([('folio_id','in',folios.ids)]) + payment_ids = payments.mapped('id') + return{ + 'name': _('Payments'), + 'view_type': 'form', + 'view_mode': 'tree,form', + 'res_model': 'account.payment', + 'target': 'new', + 'type': 'ir.actions.act_window', + 'domain': [('id', 'in', payment_ids)], + } + + dif_customer_payment = fields.Boolean(compute='_compute_dif_customer_payment') + from_folio = fields.Boolean(compute='_compute_dif_customer_payment') + sale_ids = fields.Many2many( + 'sale.order', 'sale_order_invoice_rel', 'invoice_id', + 'order_id', 'Sale Orders', readonly=True, + help="This is the list of sale orders related to this invoice.") + folio_ids = fields.Many2many( + comodel_name='hotel.folio', compute='_compute_dif_customer_payment') + + @api.multi + def _compute_dif_customer_payment(self): + for inv in self: + sales = inv.mapped('invoice_line_ids.sale_line_ids.order_id') + folios = self.env['hotel.folio'].search([('order_id.id','in',sales.ids)]) + if folios: + inv.from_folio = True + inv.folio_ids = [(6, 0, folios.ids)] + payments_obj = self.env['account.payment'] + payments = payments_obj.search([('folio_id','in',folios.ids)]) + for pay in payments: + if pay.partner_id != inv.partner_id: + inv.dif_customer_payment = True + + @api.multi + def action_invoice_open(self): + to_open_invoices_without_vat = self.filtered(lambda inv: inv.state != 'open' and inv.partner_id.vat == False) + if to_open_invoices_without_vat: + vat_error = _("We need the VAT of the following companies") + for invoice in to_open_invoices_without_vat: + vat_error += ", " + invoice.partner_id.name + raise ValidationError(vat_error) + return super(AccountInvoice, self).action_invoice_open() + + # ~ @api.multi + # ~ def confirm_paid(self): + # ~ ''' + # ~ This method change pos orders states to done when folio invoice + # ~ is in done. + # ~ ---------------------------------------------------------- + # ~ @param self: object pointer + # ~ ''' + # ~ pos_order_obj = self.env['pos.order'] + # ~ res = super(AccountInvoice, self).confirm_paid() + # ~ pos_odr_rec = pos_order_obj.search([('invoice_id', 'in', self._ids)]) + # ~ pos_odr_rec and pos_odr_rec.write({'state': 'done'}) + # ~ return res diff --git a/hotel/models/inherit_account_payment.py b/hotel/models/inherit_account_payment.py new file mode 100644 index 000000000..d111cdc6d --- /dev/null +++ b/hotel/models/inherit_account_payment.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from decimal import Decimal +import datetime +# For Python 3.0 and later +from urllib.request import urlopen +import time +import logging +from openerp.exceptions import except_orm, UserError, ValidationError +from openerp.tools import misc, DEFAULT_SERVER_DATETIME_FORMAT +from openerp import models, fields, api, _ +_logger = logging.getLogger(__name__) + + +class AccountPayment(models.Model): + + _inherit = 'account.payment' + + folio_id = fields.Many2one('hotel.folio', string='Folio') + amount_total_folio = fields.Float( + compute="_compute_folio_amount", store=True, + string="Total amount in folio", + ) + + @api.multi + def return_payment_folio(self): + journal = self.journal_id + partner = self.partner_id + amount = self.amount + reference = self.communication + account_move_lines = self.move_line_ids.filtered(lambda x: ( + x.account_id.internal_type == 'receivable')) + return_line_vals = { + 'move_line_ids': [(6, False, [x.id for x in account_move_lines])], + 'partner_id': partner.id, + 'amount': amount, + 'reference': reference, + } + return_vals = { + 'journal_id': journal.id, + 'line_ids': [(0,0,return_line_vals)], + } + return_pay = self.env['payment.return'].create(return_vals) + return { + 'name': 'Folio Payment Return', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'payment.return', + 'type': 'ir.actions.act_window', + 'res_id': return_pay.id, + } + @api.multi + def modify(self): + self.cancel() + vals = { + 'journal_id': self.journal_id, + 'partner_id': self.partner_id, + 'amount': self.amount, + 'payment_date': self.payment_date, + 'communication': self.communication, + 'folio_id': self.folio_id} + self.update(vals) + self.post() + + @api.multi + def delete(self): + self.cancel() + self.move_name = '' + self.unlink() + + @api.multi + @api.depends('state') + def _compute_folio_amount(self): + res = [] + fol = () + for payment in self: + amount_pending = 0 + total_amount = 0 + if payment.folio_id: + fol = payment.env['hotel.folio'].search([ + ('id', '=', payment.folio_id.id) + ]) + else: + return + if len(fol) == 0: + return + elif len(fol) > 1: + raise except_orm(_('Warning'), _('This pay is related with \ + more than one Reservation.')) + else: + fol.compute_invoices_amount() + return res diff --git a/hotel/models/inherit_payment_return.py b/hotel/models/inherit_payment_return.py new file mode 100644 index 000000000..b19d47260 --- /dev/null +++ b/hotel/models/inherit_payment_return.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# -------------------------------------------------------------------------- +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2018-Darío Lodeiros Vázquez +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# +# --------------------------------------------------------------------------- +from openerp import models, fields, api, _ + + +class PaymentReturn(models.Model): + + _inherit = 'payment.return' + + folio_id = fields.Many2one('hotel.folio', string='Folio') + + @api.multi + def action_confirm(self): + pay = super(PaymentReturn,self).action_confirm() + if pay: + folio_ids = [] + for line in self.line_ids: + payments = self.env['account.payment'].search([('move_line_ids','in',line.move_line_ids.ids)]) + folio_ids += payments.mapped('folio_id.id') + folios = self.env['hotel.folio'].browse(folio_ids) + folios.compute_invoices_amount() diff --git a/hotel/models/inherit_product_category.py b/hotel/models/inherit_product_category.py new file mode 100644 index 000000000..e96fea49c --- /dev/null +++ b/hotel/models/inherit_product_category.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from openerp import models, fields, api, _ + + +class ProductCategory(models.Model): + + _inherit = "product.category" + + # isroomtype = fields.Boolean('Is Room Type') + isamenitytype = fields.Boolean('Is Amenities Type') + isservicetype = fields.Boolean('Is Service Type') diff --git a/hotel/models/inherit_product_pricelist.py b/hotel/models/inherit_product_pricelist.py new file mode 100644 index 000000000..db16b5164 --- /dev/null +++ b/hotel/models/inherit_product_pricelist.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from openerp import models, api + + +class ProductPricelist(models.Model): + _inherit = 'product.pricelist' + + @api.multi + @api.depends('name') + def name_get(self): + pricelist_id = self.env['ir.default'].sudo().get( + 'res.config.settings', 'parity_pricelist_id') + if pricelist_id: + pricelist_id = int(pricelist_id) + org_names = super(ProductPricelist, self).name_get() + names = [] + for name in org_names: + if name[0] == pricelist_id: + names.append((name[0], '%s (Parity)' % name[1])) + else: + names.append((name[0], name[1])) + return names diff --git a/hotel/models/inherit_product_product.py b/hotel/models/inherit_product_product.py new file mode 100644 index 000000000..dd4efacbe --- /dev/null +++ b/hotel/models/inherit_product_product.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from openerp import models, fields, api, _ + + +class ProductProduct(models.Model): + + _inherit = "product.product" + + is_room_type = fields.Boolean('Is a Room Type', default=False) + # iscategid = fields.Boolean('Is categ id') + # isservice = fields.Boolean('Is Service id') diff --git a/hotel/models/inherit_res_company.py b/hotel/models/inherit_res_company.py new file mode 100644 index 000000000..01698224b --- /dev/null +++ b/hotel/models/inherit_res_company.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from openerp import models, fields, api, _ + + +class ResCompany(models.Model): + + _inherit = 'res.company' + + additional_hours = fields.Integer('Additional Hours', + help="Provide the min hours value for \ + check in, checkout days, whatever \ + the hours will be provided here based \ + on that extra days will be \ + calculated.") + default_cancel_policy_days = fields.Integer('Cancelation Days') + default_cancel_policy_percent = fields.Integer('Percent to pay') diff --git a/hotel/models/inherit_res_partner.py b/hotel/models/inherit_res_partner.py new file mode 100644 index 000000000..bf93539ad --- /dev/null +++ b/hotel/models/inherit_res_partner.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from openerp import models, fields, api, _ + + +class ResPartner(models.Model): + + _inherit = 'res.partner' + + reservations_count = fields.Integer('Reservations', + compute='_compute_reservations_count') + folios_count = fields.Integer('Folios', compute='_compute_folios_count') + + def _compute_reservations_count(self): + hotel_reservation_obj = self.env['hotel.reservation'] + for partner in self: + partner.reservations_count = hotel_reservation_obj.search_count([ + ('partner_id.id', '=', partner.id) + ]) + + def _compute_folios_count(self): + hotel_folio_obj = self.env['hotel.folio'] + for partner in self: + partner.folios_count = hotel_folio_obj.search_count([ + ('partner_id.id', '=', partner.id) + ]) diff --git a/hotel/models/inherited_mail_compose_message.py b/hotel/models/inherited_mail_compose_message.py new file mode 100644 index 000000000..5056b0d7e --- /dev/null +++ b/hotel/models/inherited_mail_compose_message.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2018 Alexandre Díaz +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## + +from odoo import api, models + + +class MailComposeMessage(models.TransientModel): + _inherit = 'mail.compose.message' + + @api.multi + def send_mail(self, auto_commit=False): + if self._context.get('default_model') == 'hotel.folio' and self._context.get('default_res_id') and self._context.get('mark_so_as_sent'): + folio = self.env['hotel.folio'].browse([ + self._context['default_res_id'] + ]) + if folio: + cmds = [] + for lid in folio.room_lines._ids: + cmds.append(( + 1, + lid, + {'to_send': False} + )) + if cmds: + folio.room_lines = cmds + return super(MailComposeMessage, self).send_mail(auto_commit=auto_commit) diff --git a/hotel/models/res_config.py b/hotel/models/res_config.py new file mode 100644 index 000000000..96f8fd2cc --- /dev/null +++ b/hotel/models/res_config.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +import re +import pytz +from openerp import models, fields, api, _ +from openerp.exceptions import ValidationError + + +@api.model +def _tz_get(self): + # put POSIX 'Etc/*' entries at the end to avoid confusing users + # see bug 1086728 + return [(tz, tz) for tz in sorted(pytz.all_timezones, + key=lambda tz: tz + if not tz.startswith('Etc/') else '_')] + + +class HotelConfiguration(models.TransientModel): + _inherit = 'res.config.settings' + + parity_pricelist_id = fields.Many2one('product.pricelist', + 'Product Pricelist') + parity_restrictions_id = fields.Many2one('hotel.virtual.room.restriction', + 'Restrictions') + default_arrival_hour = fields.Char('Default Arrival Hour (GMT)', + help="HH:mm Format", default="14:00") + default_departure_hour = fields.Char('Default Departure Hour (GMT)', + help="HH:mm Format", default="12:00") + tz_hotel = fields.Selection(_tz_get, string='Timezone', + default=lambda self: self._context.get('tz'), + help="The hotel's timezone, used to manage \ + date and time values in reservations \ + It is important to set a value for this \ + field.") + + @api.multi + def set_values(self): + super(HotelConfiguration, self).set_values() + + self.env['ir.default'].sudo().set( + 'res.config.settings', 'parity_pricelist_id', + self.parity_pricelist_id.id) + self.env['ir.default'].sudo().set( + 'res.config.settings', 'parity_restrictions_id', + self.parity_restrictions_id.id) + self.env['ir.default'].sudo().set( + 'res.config.settings', 'tz_hotel', self.tz_hotel) + self.env['ir.default'].sudo().set( + 'res.config.settings', 'default_arrival_hour', + self.default_arrival_hour) + self.env['ir.default'].sudo().set( + 'res.config.settings', 'default_departure_hour', + self.default_departure_hour) + + @api.model + def get_values(self): + res = super(HotelConfiguration, self).get_values() + + # ONLY FOR v11. DO NOT FORWARD-PORT + parity_pricelist_id = self.env['ir.default'].sudo().get( + 'res.config.settings', 'parity_pricelist_id') + parity_restrictions_id = self.env['ir.default'].sudo().get( + 'res.config.settings', 'parity_restrictions_id') + tz_hotel = self.env['ir.default'].sudo().get( + 'res.config.settings', 'tz_hotel') + default_arrival_hour = self.env['ir.default'].sudo().get( + 'res.config.settings', 'default_arrival_hour') + default_departure_hour = self.env['ir.default'].sudo().get( + 'res.config.settings', 'default_departure_hour') + res.update( + parity_pricelist_id=parity_pricelist_id, + parity_restrictions_id=parity_restrictions_id, + tz_hotel=tz_hotel, + default_arrival_hour=default_arrival_hour, + default_departure_hour=default_departure_hour, + ) + return res + + @api.constrains('default_arrival_hour', 'default_departure_hour') + def _check_hours(self): + r = re.compile('[0-2][0-9]:[0-5][0-9]') + if not r.match(self.default_arrival_hour): + raise ValidationError(_("Invalid arrival hour (Format: HH:mm)")) + if not r.match(self.default_departure_hour): + raise ValidationError(_("Invalid departure hour (Format: HH:mm)")) diff --git a/hotel/models/virtual_room.py b/hotel/models/virtual_room.py new file mode 100644 index 000000000..2ccfa9a99 --- /dev/null +++ b/hotel/models/virtual_room.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Dario Lodeiros <> +# Alexandre Díaz +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from decimal import Decimal +from datetime import datetime, timedelta +import dateutil.parser +# For Python 3.0 and later +from urllib.request import urlopen +import time +from openerp.exceptions import except_orm, UserError, ValidationError +from openerp.tools import ( + misc, + DEFAULT_SERVER_DATE_FORMAT, + DEFAULT_SERVER_DATETIME_FORMAT) +from openerp import models, fields, api, _ +from odoo.addons.hotel import date_utils + + +class VirtualRoom(models.Model): + _name = 'hotel.virtual.room' + _inherits = {'product.product': 'product_id'} + + @api.depends('room_ids', 'room_type_ids') + def _compute_total_rooms(self): + for r in self: + count = 0 + count += len(r.room_ids) # Rooms linked directly + room_categories = r.room_type_ids.mapped('room_ids.id') + count += self.env['hotel.room'].search_count([ + ('categ_id.id', 'in', room_categories) + ]) # Rooms linked through room type + r.total_rooms_count = count + + @api.constrains('room_ids', 'room_type_ids') + def _check_duplicated_rooms(self): + warning_msg = "" + for r in self: + room_categories = self.room_type_ids.mapped('room_ids.id') + if self.room_ids & self.env['hotel.room'].search([ + ('categ_id.id', 'in', room_categories)]): + room_ids = self.room_ids & self.env['hotel.room'].search([ + ('categ_id.id', 'in', room_categories) + ]) + rooms_name = ','.join(str(x.name) for x in room_ids) + warning_msg += _('You can not enter the same room in duplicate \ + (check the room types) %s') % rooms_name + raise models.ValidationError(warning_msg) + + @api.constrains('max_real_rooms', 'room_ids', 'room_type_ids') + def _check_max_rooms(self): + warning_msg = "" + for r in self: + if self.max_real_rooms > self.total_rooms_count: + warning_msg += _('The Maxime rooms allowed can not be greate \ + than total rooms count') + raise models.ValidationError(warning_msg) + + virtual_code = fields.Char('Code') # not used + room_ids = fields.Many2many('hotel.room', string='Rooms') + room_type_ids = fields.Many2many('hotel.room.type', string='Room Types') + total_rooms_count = fields.Integer(compute='_compute_total_rooms') + product_id = fields.Many2one('product.product', 'Product_id', + required=True, delegate=True, + ondelete='cascade') + # FIXME services are related to real rooms + service_ids = fields.Many2many('hotel.services', + string='Included Services') + max_real_rooms = fields.Integer('Default Max Room Allowed') + product_id = fields.Many2one( + 'product.product', required=True, + ondelete='cascade') + active = fields.Boolean(default=True, help="The active field allows you to hide the category without removing it.") + + @api.multi + def get_capacity(self): + self.ensure_one() + hotel_room_obj = self.env['hotel.room'] + room_categories = self.room_type_ids.mapped('room_ids.id') + room_ids = self.room_ids + hotel_room_obj.search([ + ('categ_id.id', 'in', room_categories) + ]) + capacities = room_ids.mapped('capacity') + return any(capacities) and min(capacities) or 0 + + @api.model + def check_availability_virtual_room(self, checkin, checkout, + virtual_room_id=False, notthis=[]): + occupied = self.env['hotel.reservation'].occupied(checkin, checkout) + rooms_occupied = occupied.mapped('product_id.id') + free_rooms = self.env['hotel.room'].search([ + ('product_id.id', 'not in', rooms_occupied), + ('id', 'not in', notthis) + ]) + if virtual_room_id: + hotel_room_obj = self.env['hotel.room'] + virtual_room = self.env['hotel.virtual.room'].search([ + ('id', '=', virtual_room_id) + ]) + room_categories = virtual_room.room_type_ids.mapped('room_ids.id') + rooms_linked = virtual_room.room_ids | hotel_room_obj.search([ + ('categ_id.id', 'in', room_categories)]) + free_rooms = free_rooms & rooms_linked + return free_rooms.sorted(key=lambda r: r.sequence) + + @api.multi + def unlink(self): + for record in self: + # Set fixed price to rooms with price from this virtual rooms + rooms = self.env['hotel.room'].search([ + ('sale_price_type', '=', 'vroom'), + ('price_virtual_room', '=', record.id) + ]) + for room in rooms: + room.sale_price_type = 'fixed' + # Remove product.product + record.product_id.unlink() + return super(VirtualRoom, self).unlink() diff --git a/hotel/report/__init__.py b/hotel/report/__init__.py new file mode 100644 index 000000000..a89dbe55e --- /dev/null +++ b/hotel/report/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import hotel_report diff --git a/hotel/report/hotel_report.py b/hotel/report/hotel_report.py new file mode 100644 index 000000000..ae6ffe019 --- /dev/null +++ b/hotel/report/hotel_report.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import time +from openerp import models + +# Old SXW engine was removed already in v11. You should update your code with +# current engine tools. +# class FolioReport(): +# def __init__(self, cr, uid, name, context): +# super(FolioReport, self).__init__(cr, uid, name, context) +# self.localcontext.update({'time': time, +# 'get_data': self.get_data, +# 'get_Total': self.getTotal, +# 'get_total': self.gettotal, +# }) +# self.temp = 0.0 +# +# def get_data(self, date_start, date_end): +# folio_obj = self.pool.get('hotel.folio') +# tids = folio_obj.search(self.cr, self.uid, +# [('checkin_date', '>=', date_start), +# ('checkout_date', '<=', date_end)]) +# res = folio_obj.browse(self.cr, self.uid, tids) +# return res +# +# def gettotal(self, total): +# self.temp = self.temp + float(total) +# return total +# +# def getTotal(self): +# return self.temp +# +# +# class ReportLunchorder(models.AbstractModel): +# _name = 'report.hotel.report_hotel_folio' +# _inherit = 'report.report_xlsx.abstract' +# _template = 'hotel.report_hotel_folio' +# _wrapped_report_class = FolioReport diff --git a/hotel/report/hotel_report.xml b/hotel/report/hotel_report.xml new file mode 100644 index 000000000..f6e3916f7 --- /dev/null +++ b/hotel/report/hotel_report.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/hotel/report/report_parte_viajero.xml b/hotel/report/report_parte_viajero.xml new file mode 100644 index 000000000..13758ad5f --- /dev/null +++ b/hotel/report/report_parte_viajero.xml @@ -0,0 +1,19 @@ + + + + + + + qweb-pdf + 1 + 1 + 201 + + + diff --git a/hotel/security/.~lock.ir.model.access.csv# b/hotel/security/.~lock.ir.model.access.csv# new file mode 100644 index 000000000..26689e352 --- /dev/null +++ b/hotel/security/.~lock.ir.model.access.csv# @@ -0,0 +1 @@ +,slimbook,slimbook-PRO,26.07.2018 11:51,file:///home/slimbook/.config/libreoffice/4; \ No newline at end of file diff --git a/hotel/security/hotel_security.xml b/hotel/security/hotel_security.xml new file mode 100644 index 000000000..3214173bd --- /dev/null +++ b/hotel/security/hotel_security.xml @@ -0,0 +1,22 @@ + + + + + + + Hotel Management / User + + + + + Hotel Management/ Manager + + + + + + Hotel Management / CallCenter + + + + diff --git a/hotel/security/ir.model.access.csv b/hotel/security/ir.model.access.csv new file mode 100644 index 000000000..e1b816195 --- /dev/null +++ b/hotel/security/ir.model.access.csv @@ -0,0 +1,54 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_currency_exchange_call,hotel.currency_exchange.call,model_currency_exchange,hotel.group_hotel_call,1,1,1,1 +access_currency_exchange_user,hotel.currency_exchange.user,model_currency_exchange,hotel.group_hotel_user,1,1,1,1 +access_folio_room_line_call,hotel.folio_room_line.call,hotel.model_hotel_reservation_line,hotel.group_hotel_call,1,1,1,1 +access_folio_room_line_user,hotel.folio_room_line.user,hotel.model_hotel_reservation_line,hotel.group_hotel_user,1,1,1,1 +access_hotel_account_tax_call,hotel.account.tax.call,account.model_account_tax,hotel.group_hotel_call,1,1,1,1 +access_hotel_account_tax_user,hotel.account.tax.user,account.model_account_tax,hotel.group_hotel_user,1,1,1,1 +access_hotel_floor_group,hotel.floor.user,model_hotel_floor,hotel.group_hotel_user,1,0,0,0 +access_hotel_floor_group_call,hotel.floor.call,model_hotel_floor,hotel.group_hotel_call,1,0,0,0 +access_hotel_floor_group_manager,hotel.floor.manager,model_hotel_floor,hotel.group_hotel_manager,1,1,1,1 +access_hotel_folio,hotel.folio.user,model_hotel_folio,hotel.group_hotel_user,1,1,1,1 +access_hotel_folio_call,hotel.folio.call,model_hotel_folio,hotel.group_hotel_call,1,1,1,1 +access_hotel_folio_line,hotel_folio.line.user,model_hotel_reservation,hotel.group_hotel_user,1,1,1,1 +access_hotel_folio_line_call,hotel_folio.line.call,model_hotel_reservation,hotel.group_hotel_call,1,1,1,1 +access_hotel_invoice_call,account.invoice.call,account.model_account_invoice,hotel.group_hotel_call,1,1,1,1 +access_hotel_invoice_user,account.invoice.user,account.model_account_invoice,hotel.group_hotel_user,1,1,1,1 +access_hotel_model_cardex_call,hotel.currency_exchange.call,hotel.model_cardex,hotel.group_hotel_call,1,1,1,1 +access_hotel_model_cardex_user,hotel.currency_exchange.user,hotel.model_cardex,hotel.group_hotel_user,1,1,1,1 +access_hotel_order_call,hotel.order.call,sale.model_sale_order,hotel.group_hotel_call,1,1,1,1 +access_hotel_order_line_call,hotel.order.line.call,sale.model_sale_order_line,hotel.group_hotel_call,1,1,1,1 +access_hotel_order_line_user,hotel.order.line.user,sale.model_sale_order_line,hotel.group_hotel_user,1,1,1,1 +access_hotel_order_user,hotel.order.user,sale.model_sale_order,hotel.group_hotel_user,1,1,1,1 +access_hotel_restrictions_call,hotel.restriction. All,hotel.model_hotel_virtual_room_restriction,hotel.group_hotel_call,1,0,0,0 +access_hotel_restrictions_item_call,hotel.restriction.item.call,hotel.model_hotel_virtual_room_restriction_item,hotel.group_hotel_call,1,0,0,0 +access_hotel_restrictions_item_manager,hotel.restriction.item.manager,hotel.model_hotel_virtual_room_restriction_item,hotel.group_hotel_manager,1,1,1,1 +access_hotel_restrictions_item_user,hotel.restriction.item.user,hotel.model_hotel_virtual_room_restriction_item,hotel.group_hotel_user,1,0,0,0 +access_hotel_restrictions_manager,hotel.restriction.manager,hotel.model_hotel_virtual_room_restriction,hotel.group_hotel_manager,1,1,1,1 +access_hotel_restrictions_user,hotel.restriction.user,hotel.model_hotel_virtual_room_restriction,hotel.group_hotel_user,1,0,0,0 +access_hotel_room,hotel.room.user,model_hotel_room,hotel.group_hotel_user,1,0,0,0 +access_hotel_room_amenities,hotel.room_aminities.user,model_hotel_room_amenities,hotel.group_hotel_user,1,0,0,0 +access_hotel_room_amenities_call,hotel.room_aminities.call,model_hotel_room_amenities,hotel.group_hotel_call,1,0,0,0 +access_hotel_room_amenities_manager,hotel.room_aminities.manager,model_hotel_room_amenities,hotel.group_hotel_manager,1,1,1,1 +access_hotel_room_amenities_type,hotel.room_amenities_type.user,model_hotel_room_amenities_type,hotel.group_hotel_user,1,0,0,0 +access_hotel_room_amenities_type_call,hotel.room_amenities_type.call,model_hotel_room_amenities_type,hotel.group_hotel_call,1,0,0,0 +access_hotel_room_amenities_type_manager,hotel.room_amenities_type.manager,model_hotel_room_amenities_type,hotel.group_hotel_manager,1,1,1,1 +access_hotel_room_call,hotel.room.call,model_hotel_room,hotel.group_hotel_call,1,0,0,0 +access_hotel_room_manager,hotel.room.manager,model_hotel_room,hotel.group_hotel_manager,1,1,1,1 +access_hotel_room_type,hotel.room_type.user,model_hotel_room_type,hotel.group_hotel_user,1,0,0,0 +access_hotel_room_type_call,hotel.room_type.call,model_hotel_room_type,hotel.group_hotel_call,1,0,0,0 +access_hotel_room_type_manager,hotel.room_type.manager,model_hotel_room_type,hotel.group_hotel_manager,1,1,1,1 +access_hotel_service,hotel_service.user,model_hotel_service,hotel.group_hotel_user,1,1,1,1 +access_hotel_service_call,hotel_service.call,model_hotel_service,hotel.group_hotel_call,1,1,1,1 +access_hotel_user reconcilie,hotel.user reconcilie,account.model_account_partial_reconcile,hotel.group_hotel_user,1,1,1,1 +access_hotel_user_account_full_reconcilie,hotel.user_account_full_reconcilie,account.model_account_full_reconcile,hotel.group_hotel_user,1,1,1,1 +access_hotel_user_user,hotel.user_res_user,auth_crypt.model_res_users,hotel.group_hotel_user,1,1,0,0 +access_hotel_virtual_room_availability_call,hotel.availability.call,hotel.model_hotel_virtual_room_availability,hotel.group_hotel_call,1,1,1,1 +access_hotel_virtual_room_availability_manager,hotel.availability.manager,hotel.model_hotel_virtual_room_availability,hotel.group_hotel_manager,1,1,1,1 +access_hotel_virtual_room_availability_user,hotel.availability.user,hotel.model_hotel_virtual_room_availability,hotel.group_hotel_user,1,1,1,1 +access_product_category,product.category.user,product.model_product_category,hotel.group_hotel_user,1,0,0,0 +access_product_category_call,product.category.call,product.model_product_category,hotel.group_hotel_call,1,0,0,0 +access_product_category_manager,product.category.manager,product.model_product_category,hotel.group_hotel_manager,1,1,1,1 +access_product_product,product.product.user,product.model_product_product,hotel.group_hotel_user,1,0,0,0 +access_product_product_call,product.product.call,product.model_product_product,hotel.group_hotel_call,1,0,0,0 +access_product_product_manager,product.product.manager,product.model_product_product,hotel.group_hotel_manager,1,1,1,1 diff --git a/hotel/static/description/bed.png b/hotel/static/description/bed.png new file mode 100644 index 000000000..a1f2e0d48 Binary files /dev/null and b/hotel/static/description/bed.png differ diff --git a/hotel/static/description/book.png b/hotel/static/description/book.png new file mode 100644 index 000000000..985d40bca Binary files /dev/null and b/hotel/static/description/book.png differ diff --git a/hotel/static/description/booking.png b/hotel/static/description/booking.png new file mode 100644 index 000000000..bea6c674c Binary files /dev/null and b/hotel/static/description/booking.png differ diff --git a/hotel/static/description/car.png b/hotel/static/description/car.png new file mode 100644 index 000000000..6c4a1454a Binary files /dev/null and b/hotel/static/description/car.png differ diff --git a/hotel/static/description/checkin.png b/hotel/static/description/checkin.png new file mode 100644 index 000000000..3cc72c398 Binary files /dev/null and b/hotel/static/description/checkin.png differ diff --git a/hotel/static/description/currency.png b/hotel/static/description/currency.png new file mode 100644 index 000000000..b91654c28 Binary files /dev/null and b/hotel/static/description/currency.png differ diff --git a/hotel/static/description/fast-food-icons.png b/hotel/static/description/fast-food-icons.png new file mode 100644 index 000000000..e7e148596 Binary files /dev/null and b/hotel/static/description/fast-food-icons.png differ diff --git a/hotel/static/description/gym.png b/hotel/static/description/gym.png new file mode 100644 index 000000000..a038cd5bf Binary files /dev/null and b/hotel/static/description/gym.png differ diff --git a/hotel/static/description/head.png b/hotel/static/description/head.png new file mode 100644 index 000000000..64aa015bf Binary files /dev/null and b/hotel/static/description/head.png differ diff --git a/hotel/static/description/hotel.png b/hotel/static/description/hotel.png new file mode 100644 index 000000000..a31dae49e Binary files /dev/null and b/hotel/static/description/hotel.png differ diff --git a/hotel/static/description/hotel1.png b/hotel/static/description/hotel1.png new file mode 100644 index 000000000..e00355335 Binary files /dev/null and b/hotel/static/description/hotel1.png differ diff --git a/hotel/static/description/hotel2.png b/hotel/static/description/hotel2.png new file mode 100644 index 000000000..5b43befcc Binary files /dev/null and b/hotel/static/description/hotel2.png differ diff --git a/hotel/static/description/icon-book.png b/hotel/static/description/icon-book.png new file mode 100644 index 000000000..22d8cc291 Binary files /dev/null and b/hotel/static/description/icon-book.png differ diff --git a/hotel/static/description/icon.png b/hotel/static/description/icon.png new file mode 100644 index 000000000..064b0c581 Binary files /dev/null and b/hotel/static/description/icon.png differ diff --git a/hotel/static/description/inc1.png b/hotel/static/description/inc1.png new file mode 100644 index 000000000..1104390f1 Binary files /dev/null and b/hotel/static/description/inc1.png differ diff --git a/hotel/static/description/inc2.png b/hotel/static/description/inc2.png new file mode 100644 index 000000000..4ee8fa639 Binary files /dev/null and b/hotel/static/description/inc2.png differ diff --git a/hotel/static/description/inc3.png b/hotel/static/description/inc3.png new file mode 100644 index 000000000..688e469ba Binary files /dev/null and b/hotel/static/description/inc3.png differ diff --git a/hotel/static/description/inc4.png b/hotel/static/description/inc4.png new file mode 100644 index 000000000..2eb5dc82f Binary files /dev/null and b/hotel/static/description/inc4.png differ diff --git a/hotel/static/description/inc5.png b/hotel/static/description/inc5.png new file mode 100644 index 000000000..bb91959e6 Binary files /dev/null and b/hotel/static/description/inc5.png differ diff --git a/hotel/static/description/inc6.png b/hotel/static/description/inc6.png new file mode 100644 index 000000000..88b07252e Binary files /dev/null and b/hotel/static/description/inc6.png differ diff --git a/hotel/static/description/inc7.png b/hotel/static/description/inc7.png new file mode 100644 index 000000000..340188a31 Binary files /dev/null and b/hotel/static/description/inc7.png differ diff --git a/hotel/static/description/inc8.png b/hotel/static/description/inc8.png new file mode 100644 index 000000000..d38788552 Binary files /dev/null and b/hotel/static/description/inc8.png differ diff --git a/hotel/static/description/inc9.png b/hotel/static/description/inc9.png new file mode 100644 index 000000000..2c788af93 Binary files /dev/null and b/hotel/static/description/inc9.png differ diff --git a/hotel/static/description/index.html b/hotel/static/description/index.html new file mode 100644 index 000000000..8a850002e --- /dev/null +++ b/hotel/static/description/index.html @@ -0,0 +1,56 @@ +
+
+
+

HOTEL MANAGEMENT SYSTEM

+
+
+
+
+
+
+

HOTEL BOOKING

+

Book your room.

+ + + + + +
+
+

ALL INCLUSIVE

+

Facilities provided

+ + + + + +
+
+

AMENITIES

+

Extra class hotel service

+ + + + +
+
+

RESTURANTS

+

Bon Appetite !

+ + + +
+
+

Currency Exchange

+

Exchange currency on the go

+ + +
+
+

REPORTS

+

Manage and Analyze

+ + +
+
+
diff --git a/hotel/static/description/key.png b/hotel/static/description/key.png new file mode 100644 index 000000000..b954b8c4d Binary files /dev/null and b/hotel/static/description/key.png differ diff --git a/hotel/static/description/menu.png b/hotel/static/description/menu.png new file mode 100644 index 000000000..0049bb373 Binary files /dev/null and b/hotel/static/description/menu.png differ diff --git a/hotel/static/description/menu_waitor.png b/hotel/static/description/menu_waitor.png new file mode 100644 index 000000000..4e53dc77a Binary files /dev/null and b/hotel/static/description/menu_waitor.png differ diff --git a/hotel/static/description/money.png b/hotel/static/description/money.png new file mode 100644 index 000000000..f763665a4 Binary files /dev/null and b/hotel/static/description/money.png differ diff --git a/hotel/static/description/opt.jpg b/hotel/static/description/opt.jpg new file mode 100644 index 000000000..cc596767d Binary files /dev/null and b/hotel/static/description/opt.jpg differ diff --git a/hotel/static/description/plate.png b/hotel/static/description/plate.png new file mode 100644 index 000000000..9460ac611 Binary files /dev/null and b/hotel/static/description/plate.png differ diff --git a/hotel/static/description/pool_icon.png b/hotel/static/description/pool_icon.png new file mode 100644 index 000000000..aa3bf92c0 Binary files /dev/null and b/hotel/static/description/pool_icon.png differ diff --git a/hotel/static/description/rent.jpg b/hotel/static/description/rent.jpg new file mode 100644 index 000000000..a2ef21570 Binary files /dev/null and b/hotel/static/description/rent.jpg differ diff --git a/hotel/static/description/report.png b/hotel/static/description/report.png new file mode 100644 index 000000000..622ff848d Binary files /dev/null and b/hotel/static/description/report.png differ diff --git a/hotel/static/description/report1.png b/hotel/static/description/report1.png new file mode 100644 index 000000000..16752416f Binary files /dev/null and b/hotel/static/description/report1.png differ diff --git a/hotel/static/description/revenue.png b/hotel/static/description/revenue.png new file mode 100644 index 000000000..bcd9b36dc Binary files /dev/null and b/hotel/static/description/revenue.png differ diff --git a/hotel/static/description/room.png b/hotel/static/description/room.png new file mode 100644 index 000000000..af9395687 Binary files /dev/null and b/hotel/static/description/room.png differ diff --git a/hotel/static/description/star_icon.png b/hotel/static/description/star_icon.png new file mode 100644 index 000000000..1ebe93ec9 Binary files /dev/null and b/hotel/static/description/star_icon.png differ diff --git a/hotel/static/description/swim.png b/hotel/static/description/swim.png new file mode 100644 index 000000000..b00d78b01 Binary files /dev/null and b/hotel/static/description/swim.png differ diff --git a/hotel/static/description/travel.png b/hotel/static/description/travel.png new file mode 100644 index 000000000..bd1f6ad43 Binary files /dev/null and b/hotel/static/description/travel.png differ diff --git a/hotel/static/description/vodna.png b/hotel/static/description/vodna.png new file mode 100644 index 000000000..ca556aaf2 Binary files /dev/null and b/hotel/static/description/vodna.png differ diff --git a/hotel/static/description/waiter.png b/hotel/static/description/waiter.png new file mode 100644 index 000000000..86940b889 Binary files /dev/null and b/hotel/static/description/waiter.png differ diff --git a/hotel/tests/__init__.py b/hotel/tests/__init__.py new file mode 100644 index 000000000..6166d346a --- /dev/null +++ b/hotel/tests/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from . import test_reservation +from . import test_folio diff --git a/hotel/tests/common.py b/hotel/tests/common.py new file mode 100644 index 000000000..5a32c6f3d --- /dev/null +++ b/hotel/tests/common.py @@ -0,0 +1,251 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from datetime import timedelta +from odoo import api, fields +from odoo.tests import common +from openerp.tools import ( + DEFAULT_SERVER_DATE_FORMAT, + DEFAULT_SERVER_DATETIME_FORMAT) +from odoo.addons.mail.tests.common import TestMail +from odoo.addons.hotel import date_utils +import pytz +import logging +_logger = logging.getLogger(__name__) + + +# TestMail crea recursos utiles para nuestros test... +# por ejemplo, usuarios con distintos tipos de nivel, etc... +class TestHotel(TestMail): + + @classmethod + def _init_mock_hotel(cls): + return True + + def create_folio(self, creator, partner): + # Create Folio + folio = self.env['hotel.folio'].sudo(creator).create({ + 'partner_id': partner.id, + }) + self.assertTrue(folio, "Can't create folio") + return folio + + def create_reservation(self, creator, folio, checkin, checkout, room, + resname, adults=1, children=0): + # Create Reservation (Special Room) + reservation = self.env['hotel.reservation'].sudo(creator).create({ + 'name': resname, + 'adults': adults, + 'children': children, + 'checkin': checkin.strftime(DEFAULT_SERVER_DATETIME_FORMAT), + 'checkout': checkout.strftime(DEFAULT_SERVER_DATETIME_FORMAT), + 'folio_id': folio.id, + 'virtual_room_id': room.price_virtual_room.id, + 'product_id': room.product_id.id, + }) + self.assertTrue( + reservation, + "Hotel Calendar can't create a new reservation!") + + # Create Reservation Lines + Update Reservation Price + days_diff = date_utils.date_diff(checkin, checkout, hours=False) + res = reservation.sudo(creator).prepare_reservation_lines( + checkin.strftime(DEFAULT_SERVER_DATETIME_FORMAT), days_diff) + reservation.sudo(creator).write({ + 'reservation_lines': res['commands'], + 'price_unit': res['total_price'], + }) + + return reservation + + @classmethod + def setUpClass(cls): + super(TestHotel, cls).setUpClass() + + cls._init_mock_hotel() + + # Restriction Plan + cls.restriction_1 = cls.env['hotel.virtual.room.restriction'].create({ + 'name': 'Restriction Test #1', + 'active': True + }) + + # Pricelist + cls.pricelist_1 = cls.env['product.pricelist'].create({ + 'name': 'Pricelist Test #1', + }) + + # Minimal Hotel Configuration + cls.tz_hotel = 'Europe/Madrid' + cls.parity_pricelist_id = cls.pricelist_1.id + cls.parity_restrictions_id = cls.restriction_1.id + cls.env['ir.values'].sudo().set_default('hotel.config.settings', + 'tz_hotel', cls.tz_hotel) + cls.env['ir.values'].sudo().set_default('hotel.config.settings', + 'parity_pricelist_id', + cls.parity_pricelist_id) + cls.env['ir.values'].sudo().set_default('hotel.config.settings', + 'parity_restrictions_id', + cls.parity_restrictions_id) + + # User Groups + user_group_hotel_manager = cls.env.ref('hotel.group_hotel_manager') + user_group_hotel_user = cls.env.ref('hotel.group_hotel_user') + user_group_employee = cls.env.ref('base.group_user') + user_group_public = cls.env.ref('base.group_public') + user_group_account_inv = cls.env.ref('account.group_account_invoice') + user_group_sale_manager = cls.env.ref('sales_team.group_sale_manager') + user_group_base_partner_manager = cls.env.ref( + 'base.group_partner_manager') + + # Create Test Users + Users = cls.env['res.users'].with_context({ + 'no_reset_password': True, + 'mail_create_nosubscribe': True + }) + cls.user_hotel_manager = Users.create({ + 'name': 'Jeff Hotel Manager', + 'login': 'hoteljeff', + 'email': 'mynameisjeff@example.com', + 'signature': '--\nJeff', + 'notify_email': 'always', + 'groups_id': [(6, 0, [user_group_hotel_manager.id, + user_group_employee.id, + user_group_account_inv.id, + user_group_sale_manager.id, + user_group_base_partner_manager.id])] + }) + cls.user_hotel_user = Users.create({ + 'name': 'Juancho Hotel User', + 'login': 'juancho', + 'email': 'juancho@example.com', + 'signature': '--\nJuancho', + 'notify_email': 'always', + 'groups_id': [(6, 0, [user_group_hotel_user.id, + user_group_public.id])] + }) + + # Create Tests Records + RoomTypes = cls.env['hotel.room.type'] + cls.hotel_room_type_simple = RoomTypes.create({ + 'name': 'Simple', + 'code_type': 'TSMP', + }) + cls.hotel_room_type_double = RoomTypes.create({ + 'name': 'Double', + 'code_type': 'TDBL', + }) + + VRooms = cls.env['hotel.virtual.room'] + cls.hotel_vroom_budget = VRooms.create({ + 'name': 'Budget Room', + 'virtual_code': '001', + 'list_price': 50, + }) + cls.hotel_vroom_special = VRooms.create({ + 'name': 'Special Room', + 'virtual_code': '002', + 'list_price': 150, + }) + + Rooms = cls.env['hotel.room'] + cls.hotel_room_simple_100 = Rooms.create({ + 'name': '100', + 'sale_price_type': 'vroom', + 'price_virtual_room': cls.hotel_vroom_budget.id, + 'categ_id': cls.hotel_room_type_simple.cat_id.id, + 'capacity': 1, + }) + cls.hotel_room_simple_101 = Rooms.create({ + 'name': '101', + 'sale_price_type': 'vroom', + 'price_virtual_room': cls.hotel_vroom_budget.id, + 'categ_id': cls.hotel_room_type_simple.cat_id.id, + 'capacity': 1, + 'sequence': 1, + }) + cls.hotel_room_double_200 = Rooms.create({ + 'name': '200', + 'sale_price_type': 'vroom', + 'price_virtual_room': cls.hotel_vroom_special.id, + 'categ_id': cls.hotel_room_type_double.cat_id.id, + 'capacity': 2, + }) + + cls.hotel_vroom_budget.write({ + 'room_ids': [(6, False, [cls.hotel_room_simple_100.id, + cls.hotel_room_simple_101.id])], + }) + cls.hotel_vroom_special.write({ + 'room_ids': [(6, False, [cls.hotel_room_double_200.id])], + }) + + # Create a week of fresh data + now_utc_dt = date_utils.now() + cls.avails_tmp = { + cls.hotel_vroom_budget.id: (1, 2, 2, 1, 1, 2, 2), + cls.hotel_vroom_special.id: (1, 1, 1, 1, 1, 1, 1), + } + cls.prices_tmp = { + cls.hotel_vroom_budget.id: (10.0, 80.0, 80.0, 95.0, 90.0, 80.0, + 20.0), + cls.hotel_vroom_special.id: (5.0, 15.0, 15.0, 35.0, 35.0, 10.0, + 10.0), + } + cls.restrictions_min_stay_tmp = { + cls.hotel_vroom_budget.id: (0, 1, 2, 1, 1, 0, 0), + cls.hotel_vroom_special.id: (3, 1, 0, 2, 0, 1, 4), + } + budget_product_id = cls.hotel_vroom_budget.product_id + special_product_id = cls.hotel_vroom_special.product_id + product_tmpl_ids = { + cls.hotel_vroom_budget.id: budget_product_id.product_tmpl_id.id, + cls.hotel_vroom_special.id: special_product_id.product_tmpl_id.id, + } + vroom_avail_obj = cls.env['hotel.virtual.room.availability'] + vroom_rest_item_obj = cls.env['hotel.virtual.room.restriction.item'] + pricelist_item_obj = cls.env['product.pricelist.item'] + for k_vr, v_vr in cls.avails_tmp.iteritems(): + for i in range(0, len(v_vr)): + ndate = now_utc_dt + timedelta(days=i) + vroom_avail_obj.create({ + 'virtual_room_id': k_vr, + 'avail': v_vr[i], + 'date': ndate.strftime(DEFAULT_SERVER_DATE_FORMAT) + }) + vroom_rest_item_obj.create({ + 'virtual_room_id': k_vr, + 'restriction_id': cls.parity_restrictions_id, + 'date_start': ndate.strftime(DEFAULT_SERVER_DATE_FORMAT), + 'date_end': ndate.strftime(DEFAULT_SERVER_DATE_FORMAT), + 'applied_on': '0_virtual_room', + 'min_stay': cls.restrictions_min_stay_tmp[k_vr][i], + }) + pricelist_item_obj.create({ + 'pricelist_id': cls.parity_pricelist_id, + 'date_start': ndate.strftime(DEFAULT_SERVER_DATE_FORMAT), + 'date_end': ndate.strftime(DEFAULT_SERVER_DATE_FORMAT), + 'compute_price': 'fixed', + 'applied_on': '1_product', + 'product_tmpl_id': product_tmpl_ids[k_vr], + 'fixed_price': cls.prices_tmp[k_vr][i], + }) diff --git a/hotel/tests/test_folio.py b/hotel/tests/test_folio.py new file mode 100644 index 000000000..af45fa8b8 --- /dev/null +++ b/hotel/tests/test_folio.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from datetime import timedelta +from .common import TestHotel +from odoo.addons.hotel import date_utils + + +class TestHotelReservations(TestHotel): + + def test_cancel_folio(self): + now_utc_dt = date_utils.now() + + org_reserv_start_utc_dt = now_utc_dt + timedelta(days=3) + org_reserv_end_utc_dt = org_reserv_start_utc_dt + timedelta(days=6) + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation_a = self.create_reservation( + self.user_hotel_manager, + folio, + org_reserv_start_utc_dt, + org_reserv_end_utc_dt, + self.hotel_room_double_200, + "Reservation Test #1") + reservation_b = self.create_reservation( + self.user_hotel_manager, + folio, + org_reserv_start_utc_dt, + org_reserv_end_utc_dt, + self.hotel_room_simple_100, + "Reservation Test #2") + self.assertEqual(len(folio.room_lines), 2, 'Invalid room lines count') + folio.action_cancel() + self.assertEqual(folio.state, 'cancel', 'Invalid folio state') + for rline in folio.room_lines: + self.assertEqual(rline.state, 'cancelled', + 'Invalid reservation state') diff --git a/hotel/tests/test_reservation.py b/hotel/tests/test_reservation.py new file mode 100644 index 000000000..687f7e25e --- /dev/null +++ b/hotel/tests/test_reservation.py @@ -0,0 +1,260 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +import datetime +from datetime import timedelta +from odoo import fields +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT +from openerp.exceptions import ValidationError +from .common import TestHotel +from odoo.addons.hotel import date_utils +import pytz +import logging +_logger = logging.getLogger(__name__) + + +class TestHotelReservations(TestHotel): + + def test_create_reservation(self): + now_utc_dt = date_utils.now() + reserv_start_utc_dt = now_utc_dt + timedelta(days=3) + reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3) + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_double_200, + "Reservation Test #1") + + reserv_start_dt = date_utils.dt_as_timezone(reserv_start_utc_dt, + self.tz_hotel) + reserv_end_dt = date_utils.dt_as_timezone(reserv_end_utc_dt - + timedelta(days=1), + self.tz_hotel) + self.assertEqual(reservation.reservation_lines[0].date, + reserv_start_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), + "Reservation lines don't start in the correct date") + self.assertEqual(reservation.reservation_lines[-1].date, + reserv_end_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), + "Reservation lines don't end in the correct date") + + total_price = 0.0 + for rline in reservation.reservation_lines: + total_price += rline.price + self.assertEqual(folio.amount_untaxed, total_price, + "Folio amount doesn't match with reservation lines") + + def test_create_reservations(self): + now_utc_dt = date_utils.now() + reserv_start_utc_dt = now_utc_dt + timedelta(days=3) + reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3) + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_double_200, + "Reservation Test #1") + + reserv_start_utc_dt = reserv_end_utc_dt + reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3) + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_double_200, + "Reservation Test #2") + + reserv_end_utc_dt = now_utc_dt + timedelta(days=3) + reserv_start_utc_dt = reserv_end_utc_dt - timedelta(days=1) + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_double_200, + "Reservation Test #3") + + reserv_start_utc_dt = now_utc_dt + timedelta(days=3) + reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3) + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_simple_100, + "Reservation Test #4") + + def test_create_invalid_reservations(self): + now_utc_dt = date_utils.now() + + org_reserv_start_utc_dt = now_utc_dt + timedelta(days=3) + org_reserv_end_utc_dt = org_reserv_start_utc_dt + timedelta(days=6) + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + org_reserv_start_utc_dt, + org_reserv_end_utc_dt, + self.hotel_room_double_200, + "Original Reservation Test #1") + + # Same Dates + reserv_start_utc_dt = now_utc_dt + timedelta(days=3) + reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=6) + with self.assertRaises(ValidationError): + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_double_200, + "Invalid Reservation Test #1") + + # Inside Org Reservation (Start Same Date) + reserv_start_utc_dt = now_utc_dt + timedelta(days=3) + reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3) + with self.assertRaises(ValidationError): + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_double_200, + "Invalid Reservation Test #2") + + # Inside Org Reservation (Start after) + reserv_start_utc_dt = now_utc_dt + timedelta(days=4) + reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3) + with self.assertRaises(ValidationError): + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_double_200, + "Invalid Reservation Test #3") + + # Intersect Org Reservation (Start before) + reserv_start_utc_dt = now_utc_dt + timedelta(days=2) + reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3) + with self.assertRaises(ValidationError): + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_double_200, + "Invalid Reservation Test #4") + + # Intersect Org Reservation (End Same) + reserv_start_utc_dt = org_reserv_end_utc_dt - timedelta(days=2) + reserv_end_utc_dt = org_reserv_end_utc_dt + with self.assertRaises(ValidationError): + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_double_200, + "Invalid Reservation Test #5") + + # Intersect Org Reservation (End after) + reserv_start_utc_dt = org_reserv_end_utc_dt - timedelta(days=2) + reserv_end_utc_dt = org_reserv_end_utc_dt + timedelta(days=3) + with self.assertRaises(ValidationError): + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_double_200, + "Invalid Reservation Test #6") + + # Overlays Org Reservation + reserv_start_utc_dt = org_reserv_start_utc_dt - timedelta(days=2) + reserv_end_utc_dt = org_reserv_end_utc_dt + timedelta(days=2) + with self.assertRaises(ValidationError): + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + reserv_start_utc_dt, + reserv_end_utc_dt, + self.hotel_room_double_200, + "Invalid Reservation Test #7") + + # Checkin > Checkout + with self.assertRaises(ValidationError): + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + org_reserv_end_utc_dt, + org_reserv_start_utc_dt, + self.hotel_room_simple_100, + "Invalid Reservation Test #8") + + def test_modify_reservation(self): + now_utc_dt = date_utils.now() + + # 5.0, 15.0, 15.0, 35.0, 35.0, 10.0, 10.0 + + vroom_prices = self.prices_tmp[self.hotel_room_double_200.price_virtual_room.id] + org_reserv_start_utc_dt = now_utc_dt + timedelta(days=1) + org_reserv_end_utc_dt = org_reserv_start_utc_dt + timedelta(days=2) + folio = self.create_folio(self.user_hotel_manager, self.partner_2) + reservation = self.create_reservation( + self.user_hotel_manager, + folio, + org_reserv_start_utc_dt, + org_reserv_end_utc_dt, + self.hotel_room_double_200, + "Original Reservation Test #1") + ndate = org_reserv_start_utc_dt + for r_k, r_v in enumerate(reservation.reservation_lines): + self.assertEqual(r_v.date, ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)) + self.assertEqual(r_v.price, vroom_prices[r_k+1]) + ndate = ndate + timedelta(days=1) + self.assertEqual(reservation.amount_room, 30.0) + ndate = org_reserv_start_utc_dt + timedelta(days=1) + line = reservation.reservation_lines.filtered(lambda r: r.date == ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)) + reservation.reservation_lines = [(1, line.id, {'price': 100.0})] + self.assertEqual(reservation.amount_room, 115.0) + reservation.sudo(self.user_hotel_manager).write({ + 'checkin': (org_reserv_start_utc_dt + timedelta(days=1)).strftime(DEFAULT_SERVER_DATE_FORMAT), + 'checkout': (org_reserv_end_utc_dt + timedelta(days=1)).strftime(DEFAULT_SERVER_DATE_FORMAT), + }) + self.assertEqual(reservation.amount_room, 135.0) diff --git a/hotel/views/cardex.xml b/hotel/views/cardex.xml new file mode 100644 index 000000000..e5b7dfa4f --- /dev/null +++ b/hotel/views/cardex.xml @@ -0,0 +1,57 @@ + + + + + + + + + + Cardex Form + cardex + +
+ + + + + + + + + + + + +
+
+
+ + + Cardex Tree + cardex + + + + + + + + + + + +
diff --git a/hotel/views/currency_exchange.xml b/hotel/views/currency_exchange.xml new file mode 100644 index 000000000..1efd9fba3 --- /dev/null +++ b/hotel/views/currency_exchange.xml @@ -0,0 +1,86 @@ + + + + + + + currency.exchange.form + currency.exchange + +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +

+ +
+
+
+
+ + + + currency.exchange.tree + currency.exchange + + + + + + + + + + + + + Currency Exchange + currency.exchange + form + tree,form + + +
diff --git a/hotel/views/hotel_dashboard.xml b/hotel/views/hotel_dashboard.xml new file mode 100644 index 000000000..f214e9310 --- /dev/null +++ b/hotel/views/hotel_dashboard.xml @@ -0,0 +1,210 @@ + + + + + Folios + hotel.dashboard + + + + Folios + hotel.dashboard + + + + Folios + hotel.dashboard + + + + Folios + hotel.dashboard + + + + hotel.dashboard.view + hotel.dashboard + + + + + + + Hotel Dashboard + hotel.dashboard + ir.actions.act_window + form + {} + kanban + + + + + + + + + Chekins Dashboard + sales + bar + 1 + + + On Board + sales + line + 1 + + + + diff --git a/hotel/views/hotel_floor.xml b/hotel/views/hotel_floor.xml new file mode 100644 index 000000000..39012071a --- /dev/null +++ b/hotel/views/hotel_floor.xml @@ -0,0 +1,45 @@ + + + + + + + hotel.floor.form + hotel.floor + +
+ + + + + + +
+
+
+ + + + hotel.floor.tree + hotel.floor + + + + + + + + + + + Floor Structure + hotel.floor + form + tree,form + + + + +
diff --git a/hotel/views/hotel_folio.xml b/hotel/views/hotel_folio.xml new file mode 100644 index 000000000..3ac843ffb --- /dev/null +++ b/hotel/views/hotel_folio.xml @@ -0,0 +1,611 @@ + + + + + + + hotel.folio.form + hotel.folio + +
+
+ + + +
+ + +
+ + + + + + + + + + + + + + + +
+ +

+

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cancelled Reservation! + OverBooking! +

+ + + + + +

+

+ From

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+
+ + + + hotel.reservation.tree + hotel.reservation + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + hotel.room.search + hotel.room + + + + + + + + + + + + + + + + hotel.room.tree + hotel.room + + + + + + + + + + + + + + + + + Hotel Room + hotel.room + form + + + kanban,tree,form + + + + + + + + + + + + + + + + +
diff --git a/hotel/views/hotel_room_amenities.xml b/hotel/views/hotel_room_amenities.xml new file mode 100644 index 000000000..757230b76 --- /dev/null +++ b/hotel/views/hotel_room_amenities.xml @@ -0,0 +1,131 @@ + + + + + + + hotel.room.amenities.form + hotel.room.amenities + +
+ +

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + hotel.room_amenities_search + hotel.room.amenities + + + + + + + + + + + + + + + + hotel.room_amenities_list + hotel.room.amenities + + + + + + + + + + + + Hotel Room Amenities + hotel.room.amenities + form + tree,form + + + + + + + + + + + + + +
diff --git a/hotel/views/hotel_room_amenities_type.xml b/hotel/views/hotel_room_amenities_type.xml new file mode 100644 index 000000000..f7906c879 --- /dev/null +++ b/hotel/views/hotel_room_amenities_type.xml @@ -0,0 +1,48 @@ + + + + + + + hotel.room_amenities_type_form + hotel.room.amenities.type + +
+ + + + + + + +
+
+
+ + + + hotel.room_amenities_type_list + hotel.room.amenities.type + + + + + + + + + + Hotel Room Amenities Type + hotel.room.amenities.type + + form + tree,form + + + + + +
diff --git a/hotel/views/hotel_room_type.xml b/hotel/views/hotel_room_type.xml new file mode 100644 index 000000000..47f786d86 --- /dev/null +++ b/hotel/views/hotel_room_type.xml @@ -0,0 +1,77 @@ + + + + + + hotel.room_type.form + hotel.room.type + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + hotel.room_type.tree + hotel.room.type + + + + + + + + + + + + + + + + Room Type + hotel.room.type + form + + tree,form + + + + +
diff --git a/hotel/views/hotel_sequence.xml b/hotel/views/hotel_sequence.xml new file mode 100644 index 000000000..10231a31f --- /dev/null +++ b/hotel/views/hotel_sequence.xml @@ -0,0 +1,14 @@ + + + + + + + Hotel Folio + hotel.folio + F/ + 5 + + + + diff --git a/hotel/views/hotel_service.xml b/hotel/views/hotel_service.xml new file mode 100644 index 000000000..c6c65a540 --- /dev/null +++ b/hotel/views/hotel_service.xml @@ -0,0 +1,135 @@ + + + + + + .hotel.service.form + hotel.service + +
+ +

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + hotel.service.search + hotel.service + + + + + + + + + + + + + + + + hotel.service.tree + hotel.service + + + + + + + + + + + + Hotel Services + hotel.service + form + + tree,form + + + + + + + + Services by Category + ir.actions.act_window + product.category + + tree + + + + + + + +
diff --git a/hotel/views/hotel_service_line.xml b/hotel/views/hotel_service_line.xml new file mode 100644 index 000000000..f10d988de --- /dev/null +++ b/hotel/views/hotel_service_line.xml @@ -0,0 +1,63 @@ + + + + + + + hotel.service.line.form + hotel.service.line + +
+ + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + hotel.service.line.tree + hotel.service.line + + + + + + + + + + + Hotel Services + hotel.service.line + form + + tree,form + + + + +
diff --git a/hotel/views/hotel_service_type.xml b/hotel/views/hotel_service_type.xml new file mode 100644 index 000000000..c657d358b --- /dev/null +++ b/hotel/views/hotel_service_type.xml @@ -0,0 +1,48 @@ + + + + + + + hotel.service_type.form + hotel.service.type + +
+ + + + + + + +
+
+
+ + + + hotel.service_type.tree + hotel.service.type + + + + + + + + + + Service Type + hotel.service.type + + form + tree,form + + + + +
diff --git a/hotel/views/inherit_account_invoice_views.xml b/hotel/views/inherit_account_invoice_views.xml new file mode 100644 index 000000000..f53262223 --- /dev/null +++ b/hotel/views/inherit_account_invoice_views.xml @@ -0,0 +1,26 @@ + + + + + account.invoice + + + + + + + + + + + + {'invisible': ['|',('from_folio','=',True)]} + + + + + diff --git a/hotel/views/inherit_account_payment_views.xml b/hotel/views/inherit_account_payment_views.xml new file mode 100644 index 000000000..c29f85854 --- /dev/null +++ b/hotel/views/inherit_account_payment_views.xml @@ -0,0 +1,72 @@ + + + + + account.payment + + + + + + + + + + account.payment.folio.form + account.payment + +
+ +
+
+ + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+ +
diff --git a/hotel/views/inherit_product_product.xml b/hotel/views/inherit_product_product.xml new file mode 100644 index 000000000..26a650cf4 --- /dev/null +++ b/hotel/views/inherit_product_product.xml @@ -0,0 +1,15 @@ + + + + + view.product.product.form.inherited + product.product + + + + + + + + + diff --git a/hotel/views/inherit_res_partner.xml b/hotel/views/inherit_res_partner.xml new file mode 100644 index 000000000..0101d2e24 --- /dev/null +++ b/hotel/views/inherit_res_partner.xml @@ -0,0 +1,42 @@ + + + + + Reservations + hotel.reservation + [('partner_id', '=',active_id)] + + + + Folios + hotel.folio + [('partner_id', '=',active_id)] + + + + hotel.view.partner.form + res.partner + + + + + + + + + + + + + + diff --git a/hotel/views/inherit_reservation_workflow.xml b/hotel/views/inherit_reservation_workflow.xml new file mode 100755 index 000000000..a00e64a73 --- /dev/null +++ b/hotel/views/inherit_reservation_workflow.xml @@ -0,0 +1,22 @@ + + + + + + checkin + function + action_reservation_checkin() + + + + + + done + + + + + %(launch_checkin_wizard)d + + + diff --git a/hotel/views/report_hotel_management.xml b/hotel/views/report_hotel_management.xml new file mode 100644 index 000000000..5e24f6971 --- /dev/null +++ b/hotel/views/report_hotel_management.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + diff --git a/hotel/views/res_config.xml b/hotel/views/res_config.xml new file mode 100644 index 000000000..2be495cfa --- /dev/null +++ b/hotel/views/res_config.xml @@ -0,0 +1,79 @@ + + + + + + res.config.settings.view.form.inherit.hotel + res.config.settings + + + + +
+

Hotel Parity

+
+
+
+
+
+
+

Hotel Default Hours

+
+
+
+
+
+
+
+
+
+
+
+
+ +
diff --git a/hotel/views/reservation_restriction_item_views.xml b/hotel/views/reservation_restriction_item_views.xml new file mode 100644 index 000000000..288db9d87 --- /dev/null +++ b/hotel/views/reservation_restriction_item_views.xml @@ -0,0 +1,56 @@ + + + + + + hotel.virtual.room.restriction.item.form + hotel.virtual.room.restriction.item + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + hotel.virtual.room.restriction.item.tree + hotel.virtual.room.restriction.item + + + + + + + + + + + + + +
diff --git a/hotel/views/reservation_restriction_views.xml b/hotel/views/reservation_restriction_views.xml new file mode 100644 index 000000000..910f0e9aa --- /dev/null +++ b/hotel/views/reservation_restriction_views.xml @@ -0,0 +1,61 @@ + + + + + + hotel.virtual.room.restriction.form + hotel.virtual.room.restriction + +
+ + +

+
+ + + +
+ + + + + + + + + + + + +
+
+
+
+
+ + + + hotel.virtual.room.restriction.tree + hotel.virtual.room.restriction + + + + + + + + + + + Reservation restrictions + hotel.virtual.room.restriction + form + tree,form + + + + + +
diff --git a/hotel/views/virtual_room_availability.xml b/hotel/views/virtual_room_availability.xml new file mode 100644 index 000000000..1b621aa43 --- /dev/null +++ b/hotel/views/virtual_room_availability.xml @@ -0,0 +1,59 @@ + + + + + + hotel.virtual.room.availability.form + hotel.virtual.room.availability + +
+ + + +

+
+ + + + + + +
+
+ + +
+
+
+
+ + + + hotel.virtual.room.availability.tree + hotel.virtual.room.availability + + + + + + + + + + + + + + + Virtual Room Availability + hotel.virtual.room.availability + form + tree,form + + + + + +
diff --git a/hotel/views/virtual_room_views.xml b/hotel/views/virtual_room_views.xml new file mode 100644 index 000000000..d57ed73c8 --- /dev/null +++ b/hotel/views/virtual_room_views.xml @@ -0,0 +1,72 @@ + + + + + + virtual.room.view.form + hotel.virtual.room + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + virtual.room.view.tree + hotel.virtual.room + + + + + + + + + + + + + + + Virtual Rooms + hotel.virtual.room + form + tree,form + + + + + +
diff --git a/hotel/wizard/__init__.py b/hotel/wizard/__init__.py new file mode 100644 index 000000000..ae08f23cd --- /dev/null +++ b/hotel/wizard/__init__.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Dario Lodeiros <> +# Alexandre Díaz +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from . import hotel_wizard +from . import folio_make_invoice_advance +from . import checkinwizard +from . import massive_changes +from . import split_reservation +from . import duplicate_reservation +from . import massive_price_reservation_days diff --git a/hotel/wizard/checkinwizard.py b/hotel/wizard/checkinwizard.py new file mode 100644 index 000000000..7c3959295 --- /dev/null +++ b/hotel/wizard/checkinwizard.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- + +import logging +from openerp import models, fields, api +from openerp.exceptions import UserError +from openerp.tools.translate import _ + +_logger = logging.getLogger(__name__) + +class Wizard(models.TransientModel): + _name = 'checkin.wizard' + + def default_enter_date(self): + if ('reservation_ids' and 'folio') in self.env.context: + ids = [item[1] for item in self.env.context.get('reservation_ids')] + reservations = self.env['hotel.reservation'].browse(ids) + for res in reservations: + return res.checkin + if 'enter_date' in self.env.context: + return self.env.context['enter_date'] + return False + + def default_exit_date(self): + if ('reservation_ids' and 'folio') in self.env.context: + ids = [item[1] for item in self.env.context.get('reservation_ids')] + reservations = self.env['hotel.reservation'].browse(ids) + for res in reservations: + return res.checkout + if 'exit_date' in self.env.context: + return self.env.context['exit_date'] + return False + + def default_reservation_id(self): + if ('reservation_ids' and 'folio') in self.env.context: + ids = [item[1] for item in self.env.context.get('reservation_ids')] + reservations = self.env['hotel.reservation'].browse(ids) + if len(reservations) == 1: + # return current room line (onlyone in this case) + return reservations + for res in reservations: + # return the first room line with free space for a cardex + # TODO: add 'done' to res.state condition... Maybe too restrictive right now + if res.cardex_count < (res.adults + res.children) and res.state not in ["cancelled"]: + return res + elif 'reservation_id' in self.env.context: + return self.env['hotel.reservation'].browse( + self.env.context['reservation_id']) + + _logger.info('default_reservation_id is FALSE') + return False + + def default_partner_id(self): + # no partner by default. User must search and choose one + return False + + def default_cardex_ids(self): + if ('reservation_ids' and 'folio') in self.env.context: + ids = [item[1] for item in self.env.context.get('reservation_ids')] + reservations = self.env['hotel.reservation'].browse(ids) + for res in reservations: + return res.cardex_ids + + def default_cardex_ids(self): + if ('reservation_ids' and 'folio') in self.env.context: + ids = [item[1] for item in self.env.context.get('reservation_ids')] + reservations = self.env['hotel.reservation'].browse(ids) + for res in reservations: + return res.segmentation_id + + ''' TODO: clean-up + def default_count_cardex(self): + if 'reservation_ids' and 'folio' in self.env.context: + ids = [item[1] for item in self.env.context['reservation_ids']] + reservations = self.env['hotel.reservation'].browse(ids) + for res in reservations: + return res.cardex_count + ''' + ''' TODO: clean-up + def default_pending_cardex(self): + if 'reservation_ids' and 'folio' in self.env.context: + ids = [item[1] for item in self.env.context['reservation_ids']] + reservations = self.env['hotel.reservation'].browse(ids) + for res in reservations: + return res.adults + res.children - res.cardex_count + ''' + ''' TODO: clean-up - list of checkins on smart button clean is not used anymore + def comp_checkin_list_visible(self): + if 'partner_id' in self.env.context: + self.list_checkin_cardex = False + return + ''' + def comp_checkin_edit(self): + if 'edit_cardex' in self.env.context: + return True + return False + + cardex_ids = fields.Many2many('cardex', 'reservation_id', + default=default_cardex_ids) + # count_cardex = fields.Integer('Cardex counter', + # default=default_count_cardex) + # pending_cardex = fields.Integer('Cardex pending', + # default=default_pending_cardex) + partner_id = fields.Many2one('res.partner', + default=default_partner_id) + reservation_id = fields.Many2one('hotel.reservation', + default=default_reservation_id) + enter_date = fields.Date(default=default_enter_date, + required=True) + exit_date = fields.Date(default=default_exit_date, + required=True) + + firstname_cardex = fields.Char('Firstname', + required=True) + lastname_cardex = fields.Char('Lastname', + required=True) + + email_cardex = fields.Char('E-mail') + + mobile_cardex = fields.Char('Mobile') + + segmentation_id = fields.Many2many( + related='reservation_id.folio_id.segmentation_ids') + + + ''' TODO: clean-up - list of checkins on smart button clean is not used anymore + list_checkin_cardex = fields.Boolean(compute=comp_checkin_list_visible, + default=True, store=True) + ''' + # edit_checkin_cardex = fields.Boolean(default=comp_checkin_edit, + # store=True) + + op_select_partner = fields.Selection([ + ('S', 'Select a partner for checkin'), + ('C', 'Create a new partner for checkin')], + default='S', + string='Partner for checkin') + # checkin mode: + # 0 - no selection made by the user, so hide the client fields + # 1 - select a client for update his values and do the checkin + # 2 - create a new client with the values and do the checkin + checkin_mode = fields.Integer(default=0) + + @api.multi + def action_save_check(self): + # prepare partner values + if self.op_select_partner == 'S': + partner_vals = { + 'id': self.partner_id.id, + 'firstname': self.firstname_cardex, + 'lastname': self.lastname_cardex, + 'email': self.email_cardex, + 'mobile': self.mobile_cardex, + } + self.partner_id.sudo().write(partner_vals); + elif self.op_select_partner == 'C': + partner_vals = { + 'firstname': self.firstname_cardex, + 'lastname': self.lastname_cardex, + 'email': self.email_cardex, + 'mobile': self.mobile_cardex, + } + new_partner = self.env['res.partner'].create(partner_vals) + self.partner_id = self.env['res.partner'].browse(new_partner.id) + + # prepare checkin values + cardex_val = { + 'partner_id': self.partner_id.id, + 'enter_date': self.enter_date, + 'exit_date': self.exit_date + } + record_id = self.env['hotel.reservation'].browse( + self.reservation_id.id) + # save the cardex for this reservation + record_id.write({ + 'cardex_ids': [(0, False, cardex_val)], + 'segmentation_id': self.segmentation_id, + }) + + # update the state of the current reservation + if record_id.cardex_count > 0: + record_id.state = 'booking' + record_id.is_checkin = False + folio = self.env['hotel.folio'].browse(self.reservation_id.folio_id.id) + folio.checkins_reservations -= 1 + + @api.onchange('reservation_id') + def change_enter_exit_date(self): + record_id = self.env['hotel.reservation'].browse( + self.reservation_id.id) + + self.enter_date = record_id.checkin + self.exit_date = record_id.checkout + + ''' trying to filter the reservations only to pending checkins ... + if 'reservation_ids' and 'folio' in self.env.context: + ids = [item[1] for item in self.env.context['reservation_ids']] + reservations = self.env['hotel.reservation'].browse(ids) + for res in reservations: + _logger.info('reservation cardex_count %d', res.cardex_count) + + # return { + # 'domain': {'reservation_id': [('folio_id','=', self.env.context['folio']), 'count_cardex','=','2']}, + # 'warning': {'title': "Warning", 'message': self.env.context['cardex_count']}, + # } + ''' + + @api.onchange('partner_id') + def onchange_partner_id(self): + # update partner fields + self.firstname_cardex = self.partner_id.firstname; + self.lastname_cardex = self.partner_id.lastname; + self.email_cardex = self.partner_id.email; + self.mobile_cardex = self.partner_id.mobile; + # show the checkin fields if a partner is selected + if self.op_select_partner == 'S' and self.partner_id.id != False: + self.checkin_mode = 1; + + @api.onchange('op_select_partner') + def onchange_op_select_partner(self): + # field one2many return false is record does not exist + if self.op_select_partner == 'S' and self.partner_id.id != False: + self.checkin_mode = 1; + # field one2many return 0 on empty record (nothing typed) + elif self.op_select_partner == 'C' and self.partner_id.id == 0: + self.checkin_mode = 2; diff --git a/hotel/wizard/checkinwizard.xml b/hotel/wizard/checkinwizard.xml new file mode 100644 index 000000000..ae3abc402 --- /dev/null +++ b/hotel/wizard/checkinwizard.xml @@ -0,0 +1,104 @@ + + + + + wizard.form2 + checkin.wizard + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+ + + Add Check + checkin.wizard + + new + + + + + + + +
diff --git a/hotel/wizard/duplicate_reservation.py b/hotel/wizard/duplicate_reservation.py new file mode 100644 index 000000000..528cd257f --- /dev/null +++ b/hotel/wizard/duplicate_reservation.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from datetime import datetime, timedelta +from openerp.exceptions import ValidationError +from openerp import models, fields, api, _ +from openerp.tools import ( + DEFAULT_SERVER_DATETIME_FORMAT, + DEFAULT_SERVER_DATE_FORMAT) + + +class DuplicateReservationWizard(models.TransientModel): + _name = 'hotel.wizard.duplicate.reservation' + + num = fields.Integer('Num. New Reservations', default=1, min=1) + + @api.multi + def duplicate_reservation(self): + self.ensure_one() + hotel_reservation_obj = self.env['hotel.reservation'] + reservation_id = hotel_reservation_obj.browse( + self.env.context.get('active_id')) + if not reservation_id: + return False + + if reservation_id.splitted: + raise ValidationError(_("Can't duplicate splitted reservations")) + + hotel_room_obj = self.env['hotel.room'] + hotel_vroom_obj = self.env['hotel.virtual.room'] + + room_id = hotel_room_obj.search([ + ('product_id', '=', reservation_id.product_id.id) + ], limit=1) + vroom_ids = hotel_vroom_obj.search([ + '|', ('room_ids', 'in', [room_id.id]), + ('room_type_ids', 'in', [room_id.categ_id.id]) + ]) + + cmds_reservation_lines = [] + for rline in reservation_id.reservation_lines: + cmds_reservation_lines.append((0, False, { + 'date': rline.date, + 'price': rline.price, + })) + + # Check Input + total_free_rooms = 0 + for vroom in vroom_ids: + avails = otel_vroom_obj.check_availability_virtual_room( + reservation_id.checkin, + reservation_id.checkout, + virtual_room_id=vroom.id) + total_free_rooms += len(avails) + + if total_free_rooms < self.num: + raise ValidationError(_("Too much duplicated reservations! \ + There are no '%d' free rooms") % self.num) + + for i in range(0, self.num): + for vroom in vroom_ids: + free_rooms = hotel_vroom_obj.check_availability_virtual_room( + reservation_id.checkin, + reservation_id.checkout, + virtual_room_id=vroom.id) + if any(free_rooms): + new_reservation_id = hotel_reservation_obj.create({ + 'product_id': free_rooms[0].product_id.id, + 'folio_id': reservation_id.folio_id.id, + 'checkin': reservation_id.checkin, + 'checkout': reservation_id.checkout, + 'adults': reservation_id.adults, + 'children': reservation_id.children, + 'name': reservation_id.name, + 'reservation_lines': cmds_reservation_lines, + 'price_unit': reservation_id.price_unit, + }) + if new_reservation_id: + rpartner_id = reservation_id.order_id.partner_id + new_reservation_id.order_id.partner_id = rpartner_id + break + else: + raise ValidationError(_("Unexpected Error: Can't found a \ + free room")) + return True diff --git a/hotel/wizard/duplicate_reservation.xml b/hotel/wizard/duplicate_reservation.xml new file mode 100644 index 000000000..ca87a7358 --- /dev/null +++ b/hotel/wizard/duplicate_reservation.xml @@ -0,0 +1,35 @@ + + + + + hotel.wizard.duplicate.reservation + hotel.wizard.duplicate.reservation + +
+ + + + +
+
+
+
+
+ + + Duplicate Reservation + ir.actions.act_window + hotel.wizard.duplicate.reservation + + form + form + new + + report + + +
diff --git a/hotel/wizard/folio_make_invoice_advance.py b/hotel/wizard/folio_make_invoice_advance.py new file mode 100644 index 000000000..1dbcaf5a8 --- /dev/null +++ b/hotel/wizard/folio_make_invoice_advance.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import time +from odoo import api, fields, models, _ +import odoo.addons.decimal_precision as dp +from odoo.exceptions import UserError + + +class FolioAdvancePaymentInv(models.TransientModel): + _name = "folio.advance.payment.inv" + _description = "Folios Advance Payment Invoice" + + @api.model + def _count(self): + return len(self._context.get('active_ids', [])) + + @api.model + def _get_advance_payment_method(self): + if self._count() == 1: + sale_obj = self.env['sale.order'] + folio_obj = self.env['hotel.folio'] + folio = folio_obj.browse(self._context.get('active_ids'))[0] + order = sale_obj.browse(folio_obj.mapped('order_id.id')) + if all([line.product_id.invoice_policy == 'order' for line in order.order_line]) or order.invoice_count: + return 'all' + return 'delivered' + + @api.model + def _default_product_id(self): + product_id = self.env['ir.default'].sudo().get('sale.config.settings', 'deposit_product_id_setting') + return self.env['product.product'].browse(product_id) + + @api.model + def _default_deposit_account_id(self): + return self._default_product_id().property_account_income_id + + @api.model + def _default_deposit_taxes_id(self): + return self._default_product_id().taxes_id + + advance_payment_method = fields.Selection([ + ('delivered', 'Invoiceable lines'), + ('all', 'Invoiceable lines (deduct down payments)'), + ('percentage', 'Down payment (percentage)'), + ('fixed', 'Down payment (fixed amount)') + ], string='What do you want to invoice?', default=_get_advance_payment_method, required=True) + product_id = fields.Many2one('product.product', string='Down Payment Product', domain=[('type', '=', 'service')], + default=_default_product_id) + count = fields.Integer(default=_count, string='# of Orders') + amount = fields.Float('Down Payment Amount', digits=dp.get_precision('Account'), help="The amount to be invoiced in advance, taxes excluded.") + deposit_account_id = fields.Many2one("account.account", string="Income Account", domain=[('deprecated', '=', False)], + help="Account used for deposits", default=_default_deposit_account_id) + deposit_taxes_id = fields.Many2many("account.tax", string="Customer Taxes", help="Taxes used for deposits", default=_default_deposit_taxes_id) + + @api.onchange('advance_payment_method') + def onchange_advance_payment_method(self): + if self.advance_payment_method == 'percentage': + return {'value': {'amount': 0}} + return {} + + @api.multi + def _create_invoice(self, order, so_line, amount): + inv_obj = self.env['account.invoice'] + ir_property_obj = self.env['ir.property'] + + account_id = False + if self.product_id.id: + account_id = self.product_id.property_account_income_id.id or self.product_id.categ_id.property_account_income_categ_id.id + if not account_id: + inc_acc = ir_property_obj.get('property_account_income_categ_id', 'product.category') + account_id = order.fiscal_position_id.map_account(inc_acc).id if inc_acc else False + if not account_id: + raise UserError( + _('There is no income account defined for this product: "%s". You may have to install a chart of account from Accounting app, settings menu.') % + (self.product_id.name,)) + + if self.amount <= 0.00: + raise UserError(_('The value of the down payment amount must be positive.')) + context = {'lang': order.partner_id.lang} + if self.advance_payment_method == 'percentage': + amount = order.amount_untaxed * self.amount / 100 + name = _("Down payment of %s%%") % (self.amount,) + else: + amount = self.amount + name = _('Down Payment') + del context + taxes = self.product_id.taxes_id.filtered(lambda r: not order.company_id or r.company_id == order.company_id) + if order.fiscal_position_id and taxes: + tax_ids = order.fiscal_position_id.map_tax(taxes).ids + else: + tax_ids = taxes.ids + + invoice = inv_obj.create({ + 'name': order.client_order_ref or order.name, + 'origin': order.name, + 'type': 'out_invoice', + 'reference': False, + 'account_id': order.partner_id.property_account_receivable_id.id, + 'partner_id': order.partner_invoice_id.id, + 'partner_shipping_id': order.partner_shipping_id.id, + 'invoice_line_ids': [(0, 0, { + 'name': name, + 'origin': order.name, + 'account_id': account_id, + 'price_unit': amount, + 'quantity': 1.0, + 'discount': 0.0, + 'uom_id': self.product_id.uom_id.id, + 'product_id': self.product_id.id, + 'sale_line_ids': [(6, 0, [so_line.id])], + 'invoice_line_tax_ids': [(6, 0, tax_ids)], + 'account_analytic_id': order.project_id.id or False, + })], + 'currency_id': order.pricelist_id.currency_id.id, + 'payment_term_id': order.payment_term_id.id, + 'fiscal_position_id': order.fiscal_position_id.id or order.partner_id.property_account_position_id.id, + 'team_id': order.team_id.id, + 'user_id': order.user_id.id, + 'comment': order.note, + }) + invoice.compute_taxes() + invoice.message_post_with_view('mail.message_origin_link', + values={'self': invoice, 'origin': order}, + subtype_id=self.env.ref('mail.mt_note').id) + return invoice + + @api.multi + def create_invoices(self): + folios = self.env['hotel.folio'].browse(self._context.get('active_ids', [])) + sale_orders = self.env['sale.order'].browse(folios.mapped('order_id.id')) + + if self.advance_payment_method == 'delivered': + sale_orders.action_invoice_create() + elif self.advance_payment_method == 'all': + sale_orders.action_invoice_create(final=True) + else: + # Create deposit product if necessary + if not self.product_id: + vals = self._prepare_deposit_product() + self.product_id = self.env['product.product'].create(vals) + self.env['ir.default'].sudo().set('sale.config.settings', 'deposit_product_id_setting', self.product_id.id) + + sale_line_obj = self.env['sale.order.line'] + for order in sale_orders: + if self.advance_payment_method == 'percentage': + amount = order.amount_untaxed * self.amount / 100 + else: + amount = self.amount + if self.product_id.invoice_policy != 'order': + raise UserError(_('The product used to invoice a down payment should have an invoice policy set to "Ordered quantities". Please update your deposit product to be able to create a deposit invoice.')) + if self.product_id.type != 'service': + raise UserError(_("The product used to invoice a down payment should be of type 'Service'. Please use another product or update this product.")) + taxes = self.product_id.taxes_id.filtered(lambda r: not order.company_id or r.company_id == order.company_id) + if order.fiscal_position_id and taxes: + tax_ids = order.fiscal_position_id.map_tax(taxes).ids + else: + tax_ids = taxes.ids + context = {'lang': order.partner_id.lang} + so_line = sale_line_obj.create({ + 'name': _('Advance: %s') % (time.strftime('%m %Y'),), + 'price_unit': amount, + 'product_uom_qty': 0.0, + 'order_id': order.id, + 'discount': 0.0, + 'product_uom': self.product_id.uom_id.id, + 'product_id': self.product_id.id, + 'tax_id': [(6, 0, tax_ids)], + }) + del context + self._create_invoice(order, so_line, amount) + if self._context.get('open_invoices', False): + return sale_orders.action_view_invoice() + return {'type': 'ir.actions.act_window_close'} + + def _prepare_deposit_product(self): + return { + 'name': 'Down payment', + 'type': 'service', + 'invoice_policy': 'order', + 'property_account_income_id': self.deposit_account_id.id, + 'taxes_id': [(6, 0, self.deposit_taxes_id.ids)], + } diff --git a/hotel/wizard/folio_make_invoice_advance_views.xml b/hotel/wizard/folio_make_invoice_advance_views.xml new file mode 100644 index 000000000..110dfbde3 --- /dev/null +++ b/hotel/wizard/folio_make_invoice_advance_views.xml @@ -0,0 +1,53 @@ + + + + Invoice Orders + folio.advance.payment.inv + +
+

+ Invoices will be created in draft so that you can review + them before validation. +

+ + + + + +
+
+
+
+
+ + + Invoice Order + ir.actions.act_window + folio.advance.payment.inv + form + form + new + + + +
diff --git a/hotel/wizard/hotel_wizard.py b/hotel/wizard/hotel_wizard.py new file mode 100644 index 000000000..6495b140b --- /dev/null +++ b/hotel/wizard/hotel_wizard.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Alexandre Díaz +# Copyright 2017 Dario Lodeiros +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from openerp import models, fields, api + + +class FolioReportWizard(models.TransientModel): + _name = 'folio.report.wizard' + _rec_name = 'date_start' + + date_start = fields.Datetime('Start Date') + date_end = fields.Datetime('End Date') + + @api.multi + def print_report(self): + data = { + 'ids': self.ids, + 'model': 'hotel.folio', + 'form': self.read(['date_start', 'date_end'])[0] + } + return self.env.ref('hotel.report_hotel_folio').report_action(self, data=data) diff --git a/hotel/wizard/hotel_wizard.xml b/hotel/wizard/hotel_wizard.xml new file mode 100644 index 000000000..1d6ff68c0 --- /dev/null +++ b/hotel/wizard/hotel_wizard.xml @@ -0,0 +1,35 @@ + + + + + folio.report.wizard + folio.report.wizard + +
+ + + + +
+
+
+
+
+ + + + Hotel Folio Report + folio.report.wizard + form + form + new + + + + +
diff --git a/hotel/wizard/massive_changes.py b/hotel/wizard/massive_changes.py new file mode 100644 index 000000000..26ad973f5 --- /dev/null +++ b/hotel/wizard/massive_changes.py @@ -0,0 +1,302 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from datetime import datetime, timedelta +from openerp.exceptions import ValidationError +from openerp import models, fields, api +from openerp.tools import ( + DEFAULT_SERVER_DATE_FORMAT, + DEFAULT_SERVER_DATETIME_FORMAT) +from odoo.addons.hotel import date_utils + + +class MassiveChangesWizard(models.TransientModel): + _name = 'hotel.wizard.massive.changes' + + # Common fields + section = fields.Selection([ + ('0', 'Availability'), + ('1', 'Restrictions'), + ('2', 'Pricelist'), + ], string='Section', default='0') + date_start = fields.Datetime('Start Date', required=True) + date_end = fields.Datetime('End Date', required=True) + dmo = fields.Boolean('Monday', default=True) + dtu = fields.Boolean('Tuesday', default=True) + dwe = fields.Boolean('Wednesday', default=True) + dth = fields.Boolean('Thursday', default=True) + dfr = fields.Boolean('Friday', default=True) + dsa = fields.Boolean('Saturday', default=True) + dsu = fields.Boolean('Sunday', default=True) + applied_on = fields.Selection([ + ('0', 'Global'), + ('1', 'Virtual Room'), + ], string='Applied On', default='0') + # virtual_room_ids = fields.Many2many('hotel.virtual.room', + # string="Virtual Rooms") + room_type_ids = fields.Many2many('hotel.room.type', + string="Room Types") + + # Availability fields + change_avail = fields.Boolean(default=False) + avail = fields.Integer('Avail', default=0) + change_no_ota = fields.Boolean(default=False) + no_ota = fields.Boolean('No OTA', default=False) + + # Restriction fields + restriction_id = fields.Many2one('hotel.virtual.room.restriction', + 'Restriction Plan') + change_min_stay = fields.Boolean(default=False) + min_stay = fields.Integer("Min. Stay") + change_min_stay_arrival = fields.Boolean(default=False) + min_stay_arrival = fields.Integer("Min. Stay Arrival") + change_max_stay = fields.Boolean(default=False) + max_stay = fields.Integer("Max. Stay") + change_max_stay_arrival = fields.Boolean(default=False) + max_stay_arrival = fields.Integer("Max. Stay Arrival") + change_closed = fields.Boolean(default=False) + closed = fields.Boolean('Closed') + change_closed_departure = fields.Boolean(default=False) + closed_departure = fields.Boolean('Closed Departure') + change_closed_arrival = fields.Boolean(default=False) + closed_arrival = fields.Boolean('Closed Arrival') + + # Pricelist fields + pricelist_id = fields.Many2one('product.pricelist', 'Pricelist') + price = fields.Char('Price', help="Can use '+','-' \ + or '%'...\nExamples:\n a) +12.3 \ + \t> Increase the price in 12.3\n \ + b) -1.45% \t> Substract 1.45%\n c) 45 \ + \t\t> Sets the price to 45") + + @api.onchange('date_start') + def onchange_date_start(self): + self.ensure_one() + self.date_end = self.date_start + + @api.multi + def is_valid_date(self, chkdate): + self.ensure_one() + date_start_dt = fields.Datetime.from_string(self.date_start) + date_end_dt = fields.Datetime.from_string(self.date_end) + wday = chkdate.timetuple()[6] + wedays = (self.dmo, self.dtu, self.dwe, self.dth, self.dfr, self.dsa, + self.dsu) + return (chkdate >= self.date_start and chkdate <= self.date_end + and wedays[wday]) + + @api.model + def _save_prices(self, ndate, vrooms, record): + product_pricelist_item_obj = self.env['product.pricelist.item'] + price = 0.0 + operation = 'a' + if record.price[0] == '+' or record.price[0] == '-': + if record.price[-1] == '%': + price = float(record.price[1:-1]) + operation = (record.price[0] == '+') and 'ap' or 'sp' + else: + price = float(record.price[1:]) + operation = (record.price[0] == '+') and 'a' or 's' + else: + if record.price[-1] == '%': + price = float(record.price[:-1]) + operation = 'np' + else: + price = float(record.price) + operation = 'n' + + domain = [ + ('pricelist_id', '=', record.pricelist_id.id), + ('date_start', '>=', ndate.strftime( + DEFAULT_SERVER_DATE_FORMAT)), + ('date_end', '<=', ndate.strftime( + DEFAULT_SERVER_DATE_FORMAT)), + ('compute_price', '=', 'fixed'), + ('applied_on', '=', '1_product'), + ] + + product_tmpl_ids = vrooms.mapped( + 'product_id.product_tmpl_id') + for vroom in vrooms: + prod_tmpl_id = vroom.product_id.product_tmpl_id + pricelist_item_ids = product_pricelist_item_obj.search( + domain+[('product_tmpl_id', '=', prod_tmpl_id.id)]) + if any(pricelist_item_ids): + if operation != 'n': + for pli in pricelist_item_ids: + pli_price = pli.fixed_price + if operation == 'a': + pli.write({ + 'fixed_price': pli_price + price}) + elif operation == 'ap': + pli.write({'fixed_price': pli_price + price * pli_price * 0.01}) + elif operation == 's': + pli.write({ + 'fixed_price': pli_price - price}) + elif operation == 'sp': + pli.write({'fixed_price': pli_price - price * pli_price * 0.01}) + elif operation == 'np': + pli.write({'fixed_price': price * pli_price * 0.01}) + else: + pricelist_item_ids.write({'fixed_price': price}) + else: + product_pricelist_item_obj.create({ + 'pricelist_id': record.pricelist_id.id, + 'date_start': ndate.strftime( + DEFAULT_SERVER_DATE_FORMAT), + 'date_end': ndate.strftime( + DEFAULT_SERVER_DATE_FORMAT), + 'compute_price': 'fixed', + 'applied_on': '1_product', + 'product_tmpl_id': prod_tmpl_id.id, + 'fixed_price': price, + }) + + @api.model + def _get_restrictions_values(self, ndate, vroom, record): + vals = {} + if record.change_min_stay: + vals.update({'min_stay': record.min_stay}) + if record.change_min_stay_arrival: + vals.update({'min_stay_arrival': record.min_stay_arrival}) + if record.change_max_stay: + vals.update({'max_stay': record.max_stay}) + if record.change_max_stay_arrival: + vals.update({'max_stay_arrival': record.max_stay_arrival}) + if record.change_closed: + vals.update({'closed': record.closed}) + if record.change_closed_departure: + vals.update({'closed_departure': record.closed_departure}) + if record.change_closed_arrival: + vals.update({'closed_arrival': record.closed_arrival}) + return vals + + @api.model + def _save_restrictions(self, ndate, vrooms, record): + hotel_vroom_re_it_obj = self.env['hotel.virtual.room.restriction.item'] + domain = [ + ('date_start', '>=', ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)), + ('date_end', '<=', ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)), + ('restriction_id', '=', record.restriction_id.id), + ('applied_on', '=', '0_virtual_room'), + ] + + for vroom in vrooms: + vals = self._get_restrictions_values(ndate, vroom, record) + if not any(vals): + continue + + rrest_item_ids = hotel_vroom_re_it_obj.search( + domain+[('virtual_room_id', '=', vroom.id)]) + if any(rrest_item_ids): + rrest_item_ids.write(vals) + else: + vals.update({ + 'date_start': ndate.strftime(DEFAULT_SERVER_DATE_FORMAT), + 'date_end': ndate.strftime(DEFAULT_SERVER_DATE_FORMAT), + 'restriction_id': record.restriction_id.id, + 'virtual_room_id': vroom.id, + 'applied_on': '0_virtual_room', + }) + hotel_vroom_re_it_obj.create(vals) + + @api.model + def _get_availability_values(self, ndate, vroom, record): + hotel_vroom_obj = self.env['hotel.virtual.room'] + vals = {} + if record.change_no_ota: + vals.update({'no_ota': record.no_ota}) + if record.change_avail: + cavail = len(hotel_vroom_obj.check_availability_virtual_room( + ndate.strftime(DEFAULT_SERVER_DATETIME_FORMAT), + ndate.strftime(DEFAULT_SERVER_DATETIME_FORMAT), + virtual_room_id=vroom.id)) + vals.update({ + 'avail': min(cavail, vroom.total_rooms_count, record.avail), + }) + return vals + + @api.model + def _save_availability(self, ndate, vrooms, record): + hotel_vroom_obj = self.env['hotel.virtual.room'] + hotel_vroom_avail_obj = self.env['hotel.virtual.room.availability'] + domain = [('date', '=', ndate.strftime(DEFAULT_SERVER_DATE_FORMAT))] + + for vroom in vrooms: + vals = self._get_availability_values(ndate, vroom, record) + if not any(vals): + continue + + vrooms_avail = hotel_vroom_avail_obj.search( + domain+[('virtual_room_id', '=', vroom.id)] + ) + if any(vrooms_avail): + # Mail module want a singleton + for vr_avail in vrooms_avail: + vr_avail.write(vals) + else: + vals.update({ + 'date': ndate.strftime(DEFAULT_SERVER_DATE_FORMAT), + 'virtual_room_id': vroom.id + }) + hotel_vroom_avail_obj.with_context({ + 'mail_create_nosubscribe': True, + }).create(vals) + + @api.multi + def massive_change_close(self): + self._do_massive_change() + return True + + @api.multi + def massive_change(self): + self._do_massive_change() + return { + "type": "ir.actions.do_nothing", + } + + @api.multi + def _do_massive_change(self): + hotel_vroom_obj = self.env['hotel.virtual.room'] + for record in self: + date_start_dt = date_utils.get_datetime(record.date_start, + hours=False) + # Use min '1' for same date + diff_days = date_utils.date_diff(record.date_start, + record.date_end, + hours=False) + 1 + wedays = (record.dmo, record.dtu, record.dwe, record.dth, + record.dfr, record.dsa, record.dsu) + vrooms = record.applied_on == '1' and record.room_type_id \ + or hotel_vroom_obj.search([]) + + for i in range(0, diff_days): + ndate = date_start_dt + timedelta(days=i) + if not wedays[ndate.timetuple()[6]]: + continue + + if record.section == '0': + self._save_availability(ndate, vrooms, record) + elif record.section == '1': + self._save_restrictions(ndate, vrooms, record) + elif record.section == '2': + self._save_prices(ndate, vrooms, record) + return True diff --git a/hotel/wizard/massive_changes.xml b/hotel/wizard/massive_changes.xml new file mode 100644 index 000000000..54ad251db --- /dev/null +++ b/hotel/wizard/massive_changes.xml @@ -0,0 +1,113 @@ + + + + + hotel.wizard.massive.changes + hotel.wizard.massive.changes + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Avail
No OTA
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Stay Min.
Stay Max.
Stay Min. Arrival
Stay Max. Arrival
Closed
Closed Departure
Closed Arrival
+
+ + + + + +
+
+
+
+
+ + + Hotel Massive Change + ir.actions.act_window + hotel.wizard.massive.changes + + form + form + new + + +
diff --git a/hotel/wizard/massive_price_reservation_days.py b/hotel/wizard/massive_price_reservation_days.py new file mode 100644 index 000000000..5860a61d8 --- /dev/null +++ b/hotel/wizard/massive_price_reservation_days.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +from openerp import models, fields, api + + +class MassivePriceChangeWizard(models.TransientModel): + _name = 'hotel.wizard.massive.price.reservation.days' + + new_price = fields.Float('New Price', default=1, min=1) + + @api.multi + def massive_price_change_days(self): + self.ensure_one() + hotel_reservation_obj = self.env['hotel.reservation'] + reservation_id = hotel_reservation_obj.browse( + self.env.context.get('active_id')) + if not reservation_id: + return False + + cmds = [] + for rline in reservation_id.reservation_lines: + cmds.append(( + 1, + rline.id, + { + 'price': self.new_price + } + )) + reservation_id.write({ + 'reservation_lines': cmds + }) + # FIXME: For some reason need force reservation price calcs + reservation_id._computed_amount_reservation() + # FIXME: Workaround for dispatch updated price + reservation_id.folio_id.write({ + 'room_lines': [ + ( + 1, + reservation_id.id, { + 'reservation_lines': cmds + } + ) + ] + }) + + return True diff --git a/hotel/wizard/massive_price_reservation_days.xml b/hotel/wizard/massive_price_reservation_days.xml new file mode 100644 index 000000000..f361a5d8e --- /dev/null +++ b/hotel/wizard/massive_price_reservation_days.xml @@ -0,0 +1,32 @@ + + + + + hotel.wizard.massive.price.reservation.days + hotel.wizard.massive.price.reservation.days + +
+ + + +
+
+
+
+
+ + + Massive Price Change + ir.actions.act_window + hotel.wizard.massive.price.reservation.days + + form + form + new + + +
diff --git a/hotel/wizard/split_reservation.py b/hotel/wizard/split_reservation.py new file mode 100644 index 000000000..36db0b7e1 --- /dev/null +++ b/hotel/wizard/split_reservation.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017 Solucións Aloxa S.L. +# Alexandre Díaz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## +import logging +from datetime import datetime, timedelta +from openerp.exceptions import ValidationError +from openerp import models, fields, api, _ +from openerp.tools import ( + DEFAULT_SERVER_DATETIME_FORMAT, + DEFAULT_SERVER_DATE_FORMAT) +from odoo.addons.hotel import date_utils +_logger = logging.getLogger(__name__) + + +class SplitReservationWizard(models.TransientModel): + _name = 'hotel.wizard.split.reservation' + + nights = fields.Integer('Nights', default=1, min=1) + + @api.multi + def split_reservation(self): + reservation_id = self.env['hotel.reservation'].browse( + self.env.context.get('active_id')) + if reservation_id: + date_start_dt = date_utils.get_datetime(reservation_id.checkin) + date_end_dt = date_utils.get_datetime(reservation_id.checkout) + date_diff = date_utils.date_diff(date_start_dt, date_end_dt, + hours=False) + for record in self: + new_start_date_dt = date_start_dt + \ + timedelta(days=date_diff-record.nights) + if record.nights >= date_diff or record.nights < 1: + raise ValidationError(_("Invalid Nights! Max is \ + '%d'") % (date_diff-1)) + + vals = reservation_id.generate_copy_values( + new_start_date_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), + date_end_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), + ) + # Days Price + reservation_lines = [[], []] + tprice = [0.0, 0.0] + div_dt = date_utils.dt_no_hours(new_start_date_dt) + for rline in reservation_id.reservation_lines: + rline_dt = date_utils.get_datetime(rline.date, hours=False) + if rline_dt >= div_dt: + reservation_lines[1].append((0, False, { + 'date': rline.date, + 'price': rline.price + })) + tprice[1] += rline.price + reservation_lines[0].append((2, rline.id, False)) + else: + tprice[0] += rline.price + + reservation_id.write({ + 'checkout': new_start_date_dt.strftime( + DEFAULT_SERVER_DATETIME_FORMAT), + 'price_unit': tprice[0], + 'splitted': True, + }) + reservation_id.reservation_lines = reservation_lines[0] + parent_res = reservation_id.parent_reservation or \ + reservation_id + vals.update({ + 'splitted': True, + 'price_unit': tprice[1], + 'parent_reservation': parent_res.id, + 'virtual_room_id': parent_res.virtual_room_id.id, + 'discount': parent_res.discount, + }) + reservation_copy = self.env['hotel.reservation'].create(vals) + if not reservation_copy: + raise ValidationError(_("Unexpected error copying record. \ + Can't split reservation!")) + reservation_copy.reservation_lines = reservation_lines[1] + # return { + # 'type': 'ir.actions.act_window', + # 'res_model': 'hotel.folio', + # 'views': [[False, "form"]], + # 'target': 'new', + # 'res_id': reservation_id.folio_id.id, + # } + return True diff --git a/hotel/wizard/split_reservation.xml b/hotel/wizard/split_reservation.xml new file mode 100644 index 000000000..cf4f1574c --- /dev/null +++ b/hotel/wizard/split_reservation.xml @@ -0,0 +1,33 @@ + + + + + hotel.wizard.split.reservation + hotel.wizard.split.reservation + +
+ + + + +
+
+
+
+
+ + + Split Reservation + ir.actions.act_window + hotel.wizard.split.reservation + + form + form + new + + +