[IMP] Precommit

This commit is contained in:
Darío Lodeiros
2020-08-01 22:36:39 +02:00
parent aac22ef43f
commit 80c43faa25
106 changed files with 7510 additions and 5824 deletions

View File

@@ -10,28 +10,34 @@ 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
- expect-dev # provides unbuffer utility
- python-lxml # because pip installation is slow
env:
global:
- VERSION="11.0" TESTS="0" LINT_CHECK="0" TRANSIFEX="0" MAKEPOT="0"
# - TRANSIFEX_USER='transbot@odoo-community.org'
# - secure: "XLhGdCIh86zcqww9qBpnk8Xqsf1Pcgw9SKr7X0KYBHJofHj4Z6Kq/oVFjpZ1LSjadsaABKbwY7h4hvKEpxZwptCv+fNTOKYy7hXFLGYnDeNeWu4zA4LI7TA5uPvyZjZ+g2xc+9dzR/VbfRHNqjvmgiEidxxqLeOnNFZ5CHdOdCw="
- VERSION="11.0" TESTS="0" LINT_CHECK="0" TRANSIFEX="0" MAKEPOT="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"
# Option temporarily disabled
#- LINT_CHECK="1"
- TESTS="1" ODOO_REPO="odoo/odoo"
- TESTS="1" ODOO_REPO="OCA/OCB"
install:
- git clone https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools --depth=1
- git clone https://github.com/OCA/maintainer-quality-tools.git
${HOME}/maintainer-quality-tools --depth=1
- export PATH=${HOME}/maintainer-quality-tools/travis:${PATH}
- 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 --depth=1
- git clone -b ${VERSION} https://github.com/OCA/connector.git ${HOME}/dependencies/connector --depth=1
- git clone -b ${VERSION} https://github.com/OCA/queue.git ${HOME}/dependencies/queue --depth=1
- 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 --depth=1
- git clone -b ${VERSION} https://github.com/OCA/connector.git
${HOME}/dependencies/connector --depth=1
- git clone -b ${VERSION} https://github.com/OCA/queue.git ${HOME}/dependencies/queue
--depth=1
- pip install odoorpc
- pip install cachetools>=2.0.1
- travis_install_nightly

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models
from . import wizard

View File

@@ -2,79 +2,75 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'PMS (Property Management System)',
'summary': "A property management system",
'version': '13.0.1.0.0',
'development_status': 'Beta',
'category': 'Generic Modules/Property Management System',
'website': 'https://github.com/hootel/hootel',
'author': 'Darío Lodeiros, '
'Alexandre Díaz, '
'Jose Luis Algara, '
'Pablo Quesada ',
'license': "AGPL-3",
'application': True,
'installable': True,
'depends': [
'base',
'mail',
'account_payment_return',
'partner_firstname',
'email_template_qweb',
'sales_team',
'sale'
"name": "PMS (Property Management System)",
"summary": "A property management system",
"version": "13.0.1.0.0",
"development_status": "Beta",
"category": "Generic Modules/Property Management System",
"website": "https://github.com/hootel/hootel",
"author": "Darío Lodeiros, "
"Alexandre Díaz, "
"Jose Luis Algara, "
"Pablo Quesada ",
"license": "AGPL-3",
"application": True,
"installable": True,
"depends": [
"base",
"mail",
"account_payment_return",
"partner_firstname",
"email_template_qweb",
"sales_team",
"sale",
],
'data': [
'security/pms_security.xml',
'security/ir.model.access.csv',
'data/cron_jobs.xml',
'data/pms_data.xml',
'data/pms_sequence.xml',
'data/email_template_cancel.xml',
'data/email_template_reserv.xml',
'data/email_template_exit.xml',
'report/pms_folio.xml',
'report/pms_folio_templates.xml',
'templates/pms_email_template.xml',
'wizard/massive_changes.xml',
'wizard/massive_price_reservation_days.xml',
'wizard/service_on_day.xml',
'wizard/split_reservation.xml',
'wizard/wizard_reservation.xml',
'views/general.xml',
'data/menus.xml',
'views/pms_amenity_views.xml',
'views/pms_amenity_type_views.xml',
'views/pms_board_service_views.xml',
'views/pms_board_service_room_type_views.xml',
'views/pms_cancelation_rule_views.xml',
'views/pms_checkin_partner_views.xml',
'views/pms_floor_views.xml',
'views/pms_folio_views.xml',
'views/pms_property_views.xml',
'views/pms_reservation_views.xml',
'views/pms_room_type_views.xml',
'views/pms_room_views.xml',
'views/pms_room_closure_reason_views.xml',
'views/inherited_account_payment_views.xml',
'views/inherited_account_move_views.xml',
'views/inherited_res_users_views.xml',
'views/pms_room_type_class_views.xml',
'views/pms_room_type_restriction_views.xml',
'views/pms_room_type_restriction_item_views.xml',
'views/pms_service_views.xml',
'views/pms_service_line_views.xml',
'views/pms_shared_room_views.xml',
'views/inherited_res_partner_views.xml',
'views/inherited_product_pricelist_views.xml',
'views/inherited_product_template_views.xml',
'views/inherited_webclient_templates.xml',
'wizard/folio_make_invoice_advance_views.xml',
],
'demo': [
'demo/pms_demo.xml'
],
'qweb': [
'static/src/xml/pms_base_templates.xml',
"data": [
"security/pms_security.xml",
"security/ir.model.access.csv",
"data/cron_jobs.xml",
"data/pms_data.xml",
"data/pms_sequence.xml",
"data/email_template_cancel.xml",
"data/email_template_reserv.xml",
"data/email_template_exit.xml",
"report/pms_folio.xml",
"report/pms_folio_templates.xml",
"templates/pms_email_template.xml",
"wizard/massive_changes.xml",
"wizard/massive_price_reservation_days.xml",
"wizard/service_on_day.xml",
"wizard/split_reservation.xml",
"wizard/wizard_reservation.xml",
"views/general.xml",
"data/menus.xml",
"views/pms_amenity_views.xml",
"views/pms_amenity_type_views.xml",
"views/pms_board_service_views.xml",
"views/pms_board_service_room_type_views.xml",
"views/pms_cancelation_rule_views.xml",
"views/pms_checkin_partner_views.xml",
"views/pms_floor_views.xml",
"views/pms_folio_views.xml",
"views/pms_property_views.xml",
"views/pms_reservation_views.xml",
"views/pms_room_type_views.xml",
"views/pms_room_views.xml",
"views/pms_room_closure_reason_views.xml",
"views/inherited_account_payment_views.xml",
"views/inherited_account_move_views.xml",
"views/inherited_res_users_views.xml",
"views/pms_room_type_class_views.xml",
"views/pms_room_type_restriction_views.xml",
"views/pms_room_type_restriction_item_views.xml",
"views/pms_service_views.xml",
"views/pms_service_line_views.xml",
"views/pms_shared_room_views.xml",
"views/inherited_res_partner_views.xml",
"views/inherited_product_pricelist_views.xml",
"views/inherited_product_template_views.xml",
"views/inherited_webclient_templates.xml",
"wizard/folio_make_invoice_advance_views.xml",
],
"demo": ["demo/pms_demo.xml"],
"qweb": ["static/src/xml/pms_base_templates.xml",],
}

View File

@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="0">
<!-- Scheduler For To Inform Guest About Reservation Before 24 Hours -->
<record model="ir.cron" id="autocheckout_reservations">
<field name="name">Automatic Checkout on past reservations</field>
@@ -13,11 +11,11 @@
<field name="doall" eval="False" />
<field name="state">code</field>
<field name="model_id" ref="model_pms_reservation" />
<field name="nextcall" eval="(DateTime.now() + timedelta(days=1)).strftime('%Y-%m-%d 05:00:00')"/>
<field
name="nextcall"
eval="(DateTime.now() + timedelta(days=1)).strftime('%Y-%m-%d 05:00:00')"
/>
<field name="code">model.autocheckout()</field>
</record>
</data>
</odoo>

View File

@@ -1,15 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE xml>
<odoo>
<data noupdate="1">
<!-- Email Template For PMS Reservation -->
<record id="mail_template_pms_cancel" model="mail.template">
<field name="name">Cancel Reservation-Send by Email</field>
<field name="subject">Cancelación de su reserva en ${object.company_id.property_name}</field>
<field name="partner_to">${(object.partner_id.id or '')}</field>
<field name="model_id" ref="pms.model_pms_folio"/>
<field name="auto_delete" eval="True" />
<field name="body_html">
<data noupdate="1">
<!-- Email Template For PMS Reservation -->
<record id="mail_template_pms_cancel" model="mail.template">
<field name="name">Cancel Reservation-Send by Email</field>
<field
name="subject"
>Cancelación de su reserva en ${object.company_id.property_name}</field>
<field name="partner_to">${(object.partner_id.id or '')}</field>
<field name="model_id" ref="pms.model_pms_folio" />
<field name="auto_delete" eval="True" />
<field name="body_html">
<![CDATA[
<style type="text/css">
/*Global Styles*/
@@ -706,6 +708,6 @@
</div>
]]>
</field>
</record>
</data>
</odoo>
</record>
</data>
</odoo>

View File

@@ -1,15 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE xml>
<odoo>
<data noupdate="1">
<!-- Email Template For PMS Reservation -->
<record id="mail_template_pms_exit" model="mail.template">
<field name="name">Exit Reservation-Send by Email</field>
<field name="subject">Gracias por alojarse con nosotros en ${object.company_id.property_name}</field>
<field
name="subject"
>Gracias por alojarse con nosotros en ${object.company_id.property_name}</field>
<field name="partner_to">${(object.partner_id.id or '')}</field>
<field name="model_id" ref="pms.model_pms_folio"/>
<field name="model_id" ref="pms.model_pms_folio" />
<field name="auto_delete" eval="True" />
<field name="body_html"><![CDATA[<style type="text/css">/*Global Styles*/
<field
name="body_html"
><![CDATA[<style type="text/css">/*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;}

View File

@@ -1,15 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE xml>
<odoo>
<data noupdate="1">
<!-- Email Template For PMS Reservation -->
<record id="mail_template_pms_reservation" model="mail.template">
<field name="name">Confirm Reservation-Send by Email</field>
<field name="subject">Confirmación de los detalles de su reserva en ${object.company_id.property_name}</field>
<field name="partner_to">${(object.partner_id.id or '')}</field>
<field name="model_id" ref="pms.model_pms_folio"/>
<field name="auto_delete" eval="True" />
<field name="body_html"><![CDATA[
<data noupdate="1">
<!-- Email Template For PMS Reservation -->
<record id="mail_template_pms_reservation" model="mail.template">
<field name="name">Confirm Reservation-Send by Email</field>
<field
name="subject"
>Confirmación de los detalles de su reserva en ${object.company_id.property_name}</field>
<field name="partner_to">${(object.partner_id.id or '')}</field>
<field name="model_id" ref="pms.model_pms_folio" />
<field name="auto_delete" eval="True" />
<field
name="body_html"
><![CDATA[
<style type="text/css">
/*Global Styles*/
.marco {
@@ -1037,6 +1041,6 @@
</div>
]]>
</field>
</record>
</data>
</record>
</data>
</odoo>

View File

@@ -1,27 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<menuitem id="pms_management_menu" name="PMS Management"
sequence="8" web_icon="pms,static/description/icon.png"
groups="pms.group_pms_user,pms.group_pms_call"/>
<menuitem id="pms_configuration_menu" name="Configuration"
sequence="20" parent="pms_management_menu"
groups="pms.group_pms_user"/>
<menuitem id="pms_reports_menu" name="Reports"
sequence="15" parent="pms_management_menu"
groups="pms.group_pms_user"/>
<menuitem id="menu_account_finance_xls_reports" name="XLS Reports"
parent="pms.pms_reports_menu" sequence="50"/>
<menuitem id="configuration_others" name="Configuration"
parent="pms.pms_configuration_menu" sequence="10"
groups="pms.group_pms_manager" />
<menuitem id="pms_massive_change" name="Massive Changes"
<menuitem
id="pms_management_menu"
name="PMS Management"
sequence="8"
web_icon="pms,static/description/icon.png"
groups="pms.group_pms_user,pms.group_pms_call"
/>
<menuitem
id="pms_configuration_menu"
name="Configuration"
sequence="20"
parent="pms_management_menu"
groups="pms.group_pms_user"
/>
<menuitem
id="pms_reports_menu"
name="Reports"
sequence="15"
parent="pms_management_menu"
groups="pms.group_pms_user"
/>
<menuitem
id="menu_account_finance_xls_reports"
name="XLS Reports"
parent="pms.pms_reports_menu"
sequence="50"
/>
<menuitem
id="configuration_others"
name="Configuration"
parent="pms.pms_configuration_menu"
sequence="10"
groups="pms.group_pms_manager"
/>
<menuitem
id="pms_massive_change"
name="Massive Changes"
parent="pms.configuration_others"
sequence="10" action="action_pms_massive_change"/>
sequence="10"
action="action_pms_massive_change"
/>
</odoo>

View File

@@ -1,42 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="1">
<!-- pms.users -->
<record id="base.user_admin" model="res.users">
<field name="groups_id" eval="[(4,ref('pms.group_pms_manager'))]"/>
<field name="groups_id" eval="[(4,ref('pms.group_pms_manager'))]" />
</record>
<record id="base.user_demo" model="res.users">
<field name="groups_id" eval="[(4,ref('pms.group_pms_user'))]"/>
<field name="groups_id" eval="[(4,ref('pms.group_pms_user'))]" />
</record>
<!-- Basic pms -->
<!-- Basic pms -->
<record id="main_pms_room_type_restriction" model="pms.room.type.restriction">
<field name="name">Restriction Plan</field>
</record>
<record id="main_pms_property" model="pms.property">
<field name="name">My Property</field>
<field name="company_id" ref="base.main_company"/>
<field name="default_pricelist_id" ref="product.list0"/>
<field name="default_restriction_id" ref="main_pms_room_type_restriction"/>
<field name="company_id" ref="base.main_company" />
<field name="default_pricelist_id" ref="product.list0" />
<field name="default_restriction_id" ref="main_pms_room_type_restriction" />
<field name="street">Rua Street Demo, s/n</field>
<field name="city">Commitsun city</field>
<field name="country_id" ref="base.es"/>
<field name="country_id" ref="base.es" />
<field name="zip">15703</field>
<field name="phone">+34 123 456 879</field>
<field name="email">commitsun@hootel.com</field>
<field name="website">https://www.commitsun.com</field>
</record>
<record model="res.users" id="base.user_root">
<field name="company_id" ref="base.main_company"/>
<field name="company_ids" eval="[(4, ref('base.main_company'))]"/>
<field name="pms_property_id" ref="main_pms_property"/>
<field name="pms_property_ids" eval="[(4, ref('main_pms_property'))]"/>
<field name="company_id" ref="base.main_company" />
<field name="company_ids" eval="[(4, ref('base.main_company'))]" />
<field name="pms_property_id" ref="main_pms_property" />
<field name="pms_property_ids" eval="[(4, ref('main_pms_property'))]" />
</record>
</data>
</odoo>

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data noupdate="1">
<!-- Sequences for pms folio -->
<record model="ir.sequence" id="seq_pms_folio">
<field name="name">PMS Folio</field>
@@ -9,6 +8,5 @@
<field name="prefix">F/</field>
<field name="padding">5</field>
</record>
</data>
</odoo>

View File

@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="1">
<!-- pms.floor -->
<!-- pms.floor -->
<record id="pms_floor_0" model="pms.floor">
<field name="name">Ground Floor</field>
</record>
@@ -13,9 +11,7 @@
<record id="pms_floor_2" model="pms.floor">
<field name="name">Second Floor</field>
</record>
<!-- pms.amenity.type -->
<!-- pms.amenity.type -->
<record id="pms_amenity_type_0" model="pms.amenity.type">
<field name="name">Toiletries</field>
</record>
@@ -25,146 +21,141 @@
<record id="pms_amenity_type_2" model="pms.amenity.type">
<field name="name">Kitchen facilities</field>
</record>
<!-- pms.amenity -->
<!-- pms.amenity -->
<record id="pms_amenity_0" model="pms.amenity">
<field name="name">Shampoo and Soap</field>
<field name="room_amenity_type_id" ref="pms_amenity_type_0"/>
<field name="room_amenity_type_id" ref="pms_amenity_type_0" />
</record>
<record id="pms_amenity_1" model="pms.amenity">
<field name="name">High-quality Shampoo and Soap Essential Herbs</field>
<field name="room_amenity_type_id" ref="pms_amenity_type_0"/>
<field name="room_amenity_type_id" ref="pms_amenity_type_0" />
</record>
<record id="pms_amenity_2" model="pms.amenity">
<field name="name">Hair Dryer</field>
<field name="room_amenity_type_id" ref="pms_amenity_type_0"/>
<field name="room_amenity_type_id" ref="pms_amenity_type_0" />
</record>
<record id="pms_amenity_3" model="pms.amenity">
<field name="name">High speed Wired Internet access</field>
<field name="room_amenity_type_id" ref="pms_amenity_type_1"/>
<field name="room_amenity_type_id" ref="pms_amenity_type_1" />
</record>
<record id="pms_amenity_4" model="pms.amenity">
<field name="name">Wi-Fi</field>
<field name="room_amenity_type_id" ref="pms_amenity_type_1"/>
<field name="room_amenity_type_id" ref="pms_amenity_type_1" />
</record>
<record id="pms_amenity_5" model="pms.amenity">
<field name="name">Microwave oven</field>
<field name="room_amenity_type_id" ref="pms_amenity_type_2"/>
<field name="room_amenity_type_id" ref="pms_amenity_type_2" />
</record>
<record id="pms_amenity_6" model="pms.amenity">
<field name="name">Half-sized Refrigerator</field>
<field name="room_amenity_type_id" ref="pms_amenity_type_2"/>
<field name="room_amenity_type_id" ref="pms_amenity_type_2" />
</record>
<!-- pms.room.type.class -->
<!-- pms.room.type.class -->
<record id="pms_room_type_class_0" model="pms.room.type.class">
<field name="name">Room</field>
</record>
<record id="pms_room_type_class_1" model="pms.room.type.class">
<field name="name">Conference</field>
</record>
<!-- pms.room.type -->
<!-- pms.room.type -->
<record id="pms_room_type_0" model="pms.room.type">
<field name="name">Economic</field>
<field name="code_type">ECO</field>
<field name="list_price">21.00</field>
<field name="class_id" ref="pms_room_type_class_0"/>
<field name="room_amenity_ids"
eval="[(4, ref('pms_amenity_0'))]"/>
<field name="class_id" ref="pms_room_type_class_0" />
<field name="room_amenity_ids" eval="[(4, ref('pms_amenity_0'))]" />
</record>
<record id="pms_room_type_1" model="pms.room.type">
<field name="name">Single</field>
<field name="code_type">SNG</field>
<field name="list_price">20.00</field>
<field name="class_id" ref="pms_room_type_class_0"/>
<field name="room_amenity_ids"
eval="[(4, ref('pms_amenity_0')), (4, ref('pms_amenity_4'))]"/>
<field name="class_id" ref="pms_room_type_class_0" />
<field
name="room_amenity_ids"
eval="[(4, ref('pms_amenity_0')), (4, ref('pms_amenity_4'))]"
/>
</record>
<record id="pms_room_type_2" model="pms.room.type">
<field name="name">Double</field>
<field name="code_type">DBL</field>
<field name="list_price">25.00</field>
<field name="class_id" ref="pms_room_type_class_0"/>
<field name="room_amenity_ids"
eval="[(4, ref('pms_amenity_0')), (4, ref('pms_amenity_4'))]"/>
<field name="class_id" ref="pms_room_type_class_0" />
<field
name="room_amenity_ids"
eval="[(4, ref('pms_amenity_0')), (4, ref('pms_amenity_4'))]"
/>
</record>
<record id="pms_room_type_3" model="pms.room.type">
<field name="name">Triple</field>
<field name="code_type">TRP</field>
<field name="list_price">35.00</field>
<field name="class_id" ref="pms_room_type_class_0"/>
<field name="room_amenity_ids"
eval="[(4, ref('pms_amenity_0')), (4, ref('pms_amenity_4'))]"/>
<field name="class_id" ref="pms_room_type_class_0" />
<field
name="room_amenity_ids"
eval="[(4, ref('pms_amenity_0')), (4, ref('pms_amenity_4'))]"
/>
</record>
<record id="pms_room_type_4" model="pms.room.type">
<field name="name">Conference Room</field>
<field name="code_type">CFR</field>
<field name="list_price">80.00</field>
<field name="class_id" ref="pms_room_type_class_1"/>
<field name="room_amenity_ids"
eval="[(4, ref('pms_amenity_3')), (4, ref('pms_amenity_4'))]"/>
<field name="class_id" ref="pms_room_type_class_1" />
<field
name="room_amenity_ids"
eval="[(4, ref('pms_amenity_3')), (4, ref('pms_amenity_4'))]"
/>
</record>
<!-- pms.room -->
<!-- pms.room -->
<record id="pms_room_0" model="pms.room">
<field name="name">Economic-101</field>
<field name="room_type_id" ref="pms_room_type_0"/>
<field name="floor_id" ref="pms_floor_1"/>
<field name="room_type_id" ref="pms_room_type_0" />
<field name="floor_id" ref="pms_floor_1" />
<field name="capacity">2</field>
</record>
<record id="pms_room_1" model="pms.room">
<field name="name">Single-101</field>
<field name="room_type_id" ref="pms_room_type_1"/>
<field name="floor_id" ref="pms_floor_1"/>
<field name="room_type_id" ref="pms_room_type_1" />
<field name="floor_id" ref="pms_floor_1" />
<field name="capacity">1</field>
</record>
<record id="pms_room_2" model="pms.room">
<field name="name">Single-102</field>
<field name="room_type_id" ref="pms_room_type_1"/>
<field name="floor_id" ref="pms_floor_1"/>
<field name="room_type_id" ref="pms_room_type_1" />
<field name="floor_id" ref="pms_floor_1" />
<field name="capacity">1</field>
</record>
<record id="pms_room_3" model="pms.room">
<field name="name">Single-103</field>
<field name="room_type_id" ref="pms_room_type_1"/>
<field name="floor_id" ref="pms_floor_1"/>
<field name="room_type_id" ref="pms_room_type_1" />
<field name="floor_id" ref="pms_floor_1" />
<field name="capacity">1</field>
</record>
<record id="pms_room_4" model="pms.room">
<field name="name">Double-201</field>
<field name="room_type_id" ref="pms_room_type_2"/>
<field name="floor_id" ref="pms_floor_2"/>
<field name="room_type_id" ref="pms_room_type_2" />
<field name="floor_id" ref="pms_floor_2" />
<field name="capacity">2</field>
<field name="extra_beds_allowed">1</field>
</record>
<record id="pms_room_5" model="pms.room">
<field name="name">Double-202</field>
<field name="room_type_id" ref="pms_room_type_2"/>
<field name="floor_id" ref="pms_floor_2"/>
<field name="room_type_id" ref="pms_room_type_2" />
<field name="floor_id" ref="pms_floor_2" />
<field name="capacity">2</field>
</record>
<record id="pms_room_6" model="pms.room">
<field name="name">Triple-203</field>
<field name="room_type_id" ref="pms_room_type_3"/>
<field name="floor_id" ref="pms_floor_2"/>
<field name="room_type_id" ref="pms_room_type_3" />
<field name="floor_id" ref="pms_floor_2" />
<field name="capacity">3</field>
</record>
<record id="pms_room_7" model="pms.room">
<field name="name">Open Talk Away Room</field>
<field name="room_type_id" ref="pms_room_type_4"/>
<field name="floor_id" ref="pms_floor_0"/>
<field name="room_type_id" ref="pms_room_type_4" />
<field name="floor_id" ref="pms_floor_0" />
<field name="capacity">1</field>
</record>
<!-- product.product for pms services -->
<!-- product.product for pms services -->
<record id="pms_service_0" model="product.product">
<field name="name">Breakfast Buffet</field>
<field name="list_price">5.0</field>
@@ -173,7 +164,6 @@
<field name="per_day">True</field>
<field name="per_person">True</field>
</record>
<record id="pms_service_1" model="product.product">
<field name="name">Extra Bed</field>
<field name="list_price">15.0</field>
@@ -185,7 +175,6 @@
<field name="is_extra_bed">True</field>
<field name="show_in_calendar">True</field>
</record>
<record id="pms_service_3" model="product.product">
<field name="name">Late Check-out</field>
<field name="list_price">10.0</field>
@@ -194,7 +183,6 @@
<field name="per_day">False</field>
<field name="per_person">False</field>
</record>
<record id="pms_service_4" model="product.product">
<field name="name">Lunch</field>
<field name="list_price">15.0</field>
@@ -203,7 +191,6 @@
<field name="per_day">True</field>
<field name="per_person">True</field>
</record>
<record id="pms_service_5" model="product.product">
<field name="name">Dinner</field>
<field name="list_price">20.0</field>
@@ -212,7 +199,6 @@
<field name="per_day">True</field>
<field name="per_person">True</field>
</record>
<record id="pms_service_6" model="product.product">
<field name="name">Free Bar</field>
<field name="list_price">40.0</field>
@@ -221,116 +207,94 @@
<field name="per_day">True</field>
<field name="per_person">True</field>
</record>
<!-- pms.board.service -->
<!-- pms.board.service -->
<record id="pms_board_service_0" model="pms.board.service">
<field name="name">BreakFast</field>
<field name="board_service_line_ids"
eval="[(5, 0), (0, 0, {
<field
name="board_service_line_ids"
eval="[(5, 0), (0, 0, {
'product_id': ref('pms_service_0'),
'amount': 3})]"/>
'amount': 3})]"
/>
<field name="price_type">fixed</field>
</record>
<record id="pms_board_service_1" model="pms.board.service">
<field name="name">Half Board</field>
<field name="board_service_line_ids"
eval="[(5, 0), (0, 0, {
<field
name="board_service_line_ids"
eval="[(5, 0), (0, 0, {
'product_id': ref('pms_service_0'),
'amount': 3}),
(0, 0, {'product_id': ref('pms_service_5'),
'amount': 8})
]"/>
]"
/>
<field name="price_type">fixed</field>
</record>
<record id="pms_board_service_2" model="pms.board.service">
<field name="name">FullBoard</field>
<field name="board_service_line_ids"
eval="[(5, 0), (0, 0, {
<field
name="board_service_line_ids"
eval="[(5, 0), (0, 0, {
'product_id': ref('pms_service_0'),
'amount': 3}),
(0, 0, {'product_id': ref('pms_service_4'),
'amount': 8}),
(0, 0, {'product_id': ref('pms_service_5'),
'amount': 8})
]"/>
]"
/>
<field name="price_type">fixed</field>
</record>
<!-- pms.board.service.room.type -->
<!-- pms.board.service.room.type -->
<!--Room 0 Economic-->
<record id="pms_board_service_room_0"
model="pms.board.service.room.type">
<field name="pms_board_service_id"
ref="pms_board_service_0"/>
<field name="pms_room_type_id"
ref="pms_room_type_0"/>
<record id="pms_board_service_room_0" model="pms.board.service.room.type">
<field name="pms_board_service_id" ref="pms_board_service_0" />
<field name="pms_room_type_id" ref="pms_room_type_0" />
<field name="price_type">fixed</field>
</record>
<record id="pms_board_service_room_1"
model="pms.board.service.room.type">
<field name="pms_board_service_id"
ref="pms_board_service_1"/>
<field name="pms_room_type_id"
ref="pms_room_type_0"/>
<record id="pms_board_service_room_1" model="pms.board.service.room.type">
<field name="pms_board_service_id" ref="pms_board_service_1" />
<field name="pms_room_type_id" ref="pms_room_type_0" />
<field name="price_type">fixed</field>
</record>
<record id="pms_board_service_room_2"
model="pms.board.service.room.type">
<field name="pms_board_service_id"
ref="pms_board_service_1"/>
<field name="pms_room_type_id"
ref="pms_room_type_0"/>
<field name="pricelist_id"
ref="product.list0"/>
<record id="pms_board_service_room_2" model="pms.board.service.room.type">
<field name="pms_board_service_id" ref="pms_board_service_1" />
<field name="pms_room_type_id" ref="pms_room_type_0" />
<field name="pricelist_id" ref="product.list0" />
<field name="price_type">fixed</field>
</record>
<!--Room 3 Triple-->
<record id="pms_board_service_room_3"
model="pms.board.service.room.type">
<field name="pms_board_service_id"
ref="pms_board_service_0"/>
<field name="pms_room_type_id"
ref="pms_room_type_3"/>
<!--Room 3 Triple-->
<record id="pms_board_service_room_3" model="pms.board.service.room.type">
<field name="pms_board_service_id" ref="pms_board_service_0" />
<field name="pms_room_type_id" ref="pms_room_type_3" />
<field name="price_type">fixed</field>
</record>
<record id="pms_board_service_room_4"
model="pms.board.service.room.type">
<field name="pms_board_service_id"
ref="pms_board_service_2"/>
<field name="pms_room_type_id"
ref="pms_room_type_3"/>
<record id="pms_board_service_room_4" model="pms.board.service.room.type">
<field name="pms_board_service_id" ref="pms_board_service_2" />
<field name="pms_room_type_id" ref="pms_room_type_3" />
<field name="price_type">fixed</field>
</record>
<!-- room.closure.reason -->
<!-- room.closure.reason -->
<record id="pms_room_closure_reason_0" model="room.closure.reason">
<field name="name">Maintenance</field>
<field name="description">Used for closing of rooms which require a maintenance. You can specify the reason in the own reservation.</field>
<field
name="description"
>Used for closing of rooms which require a maintenance. You can specify the reason in the own reservation.</field>
</record>
<record id="pms_room_closure_reason_1" model="room.closure.reason">
<field name="name">VIP Privacy</field>
<field name="description">Used for closing of rooms for extra privacy.</field>
<field
name="description"
>Used for closing of rooms for extra privacy.</field>
</record>
<!-- pms.folio -->
<!-- pms.folio -->
<!-- reservation of 1 economic room for 1 person -->
<record id="pms_folio_0" model="pms.folio">
<field name="partner_id" ref="base.res_partner_address_27"/>
<field name="reservation_ids"
eval="[(5, 0), (0, 0, {
<field name="partner_id" ref="base.res_partner_address_27" />
<field
name="reservation_ids"
eval="[(5, 0), (0, 0, {
'pricelist_id': 1,
'room_type_id': ref('pms_room_type_0'),
'checkin': DateTime.today().strftime('%Y-%m-%d'),
@@ -338,27 +302,31 @@
'adults': 2,
'state': 'confirm',
'board_service_room_id': ref('pms_board_service_room_1'),
})]"/>
})]"
/>
</record>
<!-- reservation of 1 triple room for 3 people on behalf on the company -->
<record id="pms_folio_1" model="pms.folio">
<field name="partner_id" ref="base.res_partner_12"/>
<field name="reservation_ids"
eval="[(5, 0), (0, 0, {
<field name="partner_id" ref="base.res_partner_12" />
<field
name="reservation_ids"
eval="[(5, 0), (0, 0, {
'pricelist_id': 1,
'room_type_id': ref('pms_room_type_3'),
'checkin': (DateTime.today() + timedelta(days=2)).strftime('%Y-%m-%d'),
'checkout': (DateTime.today() + timedelta(days=4)).strftime('%Y-%m-%d'),
'adults': 3,
'board_service_room_id': ref('pms_board_service_room_3'),
})]"/>
})]"
/>
</record>
<!-- reservation of 3 single rooms for 3 people with 1 cancelled -->
<!-- TODO: The third reservation is marked from State: Cancelled to Pending Entry at Folio creation -->
<record id="pms_folio_2" model="pms.folio">
<field name="partner_id" ref="base.res_partner_address_10"/>
<field name="reservation_ids"
eval="[(5, 0),
<field name="partner_id" ref="base.res_partner_address_10" />
<field
name="reservation_ids"
eval="[(5, 0),
(0, 0, {
'pricelist_id': 1,
'room_type_id': ref('pms_room_type_1'),
@@ -382,27 +350,31 @@
'checkout': (DateTime.today() + timedelta(days=4)).strftime('%Y-%m-%d'),
'adults': 1,
'state': 'cancelled',
})]"/>
})]"
/>
</record>
<!-- reservation of the conference room for 1 day on behalf of a company -->
<record id="pms_folio_3" model="pms.folio">
<field name="partner_id" ref="base.res_partner_12"/>
<field name="reservation_ids"
eval="[(5, 0), (0, 0, {
<field name="partner_id" ref="base.res_partner_12" />
<field
name="reservation_ids"
eval="[(5, 0), (0, 0, {
'pricelist_id': 1,
'room_type_id': ref('pms_room_type_4'),
'checkin': (DateTime.today() + timedelta(days=3)).strftime('%Y-%m-%d'),
'checkout': (DateTime.today() + timedelta(days=4)).strftime('%Y-%m-%d'),
'adults': 1,
'state': 'confirm',
})]"/>
})]"
/>
</record>
<!-- out of service room -->
<record id="pms_folio_4" model="pms.folio">
<field name="partner_id" ref="main_pms_property"/>
<field name="partner_id" ref="main_pms_property" />
<field name="reservation_type">out</field>
<field name="reservation_ids"
eval="[(5, 0), (0, 0, {
<field
name="reservation_ids"
eval="[(5, 0), (0, 0, {
'pricelist_id': 1,
'room_type_id': ref('pms_room_type_1'),
'checkin': DateTime.today().strftime('%Y-%m-%d'),
@@ -412,42 +384,38 @@
'reservation_type': 'out',
'closure_reason_id': ref('pms_room_closure_reason_0'),
'out_service_description': 'Change of lighting',
})]"/>
})]"
/>
</record>
<!-- Multi pms Demo -->
<record id="demo_pms_room_type_restriction" model="pms.room.type.restriction">
<field name="name">Restriction Plan Demo</field>
</record>
<record id="demo_pms_property" model="pms.property">
<field name="name">My pms Demo</field>
<field name="company_id" ref="base.main_company"/>
<field name="default_pricelist_id" ref="product.list0"/>
<field name="default_restriction_id" ref="demo_pms_room_type_restriction"/>
<field name="company_id" ref="base.main_company" />
<field name="default_pricelist_id" ref="product.list0" />
<field name="default_restriction_id" ref="demo_pms_room_type_restriction" />
</record>
<!-- pms.room.type -->
<record id="demo_pms_room_type_0" model="pms.room.type">
<field name="pms_property_id" ref="pms.demo_pms_property"/>
<field name="pms_property_id" ref="pms.demo_pms_property" />
<field name="name">Economic</field>
<field name="code_type">ECO</field>
<field name="list_price">21.00</field>
<field name="class_id" ref="pms_room_type_class_0"/>
<field name="room_amenity_ids"
eval="[(4, ref('pms_amenity_0'))]"/>
<field name="class_id" ref="pms_room_type_class_0" />
<field name="room_amenity_ids" eval="[(4, ref('pms_amenity_0'))]" />
</record>
<record id="demo_pms_room_type_1" model="pms.room.type">
<field name="pms_property_id" ref="pms.demo_pms_property"/>
<field name="pms_property_id" ref="pms.demo_pms_property" />
<field name="name">Single</field>
<field name="code_type">SNG</field>
<field name="list_price">20.00</field>
<field name="class_id" ref="pms_room_type_class_0"/>
<field name="room_amenity_ids"
eval="[(4, ref('pms_amenity_0')), (4, ref('pms_amenity_4'))]"/>
<field name="class_id" ref="pms_room_type_class_0" />
<field
name="room_amenity_ids"
eval="[(4, ref('pms_amenity_0')), (4, ref('pms_amenity_4'))]"
/>
</record>
</data>
</odoo>

View File

@@ -1,26 +1,25 @@
# 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, _
import json
from odoo import _, api, fields, models
from odoo.tools import float_is_zero
class AccountMove(models.Model):
_inherit = 'account.move'
_inherit = "account.move"
# Field Declarations
folio_ids = fields.Many2many(
comodel_name='pms.folio',
compute='_computed_folio_origin')
pms_property_id = fields.Many2one(
'pms.property')
from_folio = fields.Boolean(
compute='_computed_folio_origin')
comodel_name="pms.folio", compute="_computed_folio_origin"
)
pms_property_id = fields.Many2one("pms.property")
from_folio = fields.Boolean(compute="_computed_folio_origin")
outstanding_folios_debits_widget = fields.Text(
compute='_get_outstanding_folios_JSON')
has_folios_outstanding = fields.Boolean(
compute='_get_outstanding_folios_JSON')
compute="_get_outstanding_folios_JSON"
)
has_folios_outstanding = fields.Boolean(compute="_get_outstanding_folios_JSON")
# Compute and Search methods
@@ -28,8 +27,8 @@ class AccountMove(models.Model):
for inv in self:
inv.from_folio = False
inv.folio_ids = False
folios = inv.mapped('invoice_line_ids.reservation_ids.folio_id')
folios |= inv.mapped('invoice_line_ids.service_ids.folio_id')
folios = inv.mapped("invoice_line_ids.reservation_ids.folio_id")
folios |= inv.mapped("invoice_line_ids.service_ids.folio_id")
if folios:
inv.from_folio = True
inv.folio_ids = [(6, 0, folios.ids)]
@@ -38,21 +37,19 @@ class AccountMove(models.Model):
def action_folio_payments(self):
self.ensure_one()
sales = self.mapped('invoice_line_ids.sale_line_ids.order_id')
folios = self.env['pms.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)],
sales = self.mapped("invoice_line_ids.sale_line_ids.order_id")
folios = self.env["pms.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)],
}
# Business methods
@@ -60,62 +57,68 @@ class AccountMove(models.Model):
self.ensure_one()
self.outstanding_folios_debits_widget = json.dumps(False)
if self.from_folio:
payment_ids = self.folio_ids.mapped('payment_ids.id')
if self.state == 'open':
account_partner = self.env['res.partner'].\
_find_accounting_partner(self.partner_id).id
payment_ids = self.folio_ids.mapped("payment_ids.id")
if self.state == "open":
account_partner = (
self.env["res.partner"]._find_accounting_partner(self.partner_id).id
)
domain = [
('account_id', '=', self.account_id.id),
('partner_id', '!=', account_partner),
('reconciled', '=', False),
('payment_id', 'in', payment_ids),
'|', '&',
('amount_residual_currency', '!=', 0.0),
('currency_id', '!=', None),
'&', ('amount_residual_currency', '=', 0.0),
'&', ('currency_id', '=', None),
('amount_residual', '!=', 0.0)]
if self.type in ('out_invoice', 'in_refund'):
domain.extend([('credit', '>', 0), ('debit', '=', 0)])
type_payment = _('Outstanding credits in Folio')
("account_id", "=", self.account_id.id),
("partner_id", "!=", account_partner),
("reconciled", "=", False),
("payment_id", "in", payment_ids),
"|",
"&",
("amount_residual_currency", "!=", 0.0),
("currency_id", "!=", None),
"&",
("amount_residual_currency", "=", 0.0),
"&",
("currency_id", "=", None),
("amount_residual", "!=", 0.0),
]
if self.type in ("out_invoice", "in_refund"):
domain.extend([("credit", ">", 0), ("debit", "=", 0)])
type_payment = _("Outstanding credits in Folio")
else:
domain.extend([('credit', '=', 0), ('debit', '>', 0)])
type_payment = _('Outstanding debits')
info = {'title': '',
'outstanding': True,
'content': [],
'move_id': self.id}
lines = self.env['account.move.line'].search(domain)
domain.extend([("credit", "=", 0), ("debit", ">", 0)])
type_payment = _("Outstanding debits")
info = {
"title": "",
"outstanding": True,
"content": [],
"move_id": self.id,
}
lines = self.env["account.move.line"].search(domain)
currency_id = self.currency_id
if len(lines) != 0:
for line in lines:
# get the outstanding residual value in inv. currency
if line.currency_id and line.currency_id == \
self.currency_id:
if line.currency_id and line.currency_id == self.currency_id:
amount_to_show = abs(line.amount_residual_currency)
else:
amount_to_show = line.company_id.currency_id.\
with_context(date=line.date).\
compute(abs(line.amount_residual),
self.currency_id)
amount_to_show = line.company_id.currency_id.with_context(
date=line.date
).compute(abs(line.amount_residual), self.currency_id)
if float_is_zero(
amount_to_show,
precision_rounding=self.currency_id.rounding
):
amount_to_show, precision_rounding=self.currency_id.rounding
):
continue
if line.ref:
title = '%s : %s' % (line.move_id.name, line.ref)
title = "{} : {}".format(line.move_id.name, line.ref)
else:
title = line.move_id.name
info['content'].append({
'journal_name': line.ref or line.move_id.name,
'title': title,
'amount': amount_to_show,
'currency': currency_id.symbol,
'id': line.id,
'position': currency_id.position,
'digits': [69, self.currency_id.decimal_places],
})
info['title'] = type_payment
info["content"].append(
{
"journal_name": line.ref or line.move_id.name,
"title": title,
"amount": amount_to_show,
"currency": currency_id.symbol,
"id": line.id,
"position": currency_id.position,
"digits": [69, self.currency_id.decimal_places],
}
)
info["title"] = type_payment
self.outstanding_folios_debits_widget = json.dumps(info)
self.has_folio_outstanding = True

View File

@@ -5,21 +5,33 @@ from odoo import fields, models
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
_inherit = "account.move.line"
# Fields declaration
reservation_ids = fields.Many2many(
'pms.reservation',
'reservation_move_rel',
'move_line_id', 'reservation_id',
string='Reservations', readonly=True, copy=False)
"pms.reservation",
"reservation_move_rel",
"move_line_id",
"reservation_id",
string="Reservations",
readonly=True,
copy=False,
)
service_ids = fields.Many2many(
'pms.service',
'service_line_move_rel',
'move_line_id', 'service_id',
string='Services', readonly=True, copy=False)
"pms.service",
"service_line_move_rel",
"move_line_id",
"service_id",
string="Services",
readonly=True,
copy=False,
)
reservation_line_ids = fields.Many2many(
'pms.reservation.line',
'reservation_line_move_rel',
'move_line_id', 'reservation_line_id',
string='Reservation Lines', readonly=True, copy=False)
"pms.reservation.line",
"reservation_line_move_rel",
"move_line_id",
"reservation_line_id",
string="Reservation Lines",
readonly=True,
copy=False,
)

View File

@@ -1,49 +1,51 @@
# Copyright 2017 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, api, fields, models
from odoo.exceptions import except_orm
from odoo import models, fields, api, _
class AccountPayment(models.Model):
_inherit = 'account.payment'
_inherit = "account.payment"
# Fields declaration
folio_id = fields.Many2one(
'pms.folio',
string='Folio')
folio_id = fields.Many2one("pms.folio", string="Folio")
amount_total_folio = fields.Float(
compute="_compute_folio_amount", store=True,
string="Total amount in folio",
compute="_compute_folio_amount", store=True, string="Total amount in folio",
)
save_amount = fields.Monetary(string='onchange_amount')
save_amount = fields.Monetary(string="onchange_amount")
save_date = fields.Date()
save_journal_id = fields.Integer()
# Compute and Search methods
@api.depends('state')
@api.depends("state")
def _compute_folio_amount(self):
# FIXME: Finalize method
res = []
fol = ()
for payment in self:
if payment.folio_id:
fol = payment.env['pms.folio'].search([
('id', '=', payment.folio_id.id)
])
fol = payment.env["pms.folio"].search(
[("id", "=", payment.folio_id.id)]
)
else:
return
if not any(fol):
return
if len(fol) > 1:
raise except_orm(_('Warning'), _('This pay is related with \
more than one Reservation.'))
raise except_orm(
_("Warning"),
_(
"This pay is related with \
more than one Reservation."
),
)
else:
fol.compute_amount()
return res
# Constraints and onchanges
@api.onchange('amount', 'payment_date', 'journal_id')
@api.onchange("amount", "payment_date", "journal_id")
def onchange_amount(self):
if self._origin:
self.save_amount = self._origin.amount
@@ -52,100 +54,107 @@ class AccountPayment(models.Model):
# Action methods
"""WIP"""
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'))
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,
}
"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)
"journal_id": journal.id,
"line_ids": [(0, 0, return_line_vals)],
}
return_pay = self.env["payment.return"].create(return_vals)
if self.save_amount:
self.amount = self.save_amount
if self.save_date:
self.payment_date = self.save_date
if self.save_journal_id:
self.journal_id = self.env['account.journal'].browse(
self.save_journal_id)
self.journal_id = self.env["account.journal"].browse(self.save_journal_id)
return_pay.action_confirm()
# Business methods
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,
'state': 'draft'}
"journal_id": self.journal_id,
"partner_id": self.partner_id,
"amount": self.amount,
"payment_date": self.payment_date,
"communication": self.communication,
"state": "draft",
}
self.update(vals)
self.with_context({'ignore_notification_post': True}).post()
self.with_context({"ignore_notification_post": True}).post()
self._compute_folio_amount()
if self.folio_id:
msg = _("Payment %s modified: \n") % (self.communication)
if self.save_amount and self.save_amount != self.amount:
msg += _("Amount from %s to %s %s \n") % (
self.save_amount, self.amount, self.currency_id.symbol)
self.save_amount,
self.amount,
self.currency_id.symbol,
)
if self.save_date and self.save_date != self.payment_date:
msg += _("Date from %s to %s \n") % (
self.save_date, self.payment_date)
if self.save_journal_id and \
self.save_journal_id != self.journal_id.id:
msg += _("Date from %s to %s \n") % (self.save_date, self.payment_date)
if self.save_journal_id and self.save_journal_id != self.journal_id.id:
msg += _("Journal from %s to %s") % (
self.env['account.journal'].browse(
self.save_journal_id).name, self.journal_id.name)
self.folio_id.message_post(subject=_('Payment'), body=msg)
self.env["account.journal"].browse(self.save_journal_id).name,
self.journal_id.name,
)
self.folio_id.message_post(subject=_("Payment"), body=msg)
def delete(self):
msg = False
if self.folio_id:
msg = _("Deleted payment: %s %s ") % (
self.amount, self.currency_id.symbol)
msg = _("Deleted payment: %s %s ") % (self.amount, self.currency_id.symbol)
self.cancel()
self.move_name = ''
self.move_name = ""
self.unlink()
if msg:
self.folio_id.message_post(subject=_('Payment Deleted'), body=msg)
self.folio_id.message_post(subject=_("Payment Deleted"), body=msg)
def post(self):
rec = super(AccountPayment, self).post()
if rec and not self._context.get("ignore_notification_post", False):
for pay in self:
if pay.folio_id:
msg = _("Payment of %s %s registered from %s \
using %s payment method") % \
(pay.amount, pay.currency_id.symbol,
pay.communication, pay.journal_id.name)
pay.folio_id.message_post(subject=_('Payment'), body=msg)
msg = (
_(
"Payment of %s %s registered from %s \
using %s payment method"
)
% (
pay.amount,
pay.currency_id.symbol,
pay.communication,
pay.journal_id.name,
)
)
pay.folio_id.message_post(subject=_("Payment"), body=msg)
def modify_payment(self):
self.ensure_one()
view_form_id = self.env.ref('pms.account_payment_view_form_folio').id
view_form_id = self.env.ref("pms.account_payment_view_form_folio").id
# moves = self.mapped('move_ids.id')
return{
'name': _('Payment'),
'view_type': 'form',
'views': [(view_form_id, 'form')],
'view_mode': 'tree,form',
'res_model': 'account.payment',
'target': 'new',
'init_mode': 'edit',
'type': 'ir.actions.act_window',
'res_id': self.id,
return {
"name": _("Payment"),
"view_type": "form",
"views": [(view_form_id, "form")],
"view_mode": "tree,form",
"res_model": "account.payment",
"target": "new",
"init_mode": "edit",
"type": "ir.actions.act_window",
"res_id": self.id,
}

View File

@@ -2,13 +2,13 @@
# Copyright 2019 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, _
from odoo.http import request
from odoo import _, models
from odoo.exceptions import MissingError
from odoo.http import request
class IrHttp(models.AbstractModel):
_inherit = 'ir.http'
_inherit = "ir.http"
def session_info(self):
res = super().session_info()
@@ -16,21 +16,33 @@ class IrHttp(models.AbstractModel):
display_switch_pms_menu = len(user.pms_property_ids) > 1
# TODO: limit properties to the current company?
# or switch company automatically
res['pms_property_id'] = request.env.user.pms_property_id.id if \
request.session.uid else None
res['user_properties'] = {
'current_property': (user.pms_property_id.id, user.pms_property_id.name),
'allowed_properties': [
(property.id, property.name) for property in user.pms_property_ids
]
} if display_switch_pms_menu else False
res["pms_property_id"] = (
request.env.user.pms_property_id.id if request.session.uid else None
)
res["user_properties"] = (
{
"current_property": (
user.pms_property_id.id,
user.pms_property_id.name,
),
"allowed_properties": [
(property.id, property.name) for property in user.pms_property_ids
],
}
if display_switch_pms_menu
else False
)
if user.pms_property_id.company_id in user.company_ids:
user.company_id = user.pms_property_id.company_id
res['company_id'] = user.pms_property_id.company_id.id
res["company_id"] = user.pms_property_id.company_id.id
else:
return res #TODO Review method
return res # TODO Review method
raise MissingError(
_("Wrong property and company access settings for this user. "
"Please review property and company for user %s") % user.name)
_(
"Wrong property and company access settings for this user. "
"Please review property and company for user %s"
)
% user.name
)
return res

View File

@@ -5,20 +5,19 @@ from odoo import api, models
class MailComposeMessage(models.TransientModel):
_inherit = 'mail.compose.message'
_inherit = "mail.compose.message"
def send_mail(self, auto_commit=False):
if self._context.get('default_model') == 'pms.folio' and \
self._context.get('default_res_id') and \
self._context.get('mark_so_as_sent'):
folio = self.env['pms.folio'].browse([
self._context['default_res_id']
])
if (
self._context.get("default_model") == "pms.folio"
and self._context.get("default_res_id")
and self._context.get("mark_so_as_sent")
):
folio = self.env["pms.folio"].browse([self._context["default_res_id"]])
if folio:
cmds = [(1, lid, {'to_send': False}) for lid in
folio.reservation_ids.ids]
cmds = [
(1, lid, {"to_send": False}) for lid in folio.reservation_ids.ids
]
if any(cmds):
folio.reservation_ids = cmds
return super(MailComposeMessage, self).send_mail(
auto_commit=auto_commit)
return super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)

View File

@@ -1,38 +1,35 @@
# Copyright 2017 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp import _, api, fields, models
class PaymentReturn(models.Model):
_inherit = 'payment.return'
_inherit = "payment.return"
# Fields declaration
folio_id = fields.Many2one(
'pms.folio',
string='Folio')
folio_id = fields.Many2one("pms.folio", string="Folio")
pms_property_id = fields.Many2one(
'pms.property',
store=True,
readonly=True,
related='folio_id.pms_property_id')
"pms.property", store=True, readonly=True, related="folio_id.pms_property_id"
)
# Business methods
def action_confirm(self):
pay = super(PaymentReturn, self).action_confirm()
if pay:
folio_ids = []
folios = self.env['pms.folio'].browse(folio_ids)
folios = self.env["pms.folio"].browse(folio_ids)
for line in self.line_ids:
payments = self.env['account.payment'].search([
('move_line_ids', 'in', line.move_line_ids.ids)
])
folios_line = self.env['pms.folio'].browse(
payments.mapped('folio_id.id'))
payments = self.env["account.payment"].search(
[("move_line_ids", "in", line.move_line_ids.ids)]
)
folios_line = self.env["pms.folio"].browse(
payments.mapped("folio_id.id")
)
for folio in folios_line:
if self.id not in folio.return_ids.ids:
folio.update({'return_ids': [(4, self.id)]})
folio.update({"return_ids": [(4, self.id)]})
msg = _("Return of %s registered") % (line.amount)
folio.message_post(subject=_('Payment Return'), body=msg)
folio.message_post(subject=_("Payment Return"), body=msg)
folios += folios_line
folios.compute_amount()

View File

@@ -1,6 +1,6 @@
# Copyright 2017 Alexandre Díaz, Pablo Quesada, Darío Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
@@ -9,39 +9,47 @@ class ProductPricelist(models.Model):
A pricelist marked as daily is used as a daily rate plan for room types and
therefore is related only with one property.
"""
_inherit = 'product.pricelist'
_inherit = "product.pricelist"
# Fields declaration
pms_property_ids = fields.Many2many(
'pms.property',
string='Properties',
required=False,
ondelete='restrict')
"pms.property", string="Properties", required=False, ondelete="restrict"
)
cancelation_rule_id = fields.Many2one(
'pms.cancelation.rule',
string="Cancelation Policy")
pricelist_type = fields.Selection([
('daily', 'Daily Plan')],
string='Pricelist Type',
default='daily')
is_staff = fields.Boolean('Is Staff')
"pms.cancelation.rule", string="Cancelation Policy"
)
pricelist_type = fields.Selection(
[("daily", "Daily Plan")], string="Pricelist Type", default="daily"
)
is_staff = fields.Boolean("Is Staff")
# Constraints and onchanges
@api.constrains('pricelist_type', 'pms_property_ids')
@api.constrains("pricelist_type", "pms_property_ids")
def _check_pricelist_type_property_ids(self):
for record in self:
if record.pricelist_type == 'daily' and len(record.pms_property_ids) != 1:
if record.pricelist_type == "daily" and len(record.pms_property_ids) != 1:
raise ValidationError(
_("A daily pricelist is used as a daily Rate Plan "
"for room types and therefore must be related with "
"one and only one property."))
_(
"A daily pricelist is used as a daily Rate Plan "
"for room types and therefore must be related with "
"one and only one property."
)
)
if record.pricelist_type == 'daily' and len(record.pms_property_ids) == 1:
pms_property_id = self.env['pms.property'].search([
('default_pricelist_id', '=', record.id)
]) or None
if record.pricelist_type == "daily" and len(record.pms_property_ids) == 1:
pms_property_id = (
self.env["pms.property"].search(
[("default_pricelist_id", "=", record.id)]
)
or None
)
if pms_property_id and pms_property_id != record.pms_property_ids:
raise ValidationError(
_("Relationship mismatch.") + " " +
_("This pricelist is used as default in a "
"different property."))
_("Relationship mismatch.")
+ " "
+ _(
"This pricelist is used as default in a "
"different property."
)
)

View File

@@ -1,25 +1,26 @@
# 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
from odoo import fields, models
class ProductTemplate(models.Model):
_inherit = "product.template"
pms_property_ids = fields.Many2many(
'pms.property',
string='Properties',
required=False,
ondelete='restrict')
per_day = fields.Boolean('Unit increment per day')
per_person = fields.Boolean('Unit increment per person')
consumed_on = fields.Selection([
('before', 'Before night'),
('after', 'After night')], 'Consumed', default='before')
daily_limit = fields.Integer('Daily limit')
is_extra_bed = fields.Boolean('Is extra bed', default=False)
"pms.property", string="Properties", required=False, ondelete="restrict"
)
per_day = fields.Boolean("Unit increment per day")
per_person = fields.Boolean("Unit increment per person")
consumed_on = fields.Selection(
[("before", "Before night"), ("after", "After night")],
"Consumed",
default="before",
)
daily_limit = fields.Integer("Daily limit")
is_extra_bed = fields.Boolean("Is extra bed", default=False)
show_in_calendar = fields.Boolean(
'Show in Calendar',
"Show in Calendar",
default=False,
help='Specifies if the product is shown in the calendar information.')
help="Specifies if the product is shown in the calendar information.",
)

View File

@@ -1,14 +1,14 @@
# 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
from odoo import fields, models
class ResCompany(models.Model):
_inherit = 'res.company'
_inherit = "res.company"
# Fields declaration
pms_property_ids = fields.One2many('pms.property', 'company_id', 'Properties')
pms_property_ids = fields.One2many("pms.property", "company_id", "Properties")
# TODO: need extra explanation or remove otherwise
# additional_hours = fields.Integer('Additional Hours',
# help="Provide the min hours value for \

View File

@@ -1,48 +1,54 @@
# Copyright 2017 Alexandre Díaz
# Copyright 2017 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
import logging
from odoo import api, fields, models
_logger = logging.getLogger(__name__)
class ResPartner(models.Model):
_inherit = 'res.partner'
_inherit = "res.partner"
# Fields declaration
main_partner_id = fields.Many2one(
'res.partner',
string='Destination Partner fusion')
"res.partner", string="Destination Partner fusion"
)
reservations_count = fields.Integer(
'Reservations', compute='_compute_reservations_count')
folios_count = fields.Integer(
'Folios', compute='_compute_folios_count')
unconfirmed = fields.Boolean('Unconfirmed', default=True)
is_tour_operator = fields.Boolean('Is Tour Operator')
"Reservations", compute="_compute_reservations_count"
)
folios_count = fields.Integer("Folios", compute="_compute_folios_count")
unconfirmed = fields.Boolean("Unconfirmed", default=True)
is_tour_operator = fields.Boolean("Is Tour Operator")
# Compute and Search methods
def _compute_reservations_count(self):
pms_reservation_obj = self.env['pms.reservation']
pms_reservation_obj = self.env["pms.reservation"]
for record in self:
record.reservations_count = pms_reservation_obj.search_count([
('partner_id.id', '=', record.id)
])
record.reservations_count = pms_reservation_obj.search_count(
[("partner_id.id", "=", record.id)]
)
def _compute_folios_count(self):
pms_folio_obj = self.env['pms.folio']
pms_folio_obj = self.env["pms.folio"]
for record in self:
record.folios_count = pms_folio_obj.search_count([
('partner_id.id', '=', record.id)
])
record.folios_count = pms_folio_obj.search_count(
[("partner_id.id", "=", record.id)]
)
# ORM Overrides
@api.model
def name_search(self, name, args=None, operator='ilike', limit=100):
def name_search(self, name, args=None, operator="ilike", limit=100):
if not args:
args = []
domain = ['|', '|', ('phone', operator, name),
('mobile', operator, name), ('email', operator, name),
]
domain = [
"|",
"|",
("phone", operator, name),
("mobile", operator, name),
("email", operator, name),
]
partners = self.search(domain + args, limit=limit,)
res = partners.name_get()
if limit:
@@ -50,7 +56,8 @@ class ResPartner(models.Model):
else:
limit_rest = limit
if limit_rest or not limit:
args += [('id', 'not in', partners.ids)]
args += [("id", "not in", partners.ids)]
res += super(ResPartner, self).name_search(
name, args=args, operator=operator, limit=limit_rest)
name, args=args, operator=operator, limit=limit_rest
)
return res

View File

@@ -1,10 +1,10 @@
# Copyright 2019 Pablo Quesada
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, api, fields
from odoo import api, fields, models
class ResUsers(models.Model):
_inherit = 'res.users'
_inherit = "res.users"
# Default Methods ang Gets
@api.model
@@ -13,15 +13,17 @@ class ResUsers(models.Model):
# Fields declaration
pms_property_id = fields.Many2one(
'pms.property',
string='Property',
"pms.property",
string="Property",
default=_get_default_pms_property,
help='The property this user is currently working for.',
context={'user_preference': True})
help="The property this user is currently working for.",
context={"user_preference": True},
)
pms_property_ids = fields.Many2many(
'pms.property',
'pms_property_users_rel',
'user_id',
'pms_property_id',
string='Properties',
default=_get_default_pms_property)
"pms.property",
"pms_property_users_rel",
"user_id",
"pms_property_id",
string="Properties",
default=_get_default_pms_property,
)

View File

@@ -1,24 +1,20 @@
# 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
from odoo import fields, models
class PmsRoomAmenity(models.Model):
_name = 'pms.amenity'
_description = 'Room amenities'
_name = "pms.amenity"
_description = "Room amenities"
# Fields declaration
name = fields.Char('Amenity Name', translate=True, required=True)
name = fields.Char("Amenity Name", translate=True, required=True)
pms_property_ids = fields.Many2many(
'pms.property',
string='Properties',
required=False,
ondelete='restrict')
room_amenity_type_id = fields.Many2one(
'pms.amenity.type',
'Amenity Category')
default_code = fields.Char('Internal Reference')
active = fields.Boolean('Active', default=True)
"pms.property", string="Properties", required=False, ondelete="restrict"
)
room_amenity_type_id = fields.Many2one("pms.amenity.type", "Amenity Category")
default_code = fields.Char("Internal Reference")
active = fields.Boolean("Active", default=True)
# TODO: Constrain coherence pms_property_ids with amenity types pms_property_ids

View File

@@ -1,20 +1,21 @@
# 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
from odoo import fields, models
class PmsRoomAmenityType(models.Model):
_name = 'pms.amenity.type'
_description = 'Amenities Type'
_name = "pms.amenity.type"
_description = "Amenities Type"
# Fields declaration
name = fields.Char('Amenity Type Name', translate=True, required=True)
name = fields.Char("Amenity Type Name", translate=True, required=True)
pms_property_ids = fields.Many2many(
'pms.property', string='Properties', required=False, ondelete='restrict')
room_amenity_ids = fields.One2many('pms.amenity',
'room_amenity_type_id',
'Amenities in this category')
active = fields.Boolean('Active', default=True)
"pms.property", string="Properties", required=False, ondelete="restrict"
)
room_amenity_ids = fields.One2many(
"pms.amenity", "room_amenity_type_id", "Amenities in this category"
)
active = fields.Boolean("Active", default=True)
# TODO: Constrain coherence pms_property_ids with amenities pms_property_ids

View File

@@ -1,6 +1,6 @@
# Copyright 2017 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models, fields
from odoo import api, fields, models
class PmsBoardService(models.Model):

View File

@@ -1,15 +1,15 @@
# Copyright 2017 Dario
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class PmsBoardServiceRoomType(models.Model):
_name = 'pms.board.service.room.type'
_table = 'pms_board_service_room_type_rel'
_rec_name = 'pms_board_service_id'
_name = "pms.board.service.room.type"
_table = "pms_board_service_room_type_rel"
_rec_name = "pms_board_service_id"
_log_access = False
_description = 'Board Service included in Room'
_description = "Board Service included in Room"
# Default Methods ang Gets
@@ -17,124 +17,128 @@ class PmsBoardServiceRoomType(models.Model):
result = []
for res in self:
if res.pricelist_id:
name = u'%s (%s)' % (
name = u"{} ({})".format(
res.pms_board_service_id.name,
res.pricelist_id.name)
res.pricelist_id.name,
)
else:
name = u'%s (%s)' % (res.pms_board_service_id.name,
_('Generic'))
name = u"{} ({})".format(res.pms_board_service_id.name, _("Generic"))
result.append((res.id, name))
return result
# Fields declaration
pms_board_service_id = fields.Many2one(
'pms.board.service',
string='Board Service',
"pms.board.service",
string="Board Service",
index=True,
ondelete='cascade',
required=True)
ondelete="cascade",
required=True,
)
pms_room_type_id = fields.Many2one(
'pms.room.type',
string='Room Type',
"pms.room.type",
string="Room Type",
index=True,
ondelete='cascade',
required=True)
ondelete="cascade",
required=True,
)
pricelist_id = fields.Many2one(
'product.pricelist',
string='Pricelist',
required=False)
"product.pricelist", string="Pricelist", required=False
)
board_service_line_ids = fields.One2many(
'pms.board.service.room.type.line',
'pms_board_service_room_type_id')
"pms.board.service.room.type.line", "pms_board_service_room_type_id"
)
pms_property_id = fields.Many2one(
'pms.property',
related='pms_room_type_id.pms_property_id')
price_type = fields.Selection([
('fixed', 'Fixed'),
('percent', 'Percent')],
string='Type',
default='fixed',
required=True)
"pms.property", related="pms_room_type_id.pms_property_id"
)
price_type = fields.Selection(
[("fixed", "Fixed"), ("percent", "Percent")],
string="Type",
default="fixed",
required=True,
)
amount = fields.Float(
'Amount',
digits=('Product Price'),
compute='_compute_board_amount',
store=True)
"Amount", digits=("Product Price"), compute="_compute_board_amount", store=True
)
# Compute and Search methods
@api.depends('board_service_line_ids.amount')
@api.depends("board_service_line_ids.amount")
def _compute_board_amount(self):
for record in self:
total = 0
for service in record.board_service_line_ids:
total += service.amount
record.update({'amount': total})
record.update({"amount": total})
# Constraints and onchanges
@api.constrains('pricelist_id')
@api.constrains("pricelist_id")
def constrains_pricelist_id(self):
for record in self:
if self.pricelist_id:
board_pricelist = self.env['pms.board.service.room.type'].search([
('pricelist_id', '=', record.pricelist_id.id),
('pms_room_type_id', '=', record.pms_room_type_id.id),
('pms_board_service_id', '=',
record.pms_board_service_id.id),
('id', '!=', record.id)
])
board_pricelist = self.env["pms.board.service.room.type"].search(
[
("pricelist_id", "=", record.pricelist_id.id),
("pms_room_type_id", "=", record.pms_room_type_id.id),
("pms_board_service_id", "=", record.pms_board_service_id.id),
("id", "!=", record.id),
]
)
if board_pricelist:
raise UserError(
_("This Board Service in this Room can't repeat pricelist"))
_("This Board Service in this Room can't repeat pricelist")
)
else:
board_pricelist = self.env['pms.board.service.room.type'].search([
('pricelist_id', '=', False),
('pms_room_type_id', '=', record.pms_room_type_id.id),
('pms_board_service_id', '=',
record.pms_board_service_id.id),
('id', '!=', record.id)
])
board_pricelist = self.env["pms.board.service.room.type"].search(
[
("pricelist_id", "=", False),
("pms_room_type_id", "=", record.pms_room_type_id.id),
("pms_board_service_id", "=", record.pms_board_service_id.id),
("id", "!=", record.id),
]
)
if board_pricelist:
raise UserError(
_("This Board Service in this Room \
can't repeat without pricelist"))
_(
"This Board Service in this Room \
can't repeat without pricelist"
)
)
# Action methods
def open_board_lines_form(self):
action = self.env.ref(
'pms.action_pms_board_service_room_type_view').read()[0]
action['views'] = [(self.env.ref(
'pms.pms_board_service_room_type_form').id, 'form')]
action['res_id'] = self.id
action['target'] = 'new'
action = self.env.ref("pms.action_pms_board_service_room_type_view").read()[0]
action["views"] = [
(self.env.ref("pms.pms_board_service_room_type_form").id, "form")
]
action["res_id"] = self.id
action["target"] = "new"
return action
# ORM Overrides
def init(self):
self._cr.execute(
'SELECT indexname FROM pg_indexes WHERE indexname = %s',
('pms_board_service_id_pms_room_type_id_pricelist_id',))
"SELECT indexname FROM pg_indexes WHERE indexname = %s",
("pms_board_service_id_pms_room_type_id_pricelist_id",),
)
if not self._cr.fetchone():
self._cr.execute(
'CREATE INDEX pms_board_service_id_pms_room_type_id_pricelist_id \
"CREATE INDEX pms_board_service_id_pms_room_type_id_pricelist_id \
ON pms_board_service_room_type_rel \
(pms_board_service_id, pms_room_type_id, pricelist_id)')
(pms_board_service_id, pms_room_type_id, pricelist_id)"
)
@api.model
def create(self, vals):
if 'pms_board_service_id' in vals:
if "pms_board_service_id" in vals:
vals.update(
self.prepare_board_service_reservation_ids(
vals['pms_board_service_id'])
self.prepare_board_service_reservation_ids(vals["pms_board_service_id"])
)
return super(PmsBoardServiceRoomType, self).create(vals)
def write(self, vals):
if 'pms_board_service_id' in vals:
if "pms_board_service_id" in vals:
vals.update(
self.prepare_board_service_reservation_ids(
vals['pms_board_service_id'])
self.prepare_board_service_reservation_ids(vals["pms_board_service_id"])
)
return super(PmsBoardServiceRoomType, self).write(vals)
@@ -145,11 +149,9 @@ class PmsBoardServiceRoomType(models.Model):
Prepare line to price products config
"""
cmds = [(5, 0, 0)]
board_service = self.env['pms.board.service'].browse(
board_service_id)
board_service = self.env["pms.board.service"].browse(board_service_id)
for line in board_service.board_service_line_ids:
cmds.append((0, False, {
'product_id': line.product_id.id,
'amount': line.amount
}))
return {'board_service_line_ids': cmds}
cmds.append(
(0, False, {"product_id": line.product_id.id, "amount": line.amount})
)
return {"board_service_line_ids": cmds}

View File

@@ -2,20 +2,20 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class PmsBoardServiceRoomTypeLine(models.Model):
_name = 'pms.board.service.room.type.line'
_description = 'Services on Board Service included in Room'
_name = "pms.board.service.room.type.line"
_description = "Services on Board Service included in Room"
# Fields declaration
pms_board_service_room_type_id = fields.Many2one(
'pms.board.service.room.type',
'Board Service Room',
ondelete='cascade',
required=True)
product_id = fields.Many2one(
'product.product',
'Product',
"pms.board.service.room.type",
"Board Service Room",
ondelete="cascade",
required=True,
readonly=True)
)
product_id = fields.Many2one(
"product.product", "Product", required=True, readonly=True
)
# TODO def default_amount "amount of service"
amount = fields.Float('Amount', digits=('Product Price'), default=0.0)
amount = fields.Float("Amount", digits=("Product Price"), default=0.0)

View File

@@ -1,40 +1,39 @@
# 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
from odoo import fields, models
# TODO: refactoring to cancellation.rule
class PmsCancelationRule(models.Model):
_name = 'pms.cancelation.rule'
_description = 'Cancelation Rules'
_name = "pms.cancelation.rule"
_description = "Cancelation Rules"
# Fields declaration
name = fields.Char('Amenity Name', translate=True, required=True)
name = fields.Char("Amenity Name", translate=True, required=True)
pricelist_ids = fields.One2many(
'product.pricelist',
'cancelation_rule_id',
'Pricelist that use this rule')
"product.pricelist", "cancelation_rule_id", "Pricelist that use this rule"
)
pms_property_ids = fields.Many2many(
'pms.property',
string='Properties',
required=False,
ondelete='restrict')
active = fields.Boolean('Active', default=True)
"pms.property", string="Properties", required=False, ondelete="restrict"
)
active = fields.Boolean("Active", default=True)
days_intime = fields.Integer(
'Days Late',
help='Maximum number of days for free cancellation before Checkin')
penalty_late = fields.Integer('% Penalty Late', defaul="100")
apply_on_late = fields.Selection([
('first', 'First Day'),
('all', 'All Days'),
('days', 'Specify days')], 'Late apply on', default='first')
days_late = fields.Integer('Late first days', default="2")
penalty_noshow = fields.Integer('% Penalty No Show', default="100")
apply_on_noshow = fields.Selection([
('first', 'First Day'),
('all', 'All Days'),
('days', 'Specify days')], 'No Show apply on', default='all')
days_noshow = fields.Integer('NoShow first days', default="2")
"Days Late", help="Maximum number of days for free cancellation before Checkin"
)
penalty_late = fields.Integer("% Penalty Late", defaul="100")
apply_on_late = fields.Selection(
[("first", "First Day"), ("all", "All Days"), ("days", "Specify days")],
"Late apply on",
default="first",
)
days_late = fields.Integer("Late first days", default="2")
penalty_noshow = fields.Integer("% Penalty No Show", default="100")
apply_on_noshow = fields.Selection(
[("first", "First Day"), ("all", "All Days"), ("days", "Specify days")],
"No Show apply on",
default="all",
)
days_noshow = fields.Integer("NoShow first days", default="2")
# TODO: Constrain coherence pms_property_ids pricelist and cancelation_rules

View File

@@ -2,72 +2,72 @@
# Copyright 2018 Alexandre Diaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import datetime
from odoo import models, fields, api, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools import (
DEFAULT_SERVER_DATETIME_FORMAT,
DEFAULT_SERVER_DATE_FORMAT)
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
class PmsCheckinPartner(models.Model):
_name = 'pms.checkin.partner'
_description = 'Partner Checkins'
_name = "pms.checkin.partner"
_description = "Partner Checkins"
# Default Methods ang Gets
def _default_reservation_id(self):
if 'reservation_id' in self.env.context:
reservation = self.env['pms.reservation'].browse([
self.env.context['reservation_id']
])
if "reservation_id" in self.env.context:
reservation = self.env["pms.reservation"].browse(
[self.env.context["reservation_id"]]
)
return reservation
return False
def _default_partner_id(self):
if 'reservation_id' in self.env.context:
reservation = self.env['pms.reservation'].browse([
self.env.context['reservation_id']
])
if "reservation_id" in self.env.context:
reservation = self.env["pms.reservation"].browse(
[self.env.context["reservation_id"]]
)
partner_ids = []
if reservation.folio_id:
for room in reservation.folio_id.reservation_ids:
partner_ids.append(room.mapped(
'checkin_partner_ids.partner_id.id'))
if 'checkin_partner_ids' in self.env.context:
for checkin in self.env.context['checkin_partner_ids']:
partner_ids.append(room.mapped("checkin_partner_ids.partner_id.id"))
if "checkin_partner_ids" in self.env.context:
for checkin in self.env.context["checkin_partner_ids"]:
if checkin[0] == 0:
partner_ids.append(checkin[2].get('partner_id'))
if self._context.get('include_customer') and \
reservation.partner_id.id not in partner_ids and \
not reservation.partner_id.is_company:
partner_ids.append(checkin[2].get("partner_id"))
if (
self._context.get("include_customer")
and reservation.partner_id.id not in partner_ids
and not reservation.partner_id.is_company
):
return reservation.partner_id
return False
def _default_folio_id(self):
if 'folio_id' in self.env.context:
folio = self.env['pms.folio'].browse([
self.env.context['folio_id']
])
if "folio_id" in self.env.context:
folio = self.env["pms.folio"].browse([self.env.context["folio_id"]])
return folio
if 'reservation_id' in self.env.context:
folio = self.env['pms.reservation'].browse([
self.env.context['reservation_id']
]).folio_id
if "reservation_id" in self.env.context:
folio = (
self.env["pms.reservation"]
.browse([self.env.context["reservation_id"]])
.folio_id
)
return folio
return False
def _default_enter_date(self):
if 'reservation_id' in self.env.context:
reservation = self.env['pms.reservation'].browse([
self.env.context['reservation_id']
])
if "reservation_id" in self.env.context:
reservation = self.env["pms.reservation"].browse(
[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['pms.reservation'].browse([
self.env.context['reservation_id']
])
if "reservation_id" in self.env.context:
reservation = self.env["pms.reservation"].browse(
[self.env.context["reservation_id"]]
)
return reservation.checkout
return False
@@ -77,123 +77,124 @@ class PmsCheckinPartner(models.Model):
# Fields declaration
partner_id = fields.Many2one(
'res.partner',
default=_default_partner_id,
required=True)
reservation_id = fields.Many2one(
'pms.reservation',
default=_default_reservation_id)
"res.partner", default=_default_partner_id, required=True
)
reservation_id = fields.Many2one("pms.reservation", default=_default_reservation_id)
folio_id = fields.Many2one(
'pms.folio',
default=_default_folio_id,
readonly=True,
required=True)
"pms.folio", default=_default_folio_id, readonly=True, required=True
)
pms_property_id = fields.Many2one(
'pms.property',
default=_get_default_pms_property,
required=True)
email = fields.Char('E-mail', related='partner_id.email')
mobile = fields.Char('Mobile', related='partner_id.mobile')
"pms.property", default=_get_default_pms_property, required=True
)
email = fields.Char("E-mail", related="partner_id.email")
mobile = fields.Char("Mobile", related="partner_id.mobile")
enter_date = fields.Date(default=_default_enter_date, required=True)
exit_date = fields.Date(default=_default_exit_date, required=True)
arrival_hour = fields.Char('Arrival Hour',
help="Default Arrival Hour (HH:MM)")
departure_hour = fields.Char('Departure Hour',
help="Default Departure Hour (HH:MM)")
auto_booking = fields.Boolean('Get in Now', default=False)
state = fields.Selection([
('draft', 'Pending Entry'),
('booking', 'On Board'),
('done', 'Out'),
('cancelled', 'Cancelled')],
string='State',
arrival_hour = fields.Char("Arrival Hour", help="Default Arrival Hour (HH:MM)")
departure_hour = fields.Char(
"Departure Hour", help="Default Departure Hour (HH:MM)"
)
auto_booking = fields.Boolean("Get in Now", default=False)
state = fields.Selection(
[
("draft", "Pending Entry"),
("booking", "On Board"),
("done", "Out"),
("cancelled", "Cancelled"),
],
string="State",
readonly=True,
default=lambda *a: 'draft',
track_visibility='onchange')
default=lambda *a: "draft",
track_visibility="onchange",
)
# Constraints and onchanges
@api.constrains('exit_date', 'enter_date')
@api.constrains("exit_date", "enter_date")
def _check_exit_date(self):
for record in self:
date_in = fields.Date.from_string(record.enter_date)
date_out = fields.Date.from_string(record.exit_date)
if date_out < date_in:
raise models.ValidationError(
_('Departure date (%s) is prior to arrival on %s') %
(date_out, date_in))
_("Departure date (%s) is prior to arrival on %s")
% (date_out, date_in)
)
@api.onchange('enter_date', 'exit_date')
@api.onchange("enter_date", "exit_date")
def _onchange_enter_date(self):
date_in = fields.Date.from_string(self.enter_date)
date_out = fields.Date.from_string(self.exit_date)
if date_out <= date_in:
date_out = date_in + datetime.timedelta(days=1)
self.update({'exit_date': date_out})
self.update({"exit_date": date_out})
raise ValidationError(
_('Departure date, is prior to arrival. Check it now. %s') %
date_out)
_("Departure date, is prior to arrival. Check it now. %s") % date_out
)
@api.onchange('partner_id')
@api.onchange("partner_id")
def _check_partner_id(self):
for record in self:
if record.partner_id:
if record.partner_id.is_company:
raise models.ValidationError(
_('A Checkin Guest is configured like a company, \
modify it in contact form if its a mistake'))
indoor_partner_ids = record.reservation_id.\
checkin_partner_ids.filtered(
lambda r: r.id != record.id
).mapped('partner_id.id')
_(
"A Checkin Guest is configured like a company, \
modify it in contact form if its a mistake"
)
)
indoor_partner_ids = record.reservation_id.checkin_partner_ids.filtered(
lambda r: r.id != record.id
).mapped("partner_id.id")
if indoor_partner_ids.count(record.partner_id.id) > 1:
record.partner_id = None
raise models.ValidationError(
_('This guest is already registered in the room'))
_("This guest is already registered in the room")
)
# Action methods
def action_on_board(self):
for record in self:
if record.reservation_id.checkin > fields.Date.today():
raise models.ValidationError(
_('It is not yet checkin day!'))
raise models.ValidationError(_("It is not yet checkin day!"))
hour = record._get_arrival_hour()
vals = {
'state': 'booking',
'arrival_hour': hour,
"state": "booking",
"arrival_hour": hour,
}
record.update(vals)
if record.reservation_id.state == 'confirm':
record.reservation_id.state = 'booking'
if record.reservation_id.state == "confirm":
record.reservation_id.state = "booking"
if record.reservation_id.splitted:
master_reservation = \
record.reservation_id.parent_reservation or \
record.reservation_id
splitted_reservs = self.env['pms.reservation'].search([
('splitted', '=', True),
'|',
('parent_reservation', '=', master_reservation.id),
('id', '=', master_reservation.id),
('folio_id', '=', record.folio_id.id),
('id', '!=', record.id),
('state', '=', 'confirm')
])
master_reservation = (
record.reservation_id.parent_reservation
or record.reservation_id
)
splitted_reservs = self.env["pms.reservation"].search(
[
("splitted", "=", True),
"|",
("parent_reservation", "=", master_reservation.id),
("id", "=", master_reservation.id),
("folio_id", "=", record.folio_id.id),
("id", "!=", record.id),
("state", "=", "confirm"),
]
)
if splitted_reservs:
splitted_reservs.update({'state': 'booking'})
splitted_reservs.update({"state": "booking"})
return {
"type": "ir.actions.do_nothing",
}
def action_done(self):
for record in self:
if record.state == 'booking':
if record.state == "booking":
hour = record._get_departure_hour()
vals = {
'state': 'done',
'departure_hour': hour,
"state": "done",
"departure_hour": hour,
}
record.update(vals)
return True
@@ -202,7 +203,7 @@ class PmsCheckinPartner(models.Model):
@api.model
def create(self, vals):
record = super(PmsCheckinPartner, self).create(vals)
if vals.get('auto_booking', False):
if vals.get("auto_booking", False):
record.action_on_board()
return record
@@ -212,16 +213,17 @@ class PmsCheckinPartner(models.Model):
tz_property = self.env.user.pms_property_id.tz
today = fields.Datetime.context_timestamp(
self.with_context(tz=tz_property),
datetime.datetime.strptime(fields.Date.today(),
DEFAULT_SERVER_DATE_FORMAT))
datetime.datetime.strptime(fields.Date.today(), DEFAULT_SERVER_DATE_FORMAT),
)
default_arrival_hour = self.env.user.pms_property_id.default_arrival_hour
if self.reservation_id.checkin < today.strftime(
DEFAULT_SERVER_DATE_FORMAT):
if self.reservation_id.checkin < today.strftime(DEFAULT_SERVER_DATE_FORMAT):
return default_arrival_hour
now = fields.Datetime.context_timestamp(
self.with_context(tz=tz_property),
datetime.datetime.strptime(fields.Datetime.now(),
DEFAULT_SERVER_DATETIME_FORMAT))
datetime.datetime.strptime(
fields.Datetime.now(), DEFAULT_SERVER_DATETIME_FORMAT
),
)
arrival_hour = now.strftime("%H:%M")
return arrival_hour
@@ -230,15 +232,16 @@ class PmsCheckinPartner(models.Model):
tz_property = self.env.user.pms_property_id.tz
today = fields.Datetime.context_timestamp(
self.with_context(tz=tz_property),
datetime.datetime.strptime(fields.Date.today(),
DEFAULT_SERVER_DATE_FORMAT))
datetime.datetime.strptime(fields.Date.today(), DEFAULT_SERVER_DATE_FORMAT),
)
default_departure_hour = self.env.user.pms_property_id.default_departure_hour
if self.reservation_id.checkout < today.strftime(
DEFAULT_SERVER_DATE_FORMAT):
if self.reservation_id.checkout < today.strftime(DEFAULT_SERVER_DATE_FORMAT):
return default_departure_hour
now = fields.Datetime.context_timestamp(
self.with_context(tz=tz_property),
datetime.datetime.strptime(fields.Datetime.now(),
DEFAULT_SERVER_DATETIME_FORMAT))
datetime.datetime.strptime(
fields.Datetime.now(), DEFAULT_SERVER_DATETIME_FORMAT
),
)
departure_hour = now.strftime("%H:%M")
return departure_hour

View File

@@ -1,6 +1,6 @@
# Copyright 2017 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields
from odoo import fields, models
class PmsFloor(models.Model):
@@ -8,14 +8,10 @@ class PmsFloor(models.Model):
_description = "Ubication"
# Fields declaration
name = fields.Char('Ubication Name',
translate=True,
size=64,
required=True,
index=True)
name = fields.Char(
"Ubication Name", translate=True, size=64, required=True, index=True
)
pms_property_ids = fields.Many2many(
'pms.property',
string='Properties',
required=False,
ondelete='restrict')
sequence = fields.Integer('Sequence')
"pms.property", string="Properties", required=False, ondelete="restrict"
)
sequence = fields.Integer("Sequence")

File diff suppressed because it is too large Load Diff

View File

@@ -3,61 +3,59 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import re
from odoo import models, fields, api, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class PmsProperty(models.Model):
_name = 'pms.property'
_description = 'Property'
_inherits = {'res.partner': 'partner_id'}
_name = "pms.property"
_description = "Property"
_inherits = {"res.partner": "partner_id"}
# Fields declaration
partner_id = fields.Many2one(
'res.partner',
'Property',
required=True,
delegate=True,
ondelete='cascade')
"res.partner", "Property", required=True, delegate=True, ondelete="cascade"
)
company_id = fields.Many2one(
'res.company',
"res.company",
required=True,
help='The company that owns or operates this property.')
help="The company that owns or operates this property.",
)
user_ids = fields.Many2many(
'res.users',
'pms_property_users_rel',
'pms_property_id',
'user_id',
string='Accepted Users')
room_type_ids = fields.One2many(
'pms.room.type',
'pms_property_id',
'Room Types')
room_ids = fields.One2many(
'pms.room',
'pms_property_id',
'Rooms')
"res.users",
"pms_property_users_rel",
"pms_property_id",
"user_id",
string="Accepted Users",
)
room_type_ids = fields.One2many("pms.room.type", "pms_property_id", "Room Types")
room_ids = fields.One2many("pms.room", "pms_property_id", "Rooms")
default_pricelist_id = fields.Many2one(
'product.pricelist',
string='Product Pricelist',
"product.pricelist",
string="Product Pricelist",
required=True,
help='The default pricelist used in this property.')
help="The default pricelist used in this property.",
)
default_restriction_id = fields.Many2one(
'pms.room.type.restriction',
'Restriction Plan',
"pms.room.type.restriction",
"Restriction Plan",
required=True,
help='The default restriction plan used in this property.')
default_arrival_hour = fields.Char('Arrival Hour (GMT)',
help="HH:mm Format", default="14:00")
default_departure_hour = fields.Char('Departure Hour (GMT)',
help="HH:mm Format", default="12:00")
default_cancel_policy_days = fields.Integer('Cancellation Days')
default_cancel_policy_percent = fields.Float('Percent to pay')
help="The default restriction plan used in this property.",
)
default_arrival_hour = fields.Char(
"Arrival Hour (GMT)", help="HH:mm Format", default="14:00"
)
default_departure_hour = fields.Char(
"Departure Hour (GMT)", help="HH:mm Format", default="12:00"
)
default_cancel_policy_days = fields.Integer("Cancellation Days")
default_cancel_policy_percent = fields.Float("Percent to pay")
# Constraints and onchanges
@api.constrains('default_arrival_hour', 'default_departure_hour')
@api.constrains("default_arrival_hour", "default_departure_hour")
def _check_hours(self):
r = re.compile('[0-2][0-9]:[0-5][0-9]')
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):

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
# Copyright 2017-2018 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, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
@@ -16,57 +16,55 @@ class PmsReservationLine(models.Model):
result = []
for res in self:
date = fields.Date.from_string(res.date)
name = u'%s/%s' % (date.day, date.month)
name = u"{}/{}".format(date.day, date.month)
result.append((res.id, name))
return result
# Fields declaration
reservation_id = fields.Many2one(
'pms.reservation',
string='Reservation',
ondelete='cascade',
"pms.reservation",
string="Reservation",
ondelete="cascade",
required=True,
copy=False)
copy=False,
)
move_line_ids = fields.Many2many(
'account.move.line',
'reservation_line_move_rel',
'reservation_line_id',
'move_line_id',
string='Invoice Lines',
"account.move.line",
"reservation_line_move_rel",
"reservation_line_id",
"move_line_id",
string="Invoice Lines",
readonly=True,
copy=False)
copy=False,
)
pms_property_id = fields.Many2one(
'pms.property',
"pms.property",
store=True,
readonly=True,
related='reservation_id.pms_property_id')
date = fields.Date('Date')
state = fields.Selection(related='reservation_id.state')
price = fields.Float(
string='Price',
digits=('Product Price'))
related="reservation_id.pms_property_id",
)
date = fields.Date("Date")
state = fields.Selection(related="reservation_id.state")
price = fields.Float(string="Price", digits=("Product Price"))
cancel_discount = fields.Float(
string='Cancel Discount (%)',
digits=('Discount'), default=0.0)
discount = fields.Float(
string='Discount (%)',
digits=('Discount'), default=0.0)
string="Cancel Discount (%)", digits=("Discount"), default=0.0
)
discount = fields.Float(string="Discount (%)", digits=("Discount"), default=0.0)
# Constraints and onchanges
@api.constrains('date')
@api.constrains("date")
def constrains_duplicated_date(self):
for record in self:
duplicated = record.reservation_id.reservation_line_ids.filtered(
lambda r: r.date == record.date and
r.id != record.id
lambda r: r.date == record.date and r.id != record.id
)
if duplicated:
raise ValidationError(_('Duplicated reservation line date'))
raise ValidationError(_("Duplicated reservation line date"))
@api.constrains('state')
@api.constrains("state")
def constrains_service_cancel(self):
for record in self:
if record.state == 'cancelled':
if record.state == "cancelled":
room_services = record.reservation_id.service_ids
for service in room_services:
cancel_lines = service.service_line_ids.filtered(

View File

@@ -2,7 +2,7 @@
# Copyright 2017 Dario Lodeiros
# Copyright 2018 Pablo Quesada
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
@@ -11,82 +11,95 @@ class PmsRoom(models.Model):
and also for speeches (conference rooms), parking,
relax with cafe con leche, spa...
"""
_name = 'pms.room'
_description = 'Property Room'
_name = "pms.room"
_description = "Property Room"
_order = "sequence, room_type_id, name"
# Fields declaration
name = fields.Char('Room Name', required=True)
name = fields.Char("Room Name", required=True)
pms_property_id = fields.Many2one(
'pms.property',
"pms.property",
store=True,
readonly=True,
related='room_type_id.pms_property_id')
related="room_type_id.pms_property_id",
)
room_type_id = fields.Many2one(
'pms.room.type',
'Property Room Type',
required=True,
ondelete='restrict')
shared_room_id = fields.Many2one(
'pms.shared.room',
'Shared Room',
default=False)
"pms.room.type", "Property Room Type", required=True, ondelete="restrict"
)
shared_room_id = fields.Many2one("pms.shared.room", "Shared Room", default=False)
floor_id = fields.Many2one(
'pms.floor',
'Ubication',
help='At which floor the room is located.')
capacity = fields.Integer('Capacity')
to_be_cleaned = fields.Boolean('To be Cleaned', default=False)
extra_beds_allowed = fields.Integer('Extra beds allowed',
default='0',
required=True)
"pms.floor", "Ubication", help="At which floor the room is located."
)
capacity = fields.Integer("Capacity")
to_be_cleaned = fields.Boolean("To be Cleaned", default=False)
extra_beds_allowed = fields.Integer(
"Extra beds allowed", default="0", required=True
)
description_sale = fields.Text(
'Sale Description', translate=True,
"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")
active = fields.Boolean('Active', default=True)
sequence = fields.Integer('Sequence', default=0)
" your customers. This description will be copied to every Sales "
" Order, Delivery Order and Customer Invoice/Credit Note",
)
active = fields.Boolean("Active", default=True)
sequence = fields.Integer("Sequence", default=0)
# Constraints and onchanges
@api.constrains('capacity')
@api.constrains("capacity")
def _check_capacity(self):
for record in self:
if record.capacity < 1:
raise ValidationError(_("The capacity of the \
room must be greater than 0."))
raise ValidationError(
_(
"The capacity of the \
room must be greater than 0."
)
)
# CRUD methods
@api.model
def create(self, vals):
if vals.get('pms_property_id', self.env.user.pms_property_id.id) != \
self.env['pms.room.type'].browse(
vals['room_type_id']).pms_property_id.id:
raise ValidationError(
_("A room cannot be created in a room type \
of another property."))
if (
vals.get("pms_property_id", self.env.user.pms_property_id.id)
!= self.env["pms.room.type"].browse(vals["room_type_id"]).pms_property_id.id
):
raise ValidationError(
_(
"A room cannot be created in a room type \
of another property."
)
)
return super().create(vals)
def write(self, vals):
for record in self:
if vals.get('pms_property_id', record.pms_property_id.id) != record.pms_property_id.id:
if (
vals.get("pms_property_id", record.pms_property_id.id)
!= record.pms_property_id.id
):
raise ValidationError(
_("A room cannot be changed to another property.") + " " +
_("%s does not belong to %s.")
% (record, record.pms_property_id))
room_type_ids = self.env['pms.room.type'].search([
('pms_property_id', '=', record.pms_property_id.id)
]).ids
if vals.get('room_type_id', record.room_type_id.id) \
not in room_type_ids:
_("A room cannot be changed to another property.")
+ " "
+ _("%s does not belong to %s.") % (record, record.pms_property_id)
)
room_type_ids = (
self.env["pms.room.type"]
.search([("pms_property_id", "=", record.pms_property_id.id)])
.ids
)
if vals.get("room_type_id", record.room_type_id.id) not in room_type_ids:
raise ValidationError(
_("A room cannot be changed to a room type of \
another property or unlinked from a room type."))
_(
"A room cannot be changed to a room type of \
another property or unlinked from a room type."
)
)
return super().write(vals)
# Business methods
def get_capacity(self, extra_bed=0):
if not self.shared_room_id:
return self.capacity + extra_bed

View File

@@ -1,6 +1,6 @@
# Copyright 2017 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields
from odoo import fields, models
class RoomClosureReason(models.Model):
@@ -8,10 +8,8 @@ class RoomClosureReason(models.Model):
_description = "Cause of out of service"
# Fields declaration
name = fields.Char('Name', translate=True, required=True)
name = fields.Char("Name", translate=True, required=True)
pms_property_ids = fields.Many2many(
'pms.property',
string='Properties',
required=False,
ondelete='restrict')
description = fields.Text('Description', translate=True)
"pms.property", string="Properties", required=False, ondelete="restrict"
)
description = fields.Text("Description", translate=True)

View File

@@ -1,7 +1,7 @@
# 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, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
@@ -10,9 +10,10 @@ class PmsRoomType(models.Model):
With the term 'room type' is meant a sales type of residential accommodation: for
example, a Double Room, a Economic Room, an Apartment, a Tent, a Caravan...
"""
_name = "pms.room.type"
_description = "Room Type"
_inherits = {'product.product': 'product_id'}
_inherits = {"product.product": "product_id"}
_order = "sequence, code_type, name"
# Default methods
@@ -22,50 +23,50 @@ class PmsRoomType(models.Model):
# Fields declaration
product_id = fields.Many2one(
'product.product',
'Product Room Type',
"product.product",
"Product Room Type",
required=True,
delegate=True,
ondelete='cascade')
ondelete="cascade",
)
pms_property_id = fields.Many2one(
'pms.property',
'Property',
"pms.property",
"Property",
required=True,
ondelete='restrict',
default=_get_default_pms_property,)
room_ids = fields.One2many(
'pms.room',
'room_type_id',
'Rooms')
class_id = fields.Many2one(
'pms.room.type.class',
'Property Type Class')
ondelete="restrict",
default=_get_default_pms_property,
)
room_ids = fields.One2many("pms.room", "room_type_id", "Rooms")
class_id = fields.Many2one("pms.room.type.class", "Property Type Class")
board_service_room_type_ids = fields.One2many(
'pms.board.service.room.type',
'pms_room_type_id',
string='Board Services')
"pms.board.service.room.type", "pms_room_type_id", string="Board Services"
)
room_amenity_ids = fields.Many2many(
'pms.amenity',
'pms_room_type_aminity_rel',
'room_type_ids',
'amenity_ids',
string='Room Type Amenities',
help='List of Amenities.')
code_type = fields.Char('Code', required=True, )
shared_room = fields.Boolean('Shared Room', default=False,
help="This room type is reservation by beds")
total_rooms_count = fields.Integer(
compute='_compute_total_rooms', store=True)
active = fields.Boolean('Active', default=True)
sequence = fields.Integer('Sequence', default=0)
"pms.amenity",
"pms_room_type_aminity_rel",
"room_type_ids",
"amenity_ids",
string="Room Type Amenities",
help="List of Amenities.",
)
code_type = fields.Char("Code", required=True,)
shared_room = fields.Boolean(
"Shared Room", default=False, help="This room type is reservation by beds"
)
total_rooms_count = fields.Integer(compute="_compute_total_rooms", store=True)
active = fields.Boolean("Active", default=True)
sequence = fields.Integer("Sequence", default=0)
_sql_constraints = [
('code_type_pms_unique', 'unique(code_type, pms_property_id)',
'Room Type Code must be unique by Property!'),
(
"code_type_pms_unique",
"unique(code_type, pms_property_id)",
"Room Type Code must be unique by Property!",
),
]
# Constraints and onchanges
@api.depends('room_ids', 'room_ids.active')
@api.depends("room_ids", "room_ids.active")
def _compute_total_rooms(self):
for record in self:
record.total_rooms_count = len(record.room_ids)
@@ -74,43 +75,38 @@ class PmsRoomType(models.Model):
@api.model
def create(self, vals):
""" Add room types as not purchase services. """
vals.update({
'purchase_ok': False,
'type': 'service',
})
vals.update(
{"purchase_ok": False, "type": "service",}
)
return super().create(vals)
def unlink(self):
for record in self:
record.product_id.unlink()
return super().unlink()
# Business methods
def get_capacity(self):
self.ensure_one()
capacities = self.room_ids.mapped('capacity')
capacities = self.room_ids.mapped("capacity")
return min(capacities) if any(capacities) else 0
@api.model
def check_availability_room_type(self, dfrom, dto,
room_type_id=False, notthis=[]):
def check_availability_room_type(self, dfrom, dto, room_type_id=False, notthis=[]):
"""
Check the max availability for an specific
type of room in a range of dates
"""
reservations = self.env['pms.reservation'].get_reservations(dfrom,
dto)
reservations_rooms = reservations.mapped('room_id.id')
free_rooms = self.env['pms.room'].search([
('id', 'not in', reservations_rooms),
('id', 'not in', notthis)
])
reservations = self.env["pms.reservation"].get_reservations(dfrom, dto)
reservations_rooms = reservations.mapped("room_id.id")
free_rooms = self.env["pms.room"].search(
[("id", "not in", reservations_rooms), ("id", "not in", notthis)]
)
if room_type_id:
rooms_linked = self.env['pms.room.type'].search([
('id', '=', room_type_id)
]).room_ids
rooms_linked = (
self.env["pms.room.type"].search([("id", "=", room_type_id)]).room_ids
)
free_rooms = free_rooms & rooms_linked
return free_rooms.sorted(key=lambda r: r.sequence)
@@ -126,38 +122,43 @@ class PmsRoomType(models.Model):
Return Dict Code Room Types: subdict with day, discount, price
"""
vals = {}
room_type_ids = kwargs.get('room_type_ids', False)
room_types = self.env['pms.room.type'].browse(room_type_ids) if \
room_type_ids else self.env['pms.room.type'].search([])
date_from = kwargs.get('date_from', False)
days = kwargs.get('days', False)
discount = kwargs.get('discount', False)
room_type_ids = kwargs.get("room_type_ids", False)
room_types = (
self.env["pms.room.type"].browse(room_type_ids)
if room_type_ids
else self.env["pms.room.type"].search([])
)
date_from = kwargs.get("date_from", False)
days = kwargs.get("days", False)
discount = kwargs.get("discount", False)
if not date_from or not days:
raise ValidationError(_('Date From and days are mandatory'))
partner_id = kwargs.get('partner_id', False)
partner = self.env['res.partner'].browse(partner_id)
raise ValidationError(_("Date From and days are mandatory"))
partner_id = kwargs.get("partner_id", False)
partner = self.env["res.partner"].browse(partner_id)
pricelist_id = kwargs.get(
'pricelist_id',
partner.property_product_pricelist.id and
partner.property_product_pricelist.id or
self.env.user.pms_property_id.default_pricelist_id.id)
vals.update({
'partner_id': partner_id if partner_id else False,
'discount': discount,
})
"pricelist_id",
partner.property_product_pricelist.id
and partner.property_product_pricelist.id
or self.env.user.pms_property_id.default_pricelist_id.id,
)
vals.update(
{"partner_id": partner_id if partner_id else False, "discount": discount,}
)
rate_vals = {}
for room_type in room_types:
vals.update({'room_type_id': room_type.id})
room_vals = self.env['pms.reservation'].\
prepare_reservation_lines(
date_from,
days,
pricelist_id=pricelist_id,
vals=vals,
update_old_prices=False)
rate_vals.update({
room_type.id: [item[2] for item in
room_vals['reservation_line_ids'] if
item[2]]
})
vals.update({"room_type_id": room_type.id})
room_vals = self.env["pms.reservation"].prepare_reservation_lines(
date_from,
days,
pricelist_id=pricelist_id,
vals=vals,
update_old_prices=False,
)
rate_vals.update(
{
room_type.id: [
item[2] for item in room_vals["reservation_line_ids"] if item[2]
]
}
)
return rate_vals

View File

@@ -1,7 +1,7 @@
# 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
from odoo import fields, models
class PmsRoomTypeClass(models.Model):
@@ -10,25 +10,22 @@ class PmsRoomTypeClass(models.Model):
residential accommodation: for example, a Room, a Bed, an Apartment,
a Tent, a Caravan...
"""
_name = "pms.room.type.class"
_description = "Room Type Class"
_order = "sequence, name, code_class"
# Fields declaration
name = fields.Char('Class Name', required=True, translate=True)
name = fields.Char("Class Name", required=True, translate=True)
# Relationship between models
pms_property_ids = fields.Many2many(
'pms.property',
string='Properties',
required=False,
ondelete='restrict')
room_type_ids = fields.One2many(
'pms.room.type',
'class_id',
'Types')
code_class = fields.Char('Code')
active = fields.Boolean('Active', default=True)
sequence = fields.Integer('Sequence', default=0)
"pms.property", string="Properties", required=False, ondelete="restrict"
)
room_type_ids = fields.One2many("pms.room.type", "class_id", "Types")
code_class = fields.Char("Code")
active = fields.Boolean("Active", default=True)
sequence = fields.Integer("Sequence", default=0)
_sql_constraints = [('code_class_unique', 'unique(code_class)',
'Room Class Code must be unique!')]
_sql_constraints = [
("code_class_unique", "unique(code_class)", "Room Class Code must be unique!")
]

View File

@@ -1,13 +1,14 @@
# Copyright 2017 Alexandre Díaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api
from odoo import api, fields, models
class PmsRoomTypeRestriction(models.Model):
""" The room type restriction is used as a daily restriction plan for room types
and therefore is related only with one property. """
_name = 'pms.room.type.restriction'
_description = 'Reservation restriction plan'
_name = "pms.room.type.restriction"
_description = "Reservation restriction plan"
# Default methods
@api.model
@@ -15,19 +16,22 @@ class PmsRoomTypeRestriction(models.Model):
return self.env.user.pms_property_id or None
# Fields declaration
name = fields.Char('Restriction Plan Name', required=True)
name = fields.Char("Restriction Plan Name", required=True)
pms_property_id = fields.Many2one(
'pms.property',
'Property',
ondelete='restrict',
default=_get_default_pms_property)
"pms.property",
"Property",
ondelete="restrict",
default=_get_default_pms_property,
)
item_ids = fields.One2many(
'pms.room.type.restriction.item',
'restriction_id',
string='Restriction Items',
copy=True)
"pms.room.type.restriction.item",
"restriction_id",
string="Restriction Items",
copy=True,
)
active = fields.Boolean(
'Active',
"Active",
default=True,
help='If unchecked, it will allow you to hide the '
'restriction plan without removing it.')
help="If unchecked, it will allow you to hide the "
"restriction plan without removing it.",
)

View File

@@ -1,47 +1,49 @@
# Copyright 2017 Alexandre Díaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class PmsRoomTypeRestrictionItem(models.Model):
_name = 'pms.room.type.restriction.item'
_description = 'Reservation restriction by day'
_name = "pms.room.type.restriction.item"
_description = "Reservation restriction by day"
# Field Declarations
restriction_id = fields.Many2one('pms.room.type.restriction',
'Restriction Plan', ondelete='cascade',
index=True)
room_type_id = fields.Many2one('pms.room.type', 'Room Type',
required=True, ondelete='cascade')
date = fields.Date('Date')
restriction_id = fields.Many2one(
"pms.room.type.restriction", "Restriction Plan", ondelete="cascade", index=True
)
room_type_id = fields.Many2one(
"pms.room.type", "Room Type", required=True, ondelete="cascade"
)
date = fields.Date("Date")
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')
closed = fields.Boolean("Closed")
closed_departure = fields.Boolean("Closed Departure")
closed_arrival = fields.Boolean("Closed Arrival")
_sql_constraints = [('room_type_registry_unique',
'unique(restriction_id, room_type_id, date)',
'Only can exists one restriction in the same \
day for the same room type!')]
_sql_constraints = [
(
"room_type_registry_unique",
"unique(restriction_id, room_type_id, date)",
"Only can exists one restriction in the same \
day for the same room type!",
)
]
# Constraints and onchanges
@api.constrains('min_stay', 'min_stay_arrival', 'max_stay',
'max_stay_arrival')
@api.constrains("min_stay", "min_stay_arrival", "max_stay", "max_stay_arrival")
def _check_min_stay(self):
for record in self:
if record.min_stay < 0:
raise ValidationError(_("Min. Stay can't be less than zero"))
elif record.min_stay_arrival < 0:
raise ValidationError(
_("Min. Stay Arrival can't be less than zero"))
raise ValidationError(_("Min. Stay Arrival can't be less than zero"))
elif record.max_stay < 0:
raise ValidationError(_("Max. Stay can't be less than zero"))
elif record.max_stay_arrival < 0:
raise ValidationError(
_("Max. Stay Arrival can't be less than zero"))
raise ValidationError(_("Max. Stay Arrival can't be less than zero"))

View File

@@ -1,19 +1,18 @@
# 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, _
from odoo.tools import (
float_is_zero,
float_compare,
DEFAULT_SERVER_DATE_FORMAT)
from datetime import timedelta
import logging
from datetime import timedelta
from odoo import _, api, fields, models
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, float_compare, float_is_zero
_logger = logging.getLogger(__name__)
class PmsService(models.Model):
_name = 'pms.service'
_description = 'Services and its charges'
_name = "pms.service"
_description = "Services and its charges"
# Default methods
@@ -21,141 +20,129 @@ class PmsService(models.Model):
result = []
for rec in self:
name = []
name.append('%(name)s' % {'name': rec.name})
name.append("{name}".format(name=rec.name))
if rec.reservation_id.name:
name.append('%(name)s' % {'name': rec.reservation_id.name})
name.append("{name}".format(name=rec.reservation_id.name))
result.append((rec.id, ", ".join(name)))
return result
@api.model
def _default_reservation_id(self):
if self.env.context.get('reservation_ids'):
ids = [item[1] for item in self.env.context['reservation_ids']]
return self.env['pms.reservation'].browse([
(ids)], limit=1)
elif self.env.context.get('default_reservation_id'):
return self.env.context.get('default_reservation_id')
if self.env.context.get("reservation_ids"):
ids = [item[1] for item in self.env.context["reservation_ids"]]
return self.env["pms.reservation"].browse([(ids)], limit=1)
elif self.env.context.get("default_reservation_id"):
return self.env.context.get("default_reservation_id")
return False
@api.model
def _default_folio_id(self):
if 'folio_id' in self._context:
return self._context['folio_id']
if "folio_id" in self._context:
return self._context["folio_id"]
return False
# Fields declaration
name = fields.Char('Service description', required=True)
name = fields.Char("Service description", required=True)
product_id = fields.Many2one(
'product.product',
'Service',
ondelete='restrict',
required=True)
"product.product", "Service", ondelete="restrict", required=True
)
folio_id = fields.Many2one(
'pms.folio',
'Folio',
ondelete='cascade',
default=_default_folio_id)
"pms.folio", "Folio", ondelete="cascade", default=_default_folio_id
)
reservation_id = fields.Many2one(
'pms.reservation',
'Room',
default=_default_reservation_id)
service_line_ids = fields.One2many(
'pms.service.line',
'service_id')
"pms.reservation", "Room", default=_default_reservation_id
)
service_line_ids = fields.One2many("pms.service.line", "service_id")
company_id = fields.Many2one(
related='folio_id.company_id',
string='Company',
store=True,
readonly=True)
related="folio_id.company_id", string="Company", store=True, readonly=True
)
pms_property_id = fields.Many2one(
'pms.property',
store=True,
readonly=True,
related='folio_id.pms_property_id')
"pms.property", store=True, readonly=True, related="folio_id.pms_property_id"
)
tax_ids = fields.Many2many(
'account.tax',
string='Taxes',
domain=['|', ('active', '=', False), ('active', '=', True)])
"account.tax",
string="Taxes",
domain=["|", ("active", "=", False), ("active", "=", True)],
)
move_line_ids = fields.Many2many(
'account.move.line',
'service_line_move_rel',
'service_id',
'move_line_id',
string='move Lines',
copy=False)
analytic_tag_ids = fields.Many2many(
'account.analytic.tag',
string='Analytic Tags')
"account.move.line",
"service_line_move_rel",
"service_id",
"move_line_id",
string="move Lines",
copy=False,
)
analytic_tag_ids = fields.Many2many("account.analytic.tag", string="Analytic Tags")
currency_id = fields.Many2one(
related='folio_id.currency_id',
store=True,
string='Currency',
readonly=True)
sequence = fields.Integer(string='Sequence', default=10)
state = fields.Selection(related='folio_id.state')
per_day = fields.Boolean(related='product_id.per_day', related_sudo=True)
product_qty = fields.Integer('Quantity', default=1)
related="folio_id.currency_id", store=True, string="Currency", readonly=True
)
sequence = fields.Integer(string="Sequence", default=10)
state = fields.Selection(related="folio_id.state")
per_day = fields.Boolean(related="product_id.per_day", related_sudo=True)
product_qty = fields.Integer("Quantity", default=1)
days_qty = fields.Integer(compute="_compute_days_qty", store=True)
is_board_service = fields.Boolean()
to_print = fields.Boolean('Print', help='Print in Folio Report')
to_print = fields.Boolean("Print", help="Print in Folio Report")
# Non-stored related field to allow portal user to
# see the image of the product he has ordered
product_image = fields.Binary(
'Product Image', related="product_id.image_1024",
store=False, related_sudo=True)
invoice_status = fields.Selection([
('invoiced', 'Fully Invoiced'),
('to invoice', 'To Invoice'),
('no', 'Nothing to Invoice')],
string='Invoice Status',
compute='_compute_invoice_status',
store=True,
readonly=True,
default='no')
channel_type = fields.Selection([
('door', 'Door'),
('mail', 'Mail'),
('phone', 'Phone'),
('call', 'Call Center'),
('web', 'Web')],
string='Sales Channel')
"Product Image", related="product_id.image_1024", store=False, related_sudo=True
)
invoice_status = fields.Selection(
[
("invoiced", "Fully Invoiced"),
("to invoice", "To Invoice"),
("no", "Nothing to Invoice"),
],
string="Invoice Status",
compute="_compute_invoice_status",
store=True,
readonly=True,
default="no",
)
channel_type = fields.Selection(
[
("door", "Door"),
("mail", "Mail"),
("phone", "Phone"),
("call", "Call Center"),
("web", "Web"),
],
string="Sales Channel",
)
price_unit = fields.Float(
'Unit Price',
required=True,
digits=('Product Price'), default=0.0)
discount = fields.Float(
string='Discount (%)',
digits=('Discount'), default=0.0)
"Unit Price", required=True, digits=("Product Price"), default=0.0
)
discount = fields.Float(string="Discount (%)", digits=("Discount"), default=0.0)
qty_to_invoice = fields.Float(
compute='_get_to_invoice_qty',
string='To Invoice',
compute="_get_to_invoice_qty",
string="To Invoice",
store=True,
readonly=True,
digits=('Product Unit of Measure'))
digits=("Product Unit of Measure"),
)
qty_invoiced = fields.Float(
compute='_get_invoice_qty',
string='Invoiced',
compute="_get_invoice_qty",
string="Invoiced",
store=True,
readonly=True,
digits=('Product Unit of Measure'))
digits=("Product Unit of Measure"),
)
price_subtotal = fields.Monetary(
string='Subtotal',
readonly=True,
store=True,
compute='_compute_amount_service')
string="Subtotal", readonly=True, store=True, compute="_compute_amount_service"
)
price_total = fields.Monetary(
string='Total',
readonly=True,
store=True,
compute='_compute_amount_service')
string="Total", readonly=True, store=True, compute="_compute_amount_service"
)
price_tax = fields.Float(
string='Taxes Amount',
string="Taxes Amount",
readonly=True,
store=True,
compute='_compute_amount_service')
compute="_compute_amount_service",
)
# Compute and Search methods
@api.depends('qty_invoiced', 'product_qty', 'folio_id.state')
@api.depends("qty_invoiced", "product_qty", "folio_id.state")
def _get_to_invoice_qty(self):
"""
Compute the quantity to invoice. If the invoice policy is order,
@@ -163,13 +150,12 @@ class PmsService(models.Model):
Otherwise, the quantity delivered is used.
"""
for line in self:
if line.folio_id.state not in ['draft']:
if line.folio_id.state not in ["draft"]:
line.qty_to_invoice = line.product_qty - line.qty_invoiced
else:
line.qty_to_invoice = 0
@api.depends('move_line_ids.move_id.state',
'move_line_ids.quantity')
@api.depends("move_line_ids.move_id.state", "move_line_ids.quantity")
def _get_invoice_qty(self):
"""
Compute the quantity invoiced. If case of a refund,
@@ -183,16 +169,18 @@ class PmsService(models.Model):
for line in self:
qty_invoiced = 0.0
for invoice_line in line.move_line_ids:
if invoice_line.move_id.state != 'cancel':
if invoice_line.move_id.type == 'out_invoice':
if invoice_line.move_id.state != "cancel":
if invoice_line.move_id.type == "out_invoice":
qty_invoiced += invoice_line.uom_id._compute_quantity(
invoice_line.quantity, line.product_id.uom_id)
elif invoice_line.move_id.type == 'out_refund':
invoice_line.quantity, line.product_id.uom_id
)
elif invoice_line.move_id.type == "out_refund":
qty_invoiced -= move_line.uom_id._compute_quantity(
invoice_line.quantity, line.product_id.uom_id)
invoice_line.quantity, line.product_id.uom_id
)
line.qty_invoiced = qty_invoiced
@api.depends('product_qty', 'qty_to_invoice', 'qty_invoiced')
@api.depends("product_qty", "qty_to_invoice", "qty_invoiced")
def _compute_invoice_status(self):
"""
Compute the invoice status of a SO line. Possible statuses:
@@ -212,58 +200,65 @@ class PmsService(models.Model):
- invoiced: the quantity invoiced is larger or equal to the
quantity ordered.
"""
precision = self.env['decimal.precision'].precision_get(
'Product Unit of Measure')
precision = self.env["decimal.precision"].precision_get(
"Product Unit of Measure"
)
for line in self:
if line.folio_id.state in ('draft'):
line.invoice_status = 'no'
elif not float_is_zero(line.qty_to_invoice,
precision_digits=precision):
line.invoice_status = 'to invoice'
elif float_compare(line.qty_invoiced, line.product_qty,
precision_digits=precision) >= 0:
line.invoice_status = 'invoiced'
if line.folio_id.state in ("draft"):
line.invoice_status = "no"
elif not float_is_zero(line.qty_to_invoice, precision_digits=precision):
line.invoice_status = "to invoice"
elif (
float_compare(
line.qty_invoiced, line.product_qty, precision_digits=precision
)
>= 0
):
line.invoice_status = "invoiced"
else:
line.invoice_status = 'no'
line.invoice_status = "no"
@api.depends('product_qty', 'discount', 'price_unit', 'tax_ids')
@api.depends("product_qty", "discount", "price_unit", "tax_ids")
def _compute_amount_service(self):
"""
Compute the amounts of the service line.
"""
for record in self:
folio = record.folio_id or self.env['pms.folio'].browse(
self.env.context.get('default_folio_id'))
folio = record.folio_id or self.env["pms.folio"].browse(
self.env.context.get("default_folio_id")
)
reservation = record.reservation_id or self.env.context.get(
'reservation_id')
"reservation_id"
)
currency = folio.currency_id if folio else reservation.currency_id
product = record.product_id
price = record.price_unit * (1 - (record.discount or 0.0) * 0.01)
taxes = record.tax_ids.compute_all(
price, currency, record.product_qty, product=product)
price, currency, record.product_qty, product=product
)
record.update({
'price_tax': sum(t.get('amount', 0.0) for t in
taxes.get('taxes', [])),
'price_total': taxes['total_included'],
'price_subtotal': taxes['total_excluded'],
})
record.update(
{
"price_tax": sum(
t.get("amount", 0.0) for t in taxes.get("taxes", [])
),
"price_total": taxes["total_included"],
"price_subtotal": taxes["total_excluded"],
}
)
@api.depends('service_line_ids.day_qty')
@api.depends("service_line_ids.day_qty")
def _compute_days_qty(self):
for record in self:
if record.per_day:
qty = sum(record.service_line_ids.mapped('day_qty'))
vals = {
'days_qty': qty,
'product_qty': qty
}
qty = sum(record.service_line_ids.mapped("day_qty"))
vals = {"days_qty": qty, "product_qty": qty}
else:
vals = {'days_qty': 0}
vals = {"days_qty": 0}
record.update(vals)
# Constraints and onchanges
@api.onchange('product_id')
@api.onchange("product_id")
def onchange_product_id(self):
"""
Compute the default quantity according to the
@@ -274,13 +269,13 @@ class PmsService(models.Model):
if not self.product_id:
return
vals = {}
vals['product_qty'] = 1.0
vals["product_qty"] = 1.0
for record in self:
if record.per_day and record.reservation_id:
product = record.product_id
if self.env.context.get('default_reservation_id'):
reservation = self.env['pms.reservation'].browse(
self.env.context.get('default_reservation_id')
if self.env.context.get("default_reservation_id"):
reservation = self.env["pms.reservation"].browse(
self.env.context.get("default_reservation_id")
)
else:
reservation = record.reservation_id
@@ -293,14 +288,16 @@ class PmsService(models.Model):
checkin_dt = fields.Date.from_string(checkin)
checkout_dt = fields.Date.from_string(checkout)
nights = abs((checkout_dt - checkin_dt).days)
vals.update(record.prepare_service_ids(
dfrom=checkin,
days=nights,
per_person=product.per_person,
persons=reservation.adults,
old_line_days=record.service_line_ids,
consumed_on=product.consumed_on,
))
vals.update(
record.prepare_service_ids(
dfrom=checkin,
days=nights,
per_person=product.per_person,
persons=reservation.adults,
old_line_days=record.service_line_ids,
consumed_on=product.consumed_on,
)
)
if record.product_id.daily_limit > 0:
for day in record.service_line_ids:
day.no_free_resources()
@@ -308,64 +305,62 @@ class PmsService(models.Model):
Description and warnings
"""
product = self.product_id.with_context(
lang=self.folio_id.partner_id.lang,
partner=self.folio_id.partner_id.id
lang=self.folio_id.partner_id.lang, partner=self.folio_id.partner_id.id
)
title = False
message = False
warning = {}
if product.sale_line_warn != 'no-message':
if product.sale_line_warn != "no-message":
title = _("Warning for %s") % product.name
message = product.sale_line_warn_msg
warning['title'] = title
warning['message'] = message
result = {'warning': warning}
if product.sale_line_warn == 'block':
warning["title"] = title
warning["message"] = message
result = {"warning": warning}
if product.sale_line_warn == "block":
self.product_id = False
return result
name = product.name_get()[0][1]
if product.description_sale:
name += '\n' + product.description_sale
vals['name'] = name
name += "\n" + product.description_sale
vals["name"] = name
"""
Compute tax and price unit
"""
self._compute_tax_ids()
vals['price_unit'] = self._compute_price_unit()
vals["price_unit"] = self._compute_price_unit()
record.update(vals)
# Action methods
def open_service_ids(self):
action = self.env.ref('pms.action_pms_services_form').read()[0]
action['views'] = [
(self.env.ref('pms.pms_service_view_form').id, 'form')]
action['res_id'] = self.id
action['target'] = 'new'
action = self.env.ref("pms.action_pms_services_form").read()[0]
action["views"] = [(self.env.ref("pms.pms_service_view_form").id, "form")]
action["res_id"] = self.id
action["target"] = "new"
return action
# ORM Overrides
@api.model
def name_search(self, name='', args=None, operator='ilike', limit=100):
def name_search(self, name="", args=None, operator="ilike", limit=100):
if args is None:
args = []
if not(name == '' and operator == 'ilike'):
if not (name == "" and operator == "ilike"):
args += [
'|',
('reservation_id.name', operator, name),
('name', operator, name)
"|",
("reservation_id.name", operator, name),
("name", operator, name),
]
return super(PmsService, self).name_search(
name='', args=args, operator='ilike', limit=limit)
name="", args=args, operator="ilike", limit=limit
)
@api.model
def create(self, vals):
vals.update(self._prepare_add_missing_fields(vals))
if self.compute_lines_out_vals(vals):
reservation = self.env['pms.reservation'].browse(
vals['reservation_id'])
product = self.env['product.product'].browse(vals['product_id'])
reservation = self.env["pms.reservation"].browse(vals["reservation_id"])
product = self.env["product.product"].browse(vals["product_id"])
if reservation.splitted:
checkin = reservation.real_checkin
checkout = reservation.real_checkout
@@ -375,33 +370,34 @@ class PmsService(models.Model):
checkin_dt = fields.Date.from_string(checkin)
checkout_dt = fields.Date.from_string(checkout)
nights = abs((checkout_dt - checkin_dt).days)
vals.update(self.prepare_service_ids(
dfrom=checkin,
days=nights,
per_person=product.per_person,
persons=reservation.adults,
old_day_lines=False,
consumed_on=product.consumed_on,
))
vals.update(
self.prepare_service_ids(
dfrom=checkin,
days=nights,
per_person=product.per_person,
persons=reservation.adults,
old_day_lines=False,
consumed_on=product.consumed_on,
)
)
record = super(PmsService, self).create(vals)
return record
def write(self, vals):
# If you write product, We must check if its necesary create or delete
# service lines
if vals.get('product_id'):
product = self.env['product.product'].browse(
vals.get('product_id'))
if vals.get("product_id"):
product = self.env["product.product"].browse(vals.get("product_id"))
if not product.per_day:
vals.update({
'service_line_ids': [(5, 0, 0)]
})
vals.update({"service_line_ids": [(5, 0, 0)]})
else:
for record in self:
reservations = self.env['pms.reservation']
reservation = reservations.browse(vals['reservation_id']) \
if 'reservation_id' in vals else record.reservation_id
reservations = self.env["pms.reservation"]
reservation = (
reservations.browse(vals["reservation_id"])
if "reservation_id" in vals
else record.reservation_id
)
if reservation.splitted:
checkin = reservation.real_checkin
checkout = reservation.real_checkout
@@ -411,14 +407,16 @@ class PmsService(models.Model):
checkin_dt = fields.Date.from_string(checkin)
checkout_dt = fields.Date.from_string(checkout)
nights = abs((checkout_dt - checkin_dt).days)
record.update(record.prepare_service_ids(
dfrom=checkin,
days=nights,
per_person=product.per_person,
persons=reservation.adults,
old_line_days=self.service_line_ids,
consumed_on=product.consumed_on,
))
record.update(
record.prepare_service_ids(
dfrom=checkin,
days=nights,
per_person=product.per_person,
persons=reservation.adults,
old_line_days=self.service_line_ids,
consumed_on=product.consumed_on,
)
)
res = super(PmsService, self).write(vals)
return res
@@ -427,103 +425,123 @@ class PmsService(models.Model):
def _prepare_add_missing_fields(self, values):
""" Deduce missing required fields from the onchange """
res = {}
onchange_fields = ['price_unit', 'tax_ids', 'name']
if values.get('product_id'):
onchange_fields = ["price_unit", "tax_ids", "name"]
if values.get("product_id"):
line = self.new(values)
if any(f not in values for f in onchange_fields):
line.onchange_product_id()
for field in onchange_fields:
if field not in values:
res[field] = line._fields[field].convert_to_write(
line[field], line)
res[field] = line._fields[field].convert_to_write(line[field], line)
return res
def compute_lines_out_vals(self, vals):
"""
Compute if It is necesary service days in write/create
"""
if not vals:
vals = {}
if 'product_id' in vals:
product = self.env['product.product'].browse(vals['product_id']) \
if 'product_id' in vals else self.product_id
if (product.per_day and 'service_line_ids' not in vals):
if "product_id" in vals:
product = (
self.env["product.product"].browse(vals["product_id"])
if "product_id" in vals
else self.product_id
)
if product.per_day and "service_line_ids" not in vals:
return True
return False
def _compute_tax_ids(self):
for record in self:
# If company_id is set, always filter taxes by the company
folio = record.folio_id or self.env['pms.folio'].browse(
self.env.context.get('default_folio_id'))
folio = record.folio_id or self.env["pms.folio"].browse(
self.env.context.get("default_folio_id")
)
reservation = record.reservation_id or self.env.context.get(
'reservation_id')
"reservation_id"
)
origin = folio if folio else reservation
record.tax_ids = record.product_id.taxes_id.filtered(
lambda r: not record.company_id or
r.company_id == origin.company_id)
lambda r: not record.company_id or r.company_id == origin.company_id
)
def _get_display_price(self, product):
folio = self.folio_id or self.env.context.get('default_folio_id')
reservation = self.reservation_id or self.env.context.get(
'reservation_id')
folio = self.folio_id or self.env.context.get("default_folio_id")
reservation = self.reservation_id or self.env.context.get("reservation_id")
origin = folio if folio else reservation
if origin.pricelist_id.discount_policy == 'with_discount':
if origin.pricelist_id.discount_policy == "with_discount":
return product.with_context(pricelist=origin.pricelist_id.id).price
product_context = dict(
self.env.context,
partner_id=origin.partner_id.id,
date=folio.date_order if folio else fields.Date.today(),
uom=self.product_id.uom_id.id)
uom=self.product_id.uom_id.id,
)
final_price, rule_id = origin.pricelist_id.with_context(
product_context).get_product_price_rule(
self.product_id,
self.product_qty or 1.0,
origin.partner_id)
product_context
).get_product_price_rule(
self.product_id, self.product_qty or 1.0, origin.partner_id
)
base_price, currency_id = self.with_context(
product_context)._get_real_price_currency(
product,
rule_id,
self.product_qty,
self.product_id.uom_id,
origin.pricelist_id.id)
product_context
)._get_real_price_currency(
product,
rule_id,
self.product_qty,
self.product_id.uom_id,
origin.pricelist_id.id,
)
if currency_id != origin.pricelist_id.currency_id.id:
base_price = self.env['res.currency'].browse(
currency_id).with_context(product_context).compute(
base_price,
origin.pricelist_id.currency_id)
base_price = (
self.env["res.currency"]
.browse(currency_id)
.with_context(product_context)
.compute(base_price, origin.pricelist_id.currency_id)
)
# negative discounts (= surcharge) are included in the display price
return max(base_price, final_price)
def _compute_price_unit(self):
self.ensure_one()
folio = self.folio_id or self.env.context.get('default_folio_id')
reservation = self.reservation_id or self.env.context.get(
'reservation_id')
folio = self.folio_id or self.env.context.get("default_folio_id")
reservation = self.reservation_id or self.env.context.get("reservation_id")
origin = reservation if reservation else folio
if origin:
partner = origin.partner_id
pricelist = origin.pricelist_id
if reservation and self.is_board_service:
board_room_type = reservation.board_service_room_id
if board_room_type.price_type == 'fixed':
return self.env['pms.board.service.room.type.line'].\
search([
('pms_board_service_room_type_id',
'=', board_room_type.id),
('product_id', '=', self.product_id.id)]).amount
if board_room_type.price_type == "fixed":
return (
self.env["pms.board.service.room.type.line"]
.search(
[
(
"pms_board_service_room_type_id",
"=",
board_room_type.id,
),
("product_id", "=", self.product_id.id),
]
)
.amount
)
else:
return (reservation.price_total *
self.env['pms.board.service.room.type.line'].
search([
('pms_board_service_room_type_id',
'=', board_room_type.id),
('product_id', '=', self.product_id.id)])
.amount) / 100
return (
reservation.price_total
* self.env["pms.board.service.room.type.line"]
.search(
[
(
"pms_board_service_room_type_id",
"=",
board_room_type.id,
),
("product_id", "=", self.product_id.id),
]
)
.amount
) / 100
else:
product = self.product_id.with_context(
lang=partner.lang,
@@ -532,12 +550,14 @@ class PmsService(models.Model):
date=folio.date_order if folio else fields.Date.today(),
pricelist=pricelist.id,
uom=self.product_id.uom_id.id,
fiscal_position=False
fiscal_position=False,
)
return self.env['account.tax']._fix_tax_included_price_company(
return self.env["account.tax"]._fix_tax_included_price_company(
self._get_display_price(product),
product.taxes_id, self.tax_ids,
origin.company_id)
product.taxes_id,
self.tax_ids,
origin.company_id,
)
@api.model
def prepare_service_ids(self, **kwargs):
@@ -545,28 +565,26 @@ class PmsService(models.Model):
Prepare line and respect the old manual changes on lines
"""
cmds = [(5, 0, 0)]
old_line_days = kwargs.get('old_line_days')
consumed_on = kwargs.get('consumed_on') if kwargs.get(
'consumed_on') else 'before'
old_line_days = kwargs.get("old_line_days")
consumed_on = (
kwargs.get("consumed_on") if kwargs.get("consumed_on") else "before"
)
total_qty = 0
day_qty = 1
# WARNING: Change adults in reservation NOT update qty service!!
if kwargs.get('per_person'):
day_qty = kwargs.get('persons')
for i in range(0, kwargs.get('days')):
if consumed_on == 'after':
if kwargs.get("per_person"):
day_qty = kwargs.get("persons")
for i in range(0, kwargs.get("days")):
if consumed_on == "after":
i += 1
idate = (fields.Date.from_string(kwargs.get('dfrom')) +
timedelta(days=i)).strftime(
DEFAULT_SERVER_DATE_FORMAT)
if not old_line_days or idate not in old_line_days.mapped('date'):
cmds.append((0, False, {
'date': idate,
'day_qty': day_qty
}))
idate = (
fields.Date.from_string(kwargs.get("dfrom")) + timedelta(days=i)
).strftime(DEFAULT_SERVER_DATE_FORMAT)
if not old_line_days or idate not in old_line_days.mapped("date"):
cmds.append((0, False, {"date": idate, "day_qty": day_qty}))
total_qty = total_qty + day_qty
else:
old_line = old_line_days.filtered(lambda r: r.date == idate)
cmds.append((4, old_line.id))
total_qty = total_qty + old_line.day_qty
return {'service_line_ids': cmds, 'product_qty': total_qty}
return {"service_line_ids": cmds, "product_qty": total_qty}

View File

@@ -1,7 +1,7 @@
# Copyright 2017-2018 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, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
@@ -12,50 +12,39 @@ class PmsServiceLine(models.Model):
# Fields declaration
service_id = fields.Many2one(
'pms.service',
string='Service Room',
ondelete='cascade',
"pms.service",
string="Service Room",
ondelete="cascade",
required=True,
copy=False)
product_id = fields.Many2one(
related='service_id.product_id',
store=True)
copy=False,
)
product_id = fields.Many2one(related="service_id.product_id", store=True)
tax_ids = fields.Many2many(
'account.tax',
string='Taxes',
related="service_id.tax_ids",
readonly="True")
"account.tax", string="Taxes", related="service_id.tax_ids", readonly="True"
)
pms_property_id = fields.Many2one(
'pms.property',
store=True,
readonly=True,
related='service_id.pms_property_id')
date = fields.Date('Date')
day_qty = fields.Integer('Units')
"pms.property", store=True, readonly=True, related="service_id.pms_property_id"
)
date = fields.Date("Date")
day_qty = fields.Integer("Units")
price_total = fields.Float(
'Price Total',
compute='_compute_price_total',
store=True)
"Price Total", compute="_compute_price_total", store=True
)
price_unit = fields.Float(
'Unit Price',
related="service_id.price_unit",
readonly=True,
store=True)
"Unit Price", related="service_id.price_unit", readonly=True, store=True
)
room_id = fields.Many2one(
string='Room',
related="service_id.reservation_id",
readonly=True,
store=True)
string="Room", related="service_id.reservation_id", readonly=True, store=True
)
discount = fields.Float(
'Discount',
related="service_id.discount",
readonly=True,
store=True)
"Discount", related="service_id.discount", readonly=True, store=True
)
cancel_discount = fields.Float(
'Discount cancel', compute='_compute_cancel_discount')
"Discount cancel", compute="_compute_cancel_discount"
)
# Compute and Search methods
@api.depends('day_qty', 'service_id.price_total')
@api.depends("day_qty", "service_id.price_total")
def _compute_price_total(self):
"""
Used to reports
@@ -63,26 +52,33 @@ class PmsServiceLine(models.Model):
for record in self:
if record.service_id.product_qty != 0:
record.price_total = (
record.service_id.price_total * record.day_qty) \
/ record.service_id.product_qty
record.service_id.price_total * record.day_qty
) / record.service_id.product_qty
else:
record.price_total = 0
# Constraints and onchanges
@api.constrains('day_qty')
@api.constrains("day_qty")
def no_free_resources(self):
for record in self:
limit = record.product_id.daily_limit
if limit > 0:
out_qty = sum(self.env['pms.service.line'].search([
('product_id', '=', record.product_id.id),
('date', '=', record.date),
('service_id', '!=', record.service_id.id)
]).mapped('day_qty'))
out_qty = sum(
self.env["pms.service.line"]
.search(
[
("product_id", "=", record.product_id.id),
("date", "=", record.date),
("service_id", "!=", record.service_id.id),
]
)
.mapped("day_qty")
)
if limit < out_qty + record.day_qty:
raise ValidationError(
_("%s limit exceeded for %s") %
(record.service_id.product_id.name, record.date))
_("%s limit exceeded for %s")
% (record.service_id.product_id.name, record.date)
)
# Business methods
def _cancel_discount(self):

View File

@@ -2,111 +2,112 @@
# Copyright 2017 Dario Lodeiros
# Copyright 2018 Pablo Quesada
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class PmsSharedRoom(models.Model):
_name = 'pms.shared.room'
_description = 'Shared Room'
_name = "pms.shared.room"
_description = "Shared Room"
_order = "room_type_id, name"
# Fields declaration
name = fields.Char('Room Name', required=True)
name = fields.Char("Room Name", required=True)
room_type_id = fields.Many2one(
'pms.room.type',
'Room Type',
"pms.room.type",
"Room Type",
required=True,
ondelete='restrict',
domain=[('shared_room', '=', True)]
)
ondelete="restrict",
domain=[("shared_room", "=", True)],
)
pms_property_id = fields.Many2one(
'pms.property',
"pms.property",
store=True,
readonly=True,
related='room_type_id.pms_property_id')
related="room_type_id.pms_property_id",
)
floor_id = fields.Many2one(
'pms.floor',
'Ubication',
ondelete='restrict',
help='At which floor the room is located.')
"pms.floor",
"Ubication",
ondelete="restrict",
help="At which floor the room is located.",
)
bed_ids = fields.One2many(
'pms.room',
'shared_room_id',
readonly=True,
ondelete='restrict',)
active = fields.Boolean('Active', default=True)
sequence = fields.Integer('Sequence', required=True)
beds = fields.Integer('Beds')
"pms.room", "shared_room_id", readonly=True, ondelete="restrict",
)
active = fields.Boolean("Active", default=True)
sequence = fields.Integer("Sequence", required=True)
beds = fields.Integer("Beds")
description_sale = fields.Text(
'Sale Description',
"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")
" your customers. This description will be copied to every Sales "
" Order, Delivery Order and Customer Invoice/Credit Note",
)
# Constraints and onchanges
@api.constrains('beds')
@api.constrains("beds")
def _constrain_beds(self):
self.ensure_one()
if self.beds < 1:
raise ValidationError(_("Room beds can't be less than one"))
if len(self.bed_ids) > self.beds:
raise ValidationError(_(
"If you want to eliminate beds in the \
room you must deactivate the beds from your form"))
raise ValidationError(
_(
"If you want to eliminate beds in the \
room you must deactivate the beds from your form"
)
)
beds = []
inactive_beds = self.env['pms.room'].search([
('active', '=', False),
('shared_room_id', '=', self.id)
])
inactive_beds = self.env["pms.room"].search(
[("active", "=", False), ("shared_room_id", "=", self.id)]
)
for i in range(len(self.bed_ids), self.beds):
if inactive_beds:
bed = inactive_beds[0]
bed.update({'active': True})
bed.update({"active": True})
inactive_beds -= bed
continue
name = u'%s (%s)' % (self.name, i + 1)
name = u"{} ({})".format(self.name, i + 1)
bed_vals = {
'name': name,
'capacity': 1,
'room_type_id': self.room_type_id.id,
'sequence': self.sequence,
'floor_id': self.floor_id.id if self.floor_id else False,
'shared_room_id': self.id,
"name": name,
"capacity": 1,
"room_type_id": self.room_type_id.id,
"sequence": self.sequence,
"floor_id": self.floor_id.id if self.floor_id else False,
"shared_room_id": self.id,
}
beds.append((0, False, bed_vals))
if beds:
self.update({
'bed_ids': beds
})
self.update({"bed_ids": beds})
@api.constrains('active')
@api.constrains("active")
def _constrain_active(self):
self.bed_ids.write({
'active': self.active,
})
self.bed_ids.write(
{"active": self.active,}
)
@api.constrains('room_type_id')
@api.constrains("room_type_id")
def _constrain_room_type_id(self):
self.bed_ids.write({
'room_type_id': self.room_type_id.id,
})
self.bed_ids.write(
{"room_type_id": self.room_type_id.id,}
)
@api.constrains('floor_id')
@api.constrains("floor_id")
def _constrain_floor_id(self):
self.bed_ids.write({
'floor_id': self.floor_id.id,
})
self.bed_ids.write(
{"floor_id": self.floor_id.id,}
)
@api.constrains('sequence')
@api.constrains("sequence")
def _constrain_sequence(self):
self.bed_ids.write({
'sequence': self.sequence,
})
self.bed_ids.write(
{"sequence": self.sequence,}
)
@api.constrains('descrition_sale')
@api.constrains("descrition_sale")
def _constrain_descrition_sale(self):
self.bed_ids.write({
'description_sale': self.descrition_sale,
})
self.bed_ids.write(
{"description_sale": self.descrition_sale,}
)

View File

@@ -3,4 +3,4 @@ the module before using it; it is aimed at advanced users. ]
You will find the hotel settings in `Settings > Users & Companies > Hotels > Your Hotel.
This module required additional configuration for company, accounting, invoicing and user privileges.
This module required additional configuration for company, accounting, invoicing and user privileges.

View File

@@ -1,2 +1,2 @@
.. [ This file is optional and contains additional credits, other than
authors, contributors, and maintainers. ]
authors, contributors, and maintainers. ]

View File

@@ -4,4 +4,4 @@ This module is an all-in-one property management system (PMS) focused on medium-
for managing every aspect of your property's daily operations.
You can manage hotel properties with multi-hotel and multi-company support, including your rooms inventory,
reservations, check-in, daily reports, board services, rate and restriction plans among other hotel functionalities.
reservations, check-in, daily reports, board services, rate and restriction plans among other hotel functionalities.

View File

@@ -2,4 +2,4 @@
installation instructions, such as installing non-python dependencies. The audience is systems administrators. ]
This module depends on modules ``base``, ``sale_stock``, ``account_payment_return``, ``partner_firstname``,
and ``account_cancel``. Ensure yourself to have all them in your addons list.
and ``account_cancel``. Ensure yourself to have all them in your addons list.

View File

@@ -1,4 +1,4 @@
.. [ Enumerate known caveats and future potential improvements.
It is mostly intended for end-users, and can also help potential new contributors discovering new features to implement. ]
- [ ]
- [ ]

View File

@@ -3,4 +3,4 @@ for end-users. As all other rst files included in the README, it MUST NOT contai
only body text (paragraphs, lists, tables, etc). Should you need a more elaborate structure to explain the addon,
please create a Sphinx documentation (which may include this file as a "quick start" section). ]
To use this module, please, read the complete user guide at https://roomdoo.com.
To use this module, please, read the complete user guide at https://roomdoo.com.

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<report

View File

@@ -1,232 +1,322 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<template id="report_folio_document">
<t t-call="web.external_layout">
<t t-set="doc" t-value="doc.with_context({'lang':doc.partner_id.lang})" />
<div class="page">
<div class="oe_structure"/>
<div class="row">
<div class="col-xs-6">
<t t-if="doc.partner_invoice_id != doc.partner_id">
<div t-field="doc.partner_invoice_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone"], "no_marker": True, "phone_icons": True}'/>
</t>
<template id="report_folio_document">
<t t-call="web.external_layout">
<t t-set="doc" t-value="doc.with_context({'lang':doc.partner_id.lang})" />
<div class="page">
<div class="oe_structure" />
<div class="row">
<div class="col-xs-6">
<t t-if="doc.partner_invoice_id != doc.partner_id">
<div
t-field="doc.partner_invoice_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone"], "no_marker": True, "phone_icons": True}'
/>
</t>
</div>
<div class="col-xs-5 col-xs-offset-1">
<div
t-field="doc.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'
/>
<p t-if="doc.partner_id.vat"><t
t-esc="doc.company_id.country_id.vat_label or 'TIN'"
/>: <span t-field="doc.partner_id.vat" /></p>
</div>
</div>
<div class="col-xs-5 col-xs-offset-1">
<div t-field="doc.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}' />
<p t-if="doc.partner_id.vat"><t t-esc="doc.company_id.country_id.vat_label or 'TIN'"/>: <span t-field="doc.partner_id.vat"/></p>
<h2>
<span t-if="doc.state not in ['draft','sent']">Order # </span>
<span t-if="doc.state in ['draft','sent']">Quotation # </span>
<span t-field="doc.name" />
</h2>
<div class="row mt32 mb32" id="informations">
<div t-if="doc.client_order_ref" class="col-xs-3">
<strong>Your Reference:</strong>
<p t-field="doc.client_order_ref" />
</div>
<div
t-if="doc.confirmation_date and doc.state not in ['draft','sent']"
class="col-xs-3"
>
<strong>Date Ordered:</strong>
<p t-field="doc.confirmation_date" />
</div>
<div
t-if="doc.date_order and doc.state in ['draft','sent']"
class="col-xs-3"
>
<strong>Quotation Date:</strong>
<p t-field="doc.date_order" />
</div>
<div t-if="doc.user_id.name" class="col-xs-3">
<strong>Salesperson:</strong>
<p t-field="doc.user_id" />
</div>
<div
name="payment_term"
t-if="doc.payment_term_id"
class="col-xs-3"
>
<strong>Payment Terms:</strong>
<p t-field="doc.payment_term_id" />
</div>
</div>
</div>
<h2>
<span t-if="doc.state not in ['draft','sent']">Order # </span>
<span t-if="doc.state in ['draft','sent']">Quotation # </span>
<span t-field="doc.name"/>
</h2>
<div class="row mt32 mb32" id="informations">
<div t-if="doc.client_order_ref" class="col-xs-3">
<strong>Your Reference:</strong>
<p t-field="doc.client_order_ref"/>
</div>
<div t-if="doc.confirmation_date and doc.state not in ['draft','sent']" class="col-xs-3">
<strong>Date Ordered:</strong>
<p t-field="doc.confirmation_date"/>
</div>
<div t-if="doc.date_order and doc.state in ['draft','sent']" class="col-xs-3">
<strong>Quotation Date:</strong>
<p t-field="doc.date_order"/>
</div>
<div t-if="doc.user_id.name" class="col-xs-3">
<strong>Salesperson:</strong>
<p t-field="doc.user_id"/>
</div>
<div name="payment_term" t-if="doc.payment_term_id" class="col-xs-3">
<strong>Payment Terms:</strong>
<p t-field="doc.payment_term_id"/>
</div>
</div>
<!-- Is there a discount on at least one line? -->
<t t-set="display_discount" t-value="any([l.discount for l in doc.reservation_ids])"/>
<!-- Is there a discount on at least one line? -->
<t
t-set="display_discount"
t-value="any([l.discount for l in doc.reservation_ids])"
/>
<table class="table table-condensed">
<thead>
<tr>
<th>Description</th>
<th class="text-right">Quantity</th>
<th t-if="display_discount" class="text-right" groups="sale.group_discount_per_so_line">Disc.(%)</th>
<th
t-if="display_discount"
class="text-right"
groups="sale.group_discount_per_so_line"
>Disc.(%)</th>
<th class="text-right">Taxes</th>
<th class="text-right" groups="sale.group_show_price_subtotal">Amount</th>
<th class="text-right price_tax_included" groups="sale.group_show_price_total">Total Price</th>
<th
class="text-right"
groups="sale.group_show_price_subtotal"
>Amount</th>
<th
class="text-right price_tax_included"
groups="sale.group_show_price_total"
>Total Price</th>
</tr>
</thead>
<tbody class="sale_tbody">
<!-- Lines associated -->
<t t-foreach="doc.reservation_ids" t-as="l">
<t t-if="l.to_print == True and l.price_total > 0">
<tr>
<td><span t-field="l.name"/></td>
<td class="text-right">
<span t-field="l.nights"/>
</td>
<td t-if="display_discount" class="text-right" groups="sale.group_discount_per_so_line">
<span t-field="l.discount"/>
</td>
<td class="text-right">
<span t-esc="', '.join(map(lambda x: (x.description or x.name), l.tax_ids))"/>
</td>
<td class="text-right" groups="sale.group_show_price_subtotal">
<span t-field="l.price_subtotal"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'/>
</td>
<td class="text-right" groups="sale.group_show_price_total">
<span t-field="l.price_total"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'/>
</td>
</tr>
</t>
</t>
<t t-foreach="doc.service_ids" t-as="l">
<t t-if="l.to_print == True and l.price_total > 0">
<tr>
<td><span t-field="l.name"/></td>
<td class="text-right">
<span t-field="l.product_qty"/>
</td>
<td t-if="display_discount" class="text-right" groups="sale.group_discount_per_so_line">
<span t-field="l.discount"/>
</td>
<td class="text-right">
<span t-esc="', '.join(map(lambda x: (x.description or x.name), l.tax_ids))"/>
</td>
<td class="text-right" groups="sale.group_show_price_subtotal">
<span t-field="l.price_subtotal"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'/>
</td>
<td class="text-right" groups="sale.group_show_price_total">
<span t-field="l.price_total"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'/>
</td>
</tr>
</t>
</t>
</tbody>
</table>
<div class="clearfix">
<div class="row" name="total">
<div class="col-xs-4 pull-right">
<table class="table table-condensed" style="min-width: 200px;max-width: 350px;">
<tr class="border-black" style="border-bottom:1px solid #dddddd;">
<td><strong>Subtotal</strong></td>
<td class="text-right">
<span t-field="doc.amount_untaxed"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'/>
</td>
</tr>
-<t t-foreach="doc._get_tax_amount_by_group()" t-as="amount_by_group">
<tr style="border-bottom:1px solid #dddddd;">
<t t-if="amount_by_group[3] == 1 and doc.amount_untaxed == amount_by_group[2]">
<td>
<span t-esc="amount_by_group[0]"/>
<span>&amp;nbsp;<span>on</span>&amp;nbsp;<t t-esc="amount_by_group[2]" t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'/></span>
</td>
<td class="text-right">
<span t-esc="amount_by_group[1]"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'/>
</td>
</t>
<t t-else ="">
<td>
<span t-esc="amount_by_group[0]"/>
</td>
<td class="text-right">
<span t-esc="amount_by_group[1]"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'/>
</td>
</t>
</thead>
<tbody class="sale_tbody">
<!-- Lines associated -->
<t t-foreach="doc.reservation_ids" t-as="l">
<t t-if="l.to_print == True and l.price_total > 0">
<tr>
<td>
<span t-field="l.name" />
</td>
<td class="text-right">
<span t-field="l.nights" />
</td>
<td
t-if="display_discount"
class="text-right"
groups="sale.group_discount_per_so_line"
>
<span t-field="l.discount" />
</td>
<td class="text-right">
<span
t-esc="', '.join(map(lambda x: (x.description or x.name), l.tax_ids))"
/>
</td>
<td
class="text-right"
groups="sale.group_show_price_subtotal"
>
<span
t-field="l.price_subtotal"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'
/>
</td>
<td
class="text-right"
groups="sale.group_show_price_total"
>
<span
t-field="l.price_total"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'
/>
</td>
</tr>
</t>
</t>
<t t-foreach="doc.service_ids" t-as="l">
<t t-if="l.to_print == True and l.price_total > 0">
<tr>
<td>
<span t-field="l.name" />
</td>
<td class="text-right">
<span t-field="l.product_qty" />
</td>
<td
t-if="display_discount"
class="text-right"
groups="sale.group_discount_per_so_line"
>
<span t-field="l.discount" />
</td>
<td class="text-right">
<span
t-esc="', '.join(map(lambda x: (x.description or x.name), l.tax_ids))"
/>
</td>
<td
class="text-right"
groups="sale.group_show_price_subtotal"
>
<span
t-field="l.price_subtotal"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'
/>
</td>
<td
class="text-right"
groups="sale.group_show_price_total"
>
<span
t-field="l.price_total"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'
/>
</td>
</tr>
</t>
</t>
</tbody>
</table>
<div class="clearfix">
<div class="row" name="total">
<div class="col-xs-4 pull-right">
<table
class="table table-condensed"
style="min-width: 200px;max-width: 350px;"
>
<tr
class="border-black"
style="border-bottom:1px solid #dddddd;"
>
<td>
<strong>Subtotal</strong>
</td>
<td class="text-right">
<span
t-field="doc.amount_untaxed"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'
/>
</td>
</tr>
-<t
t-foreach="doc._get_tax_amount_by_group()"
t-as="amount_by_group"
>
<tr style="border-bottom:1px solid #dddddd;">
<t
t-if="amount_by_group[3] == 1 and doc.amount_untaxed == amount_by_group[2]"
>
<td>
<span t-esc="amount_by_group[0]" />
<span>&amp;nbsp;<span
>on</span>&amp;nbsp;<t
t-esc="amount_by_group[2]"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'
/></span>
</td>
<td class="text-right">
<span
t-esc="amount_by_group[1]"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'
/>
</td>
</t>
<t t-else="">
<td>
<span t-esc="amount_by_group[0]" />
</td>
<td class="text-right">
<span
t-esc="amount_by_group[1]"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'
/>
</td>
</t>
</tr>
</t>
<tr class="border-black">
<td><strong>Total</strong></td>
<td class="text-right">
<span t-field="doc.amount_total"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'/>
</td>
</tr>
<td>
<strong>Total</strong>
</td>
<td class="text-right">
<span
t-field="doc.amount_total"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'
/>
</td>
</tr>
<tr class="border-black">
<td><strong>Pending Payment</strong></td>
<td class="text-right">
<span t-field="doc.pending_amount"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'/>
</td>
</tr>
<td>
<strong>Pending Payment</strong>
</td>
<td class="text-right">
<span
t-field="doc.pending_amount"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'
/>
</td>
</tr>
</table>
</div>
</div>
</div>
<div>
<span t-if="doc.payment_ids">
<table style="width:80%;">
<thead>
<tr>
<th>Payment Ref.</th>
<th>Payment Date</th>
<th>Payment Method</th>
<th>Paid Amount</th>
</tr>
</thead>
<tbody>
<tr t-foreach="doc.payment_ids" t-as="l">
<td t-esc="l.name" />
<td t-esc="l.payment_date" />
<td t-esc="l.journal_id.name" />
<td t-esc="l.amount" />
</tr>
</tbody>
</table>
</span>
<span t-if="doc.return_ids">
<table style="width:80%;">
<thead>
<tr>
<th>Return Ref.</th>
<th>Return Date</th>
<th>Return Method</th>
<th>Return Amount</th>
</tr>
</thead>
<tbody>
<tr t-foreach="doc.return_ids" t-as="r">
<td t-esc="r.name" />
<td t-esc="r.date" />
<td t-esc="r.journal_id.name" />
<t
t-set="total_amount"
t-value="sum(l.amount for l in r.line_ids)"
/>
<td t-esc="total_amount" />
</tr>
</tbody>
</table>
</span>
</div>
<p t-field="doc.note" />
<p t-if="doc.payment_term_id.note">
<span t-field="doc.payment_term_id.note" />
</p>
<div class="oe_structure" />
</div>
<div>
<span t-if="doc.payment_ids">
<table style="width:80%;">
<thead>
<tr>
<th>Payment Ref.</th>
<th>Payment Date</th>
<th>Payment Method</th>
<th>Paid Amount</th>
</tr>
</thead>
<tbody>
<tr t-foreach="doc.payment_ids" t-as="l">
<td t-esc="l.name" />
<td t-esc="l.payment_date" />
<td t-esc="l.journal_id.name" />
<td t-esc="l.amount" />
</tr>
</tbody>
</table>
</span>
<span t-if="doc.return_ids">
<table style="width:80%;">
<thead>
<tr>
<th>Return Ref.</th>
<th>Return Date</th>
<th>Return Method</th>
<th>Return Amount</th>
</tr>
</thead>
<tbody>
<tr t-foreach="doc.return_ids" t-as="r">
<td t-esc="r.name" />
<td t-esc="r.date" />
<td t-esc="r.journal_id.name" />
<t t-set="total_amount" t-value="sum(l.amount for l in r.line_ids)"/>
<td t-esc="total_amount" />
</tr>
</tbody>
</table>
</span>
</div>
<p t-field="doc.note" />
<p t-if="doc.payment_term_id.note">
<span t-field="doc.payment_term_id.note"/>
</p>
<div class="oe_structure"/>
</div>
</t>
</template>
<template id="report_folio">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="pms.report_folio_document" t-lang="doc.partner_id.lang"/>
</t>
</t>
</template>
</template>
<template id="report_folio">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="pms.report_folio_document" t-lang="doc.partner_id.lang" />
</t>
</t>
</template>
</odoo>

View File

@@ -1,22 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="0">
<!--Group for pms user -->
<record id="group_pms_user" model="res.groups">
<field name="name">Property Management / User</field>
</record>
<!--Group for pms manager -->
<record id="group_pms_manager" model="res.groups">
<field name="name">Property Management/ Manager</field>
<field name="implied_ids" eval="[(4, ref('pms.group_pms_user'))]"/>
<field name="implied_ids" eval="[(4, ref('pms.group_pms_user'))]" />
</record>
<!--Group for pms user -->
<record id="group_pms_call" model="res.groups">
<field name="name">Property Management / CallCenter</field>
</record>
</data>
</odoo>

View File

@@ -1,28 +1,32 @@
odoo.define('pms.ListController', function(require) {
'use strict';
/*
* Pms
* GNU Public License
* Alexandre Díaz <dev@redneboa.es>
*/
odoo.define("pms.ListController", function(require) {
"use strict";
/*
* Pms
* GNU Public License
* Alexandre Díaz <dev@redneboa.es>
*/
var ListController = require('web.ListController');
var Core = require('web.core');
var ListController = require("web.ListController");
var Core = require("web.core");
var _t = Core._t;
ListController.include({
renderButtons: function () {
this._super.apply(this, arguments); // Sets this.$buttons
var self = this;
if (this.modelName === 'pms.reservation') {
this.$buttons.append("<button class='btn btn-sm oe_open_reservation_wizard oe_highlight' type='button'>"+_t('Open Wizard')+"</button>");
this.$buttons.find('.oe_open_reservation_wizard').on('click', function(){
self.do_action('pms.open_wizard_reservations');
});
}
}
});
var _t = Core._t;
ListController.include({
renderButtons: function() {
this._super.apply(this, arguments); // Sets this.$buttons
var self = this;
if (this.modelName === "pms.reservation") {
this.$buttons.append(
"<button class='btn btn-sm oe_open_reservation_wizard oe_highlight' type='button'>" +
_t("Open Wizard") +
"</button>"
);
this.$buttons
.find(".oe_open_reservation_wizard")
.on("click", function() {
self.do_action("pms.open_wizard_reservations");
});
}
},
});
});

View File

@@ -1,61 +1,77 @@
odoo.define('pms.SwitchPmsMenu', function(require) {
"use strict";
odoo.define("pms.SwitchPmsMenu", function(require) {
"use strict";
var config = require('web.config');
var core = require('web.core');
var session = require('web.session');
var SystrayMenu = require('web.SystrayMenu');
var Widget = require('web.Widget');
var config = require("web.config");
var core = require("web.core");
var session = require("web.session");
var SystrayMenu = require("web.SystrayMenu");
var Widget = require("web.Widget");
var _t = core._t;
var _t = core._t;
var SwitchPmsMenu = Widget.extend({
template: 'pms.SwitchPmsMenu',
willStart: function() {
this.isMobile = config.device.isMobile;
if (!session.user_pms) {
return $.Deferred().reject();
}
return this._super();
},
start: function() {
var self = this;
this.$el.on('click', '.dropdown-menu li a[data-menu]', _.debounce(function(ev) {
ev.preventDefault();
var pms_property_id = $(ev.currentTarget).data('property-id');
self._rpc({
model: 'res.users',
method: 'write',
args: [[session.uid], {'pms_property_id': pms_property_id}],
})
.then(function() {
location.reload();
});
}, 1500, true));
var properties_list = '';
if (this.isMobile) {
propertiess_list = '<li class="bg-info">' + _t('Tap on the list to change property') + '</li>';
}
else {
self.$('.oe_topbar_name').text(session.user_properties.current_property[1]);
}
_.each(session.user_properties.allowed_propierties, function(property) {
var a = '';
if (property[0] === session.user_properties.current_property[0]) {
a = '<i class="fa fa-check mr8"></i>';
} else {
a = '<span class="mr24"/>';
var SwitchPmsMenu = Widget.extend({
template: "pms.SwitchPmsMenu",
willStart: function() {
this.isMobile = config.device.isMobile;
if (!session.user_pms) {
return $.Deferred().reject();
}
properties_list += '<li><a href="#" data-menu="property" data-property-id="' + property[0] + '">' + a + property[1] + '</a></li>';
});
self.$('.dropdown-menu').html(properties_list);
return this._super();
},
});
SystrayMenu.Items.push(SwitchPmsMenu);
return SwitchPmsMenu;
return this._super();
},
start: function() {
var self = this;
this.$el.on(
"click",
".dropdown-menu li a[data-menu]",
_.debounce(
function(ev) {
ev.preventDefault();
var pms_property_id = $(ev.currentTarget).data("property-id");
self._rpc({
model: "res.users",
method: "write",
args: [[session.uid], {pms_property_id: pms_property_id}],
}).then(function() {
location.reload();
});
},
1500,
true
)
);
var properties_list = "";
if (this.isMobile) {
propertiess_list =
'<li class="bg-info">' +
_t("Tap on the list to change property") +
"</li>";
} else {
self.$(".oe_topbar_name").text(
session.user_properties.current_property[1]
);
}
_.each(session.user_properties.allowed_propierties, function(property) {
var a = "";
if (property[0] === session.user_properties.current_property[0]) {
a = '<i class="fa fa-check mr8"></i>';
} else {
a = '<span class="mr24"/>';
}
properties_list +=
'<li><a href="#" data-menu="property" data-property-id="' +
property[0] +
'">' +
a +
property[1] +
"</a></li>";
});
self.$(".dropdown-menu").html(properties_list);
return this._super();
},
});
SystrayMenu.Items.push(SwitchPmsMenu);
return SwitchPmsMenu;
});

View File

@@ -1,12 +1,18 @@
<template>
<t t-name="pms.SwitchPmsMenu">
<li class="o_switch_company_menu">
<a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" href="#">
<span t-attf-class="#{widget.isMobile ? 'fa fa-building-o' : 'oe_topbar_name'}"/> <span class="caret"/>
</a>
<ul class="dropdown-menu" role="menu"/>
</li>
</t>
<t t-name="pms.SwitchPmsMenu">
<li class="o_switch_company_menu">
<a
class="dropdown-toggle"
data-toggle="dropdown"
aria-expanded="false"
href="#"
>
<span
t-attf-class="#{widget.isMobile ? 'fa fa-building-o' : 'oe_topbar_name'}"
/>
<span class="caret" />
</a>
<ul class="dropdown-menu" role="menu" />
</li>
</t>
</template>

View File

@@ -1,117 +1,139 @@
<?xml version="1.0"?>
<?xml version="1.0" ?>
<odoo>
<data noupdate="0">
<template id="template_header">
<h1 t-field="object.pms_property_id.name" />
<div class="row">
<div class="col-sm-4">
<template id="template_header">
<h1 t-field="object.pms_property_id.name" />
<div class="row">
<div class="col-sm-4">
<t t-esc="object.pms_property_id.street" />
<t t-if="object.pms_property_id.street2" >- <t t-esc="object.pms_property_id.street2" /></t> <br />
<t t-if="object.pms_property_id.street2">- <t
t-esc="object.pms_property_id.street2"
/></t> <br />
<t t-esc="object.pms_property_id.zip" />
<t t-esc="object.pms_property_id.city" />,
<t t-esc="object.pms_property_id.state_id.name" /> <br />
<t t-esc="object.pms_property_id.country_id.name" />
</div>
<div class="col-sm-4">
<i class="glyphicon glyphicon-phone-alt" /> <t t-esc="object.pms_property_id.phone" /> <br />
<i class="glyphicon glyphicon-envelope" /> <t t-esc="object.pms_property_id.email" /> <br />
<i class="glyphicon glyphicon-home" /> <t t-esc="object.pms_property_id.website" /> <br />
<div class="col-sm-4">
<i class="glyphicon glyphicon-phone-alt" />
<t t-esc="object.pms_property_id.phone" />
<br />
<i class="glyphicon glyphicon-envelope" />
<t t-esc="object.pms_property_id.email" />
<br />
<i class="glyphicon glyphicon-home" />
<t t-esc="object.pms_property_id.website" />
<br />
</div>
</div>
</div>
</template>
<template id="template_reservation_details">
<div class="row table-responsive" style="padding-top: 20px;">
<div class="col-sm-12">
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Room Type</th>
<th scope="col">Checkin</th>
<th scope="col">Nights</th>
<th scope="col">Price <t t-esc="object.currency_id.name"/></th>
</tr>
</thead>
<tbody>
<t t-foreach="object.reservation_ids" t-as="r">
</template>
<template id="template_reservation_details">
<div class="row table-responsive" style="padding-top: 20px;">
<div class="col-sm-12">
<table class="table">
<thead>
<tr>
<th scope="row"><t t-esc="r_index+1"/></th>
<td><t t-esc="r.room_type_id.name"/></td>
<td><t t-esc="r.real_checkin"/></td>
<td><t t-esc="r.nights"/></td>
<td><t t-esc="r.price_total"/></td>
<th scope="col">#</th>
<th scope="col">Room Type</th>
<th scope="col">Checkin</th>
<th scope="col">Nights</th>
<th scope="col">Price <t
t-esc="object.currency_id.name"
/></th>
</tr>
</t>
</tbody>
</table>
</thead>
<tbody>
<t t-foreach="object.reservation_ids" t-as="r">
<tr>
<th scope="row">
<t t-esc="r_index+1" />
</th>
<td>
<t t-esc="r.room_type_id.name" />
</td>
<td>
<t t-esc="r.real_checkin" />
</td>
<td>
<t t-esc="r.nights" />
</td>
<td>
<t t-esc="r.price_total" />
</td>
</tr>
</t>
</tbody>
</table>
</div>
</div>
</div>
</template>
<template id="template_reservation">
<div class="row" style="padding-top: 20px;">
<div class="col-sm-12">
<p>Dear <span t-field="object.partner_id.name"/>,<br />
</template>
<template id="template_reservation">
<div class="row" style="padding-top: 20px;">
<div class="col-sm-12">
<p>Dear <span t-field="object.partner_id.name" />,<br />
Thank you for your reservation.</p>
<p>Here is your confirmation code: <b t-esc="object.name" />.
<p>Here is your confirmation code: <b t-esc="object.name" />.
Keep this code for any question about your booking order.</p>
<p>You can find the reservation details below:</p>
<p>You can find the reservation details below:</p>
</div>
</div>
</div>
<t t-call="pms.template_reservation_details"/>
<div class="row" style="padding-top: 20px;">
<div class="col-sm-12">
If you have any questions, please do not hesitate to contact with the property's staff. <br/>
<t t-call="pms.template_reservation_details" />
<div class="row" style="padding-top: 20px;">
<div class="col-sm-12">
If you have any questions, please do not hesitate to contact with the property's staff. <br
/>
Looking forward to seeing you at our property, <br />
Best regards.
</div>
</div>
</template>
<template id="template_footer">
<div class="row" style="padding-top: 20px;">
<div class="col-sm-12">
</div>
</template>
<template id="template_footer">
<div class="row" style="padding-top: 20px;">
<div class="col-sm-12">
Privacy Policy: We use your Personal Information only for managing your reservation. By using the property, you
agree to the collection and use of information in accordance with this policy.
</div>
</div>
</template>
<template id="template_reservation_confirmed" name="Property Reservation Confirmed">
<t t-call="web.layout">
<t t-set="head">
<!-- TODO: ensure bootstrap in shipped within the email -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous" />
</t>
<t t-set="body_classname" t-value="'container'"/>
<div class="container">
<t t-call="pms.template_header"/>
<t t-call="pms.template_reservation"/>
<t t-call="pms.template_footer"/>
</div>
</t>
</template>
<!-- notify customer that reservation has been confirmed -->
<record id="email_template_reservation" model="mail.template">
</template>
<template
id="template_reservation_confirmed"
name="Property Reservation Confirmed"
>
<t t-call="web.layout">
<t t-set="head">
<!-- TODO: ensure bootstrap in shipped within the email -->
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous"
/>
</t>
<t t-set="body_classname" t-value="'container'" />
<div class="container">
<t t-call="pms.template_header" />
<t t-call="pms.template_reservation" />
<t t-call="pms.template_footer" />
</div>
</t>
</template>
<!-- notify customer that reservation has been confirmed -->
<record id="email_template_reservation" model="mail.template">
<field name="name">Property: Reservation Confirmed</field>
<field name="model_id" ref="pms.model_pms_folio"/>
<field name="email_from">${('%s &lt;%s&gt;' % (object.pms_property_id.partner_id.name, object.pms_property_id.partner_id.email) or '')|safe}</field>
<field name="model_id" ref="pms.model_pms_folio" />
<field
name="email_from"
>${('%s &lt;%s&gt;' % (object.pms_property_id.partner_id.name, object.pms_property_id.partner_id.email) or '')|safe}</field>
<field name="email_to">${(object.email or '')|safe}</field>
<field name="partner_to">${(object.partner_id.id or '')}</field>
<field name="lang">${object.partner_id.lang}</field>
<field name="subject">Your reservation ${object.name} has been confirmed by the property staff</field>
<field name="auto_delete" eval="True"/>
<field
name="subject"
>Your reservation ${object.name} has been confirmed by the property staff</field>
<field name="auto_delete" eval="True" />
<field name="body_type">qweb</field>
<field name="body_view_id" ref="pms.template_reservation_confirmed"/>
</record>
<field name="body_view_id" ref="pms.template_reservation_confirmed" />
</record>
</data>
</odoo>

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
@@ -20,46 +19,50 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import logging
from datetime import timedelta
from odoo import api, fields
from odoo.tests import common
from odoo.tools import (
DEFAULT_SERVER_DATE_FORMAT,
DEFAULT_SERVER_DATETIME_FORMAT)
import logging
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
_logger = logging.getLogger(__name__)
class TestHotel(common.SavepointCase):
@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,
})
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):
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,
'room_type_id': room.price_room_type.id,
'product_id': room.product_id.id,
})
self.assertTrue(
reservation,
"Hotel Calendar can't create a new reservation!")
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,
"room_type_id": room.price_room_type.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)
@@ -79,27 +82,26 @@ class TestHotel(common.SavepointCase):
cls._init_mock_hotel()
# Create Tests Records
cls.main_hotel_property = cls.env.ref('hotel.main_hotel_property')
cls.demo_hotel_property = cls.env.ref('hotel.demo_hotel_property')
cls.main_hotel_property = cls.env.ref("hotel.main_hotel_property")
cls.demo_hotel_property = cls.env.ref("hotel.demo_hotel_property")
cls.room_type_0 = cls.env.ref('hotel.hotel_room_type_0')
cls.room_type_1 = cls.env.ref('hotel.hotel_room_type_1')
cls.room_type_2 = cls.env.ref('hotel.hotel_room_type_2')
cls.room_type_3 = cls.env.ref('hotel.hotel_room_type_3')
cls.room_type_0 = cls.env.ref("hotel.hotel_room_type_0")
cls.room_type_1 = cls.env.ref("hotel.hotel_room_type_1")
cls.room_type_2 = cls.env.ref("hotel.hotel_room_type_2")
cls.room_type_3 = cls.env.ref("hotel.hotel_room_type_3")
cls.demo_room_type_0 = cls.env.ref('hotel.demo_hotel_room_type_0')
cls.demo_room_type_1 = cls.env.ref('hotel.demo_hotel_room_type_1')
cls.demo_room_type_0 = cls.env.ref("hotel.demo_hotel_room_type_0")
cls.demo_room_type_1 = cls.env.ref("hotel.demo_hotel_room_type_1")
cls.room_0 = cls.env.ref('hotel.hotel_room_0')
cls.room_1 = cls.env.ref('hotel.hotel_room_1')
cls.room_2 = cls.env.ref('hotel.hotel_room_2')
cls.room_3 = cls.env.ref('hotel.hotel_room_3')
cls.room_4 = cls.env.ref('hotel.hotel_room_4')
cls.room_5 = cls.env.ref('hotel.hotel_room_5')
cls.room_6 = cls.env.ref('hotel.hotel_room_6')
cls.room_0 = cls.env.ref("hotel.hotel_room_0")
cls.room_1 = cls.env.ref("hotel.hotel_room_1")
cls.room_2 = cls.env.ref("hotel.hotel_room_2")
cls.room_3 = cls.env.ref("hotel.hotel_room_3")
cls.room_4 = cls.env.ref("hotel.hotel_room_4")
cls.room_5 = cls.env.ref("hotel.hotel_room_5")
cls.room_6 = cls.env.ref("hotel.hotel_room_6")
cls.list0 = cls.env.ref('product.list0')
cls.list1 = cls.env['product.pricelist'].create({
'name': 'Test Pricelist',
'pricelist_type': ''
})
cls.list0 = cls.env.ref("product.list0")
cls.list1 = cls.env["product.pricelist"].create(
{"name": "Test Pricelist", "pricelist_type": ""}
)

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
@@ -21,12 +20,13 @@
#
##############################################################################
from datetime import timedelta
from .common import TestHotel
from odoo.addons.hotel import date_utils
from .common import TestHotel
class TestHotelReservations(TestHotel):
def test_cancel_folio(self):
now_utc_dt = date_utils.now()
@@ -39,17 +39,18 @@ class TestHotelReservations(TestHotel):
org_reserv_start_utc_dt,
org_reserv_end_utc_dt,
self.hotel_room_double_200,
"Reservation Test #1")
"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.reservation_ids), 2, 'Invalid room lines count')
"Reservation Test #2",
)
self.assertEqual(len(folio.reservation_ids), 2, "Invalid room lines count")
folio.action_cancel()
self.assertEqual(folio.state, 'cancel', 'Invalid folio state')
self.assertEqual(folio.state, "cancel", "Invalid folio state")
for rline in folio.reservation_ids:
self.assertEqual(rline.state, 'cancelled',
'Invalid reservation state')
self.assertEqual(rline.state, "cancelled", "Invalid reservation state")

View File

@@ -1,7 +1,8 @@
from .common import TestHotel
from odoo import fields
from odoo.exceptions import ValidationError
from .common import TestHotel
class TestHotelProperty(TestHotel):

View File

@@ -19,36 +19,36 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from .common import TestHotel
from odoo.exceptions import ValidationError
from .common import TestHotel
class TestHotelRoom(TestHotel):
def test_rooms_by_hotel(self):
# A room cannot be created in a room type of another hotel
with self.assertRaises(ValidationError):
record = self.env['hotel.room'].sudo().create({
'name': 'Test Room',
'hotel_id': self.demo_hotel_property.id,
'room_type_id': self.room_type_0.id,
})
record = (
self.env["hotel.room"]
.sudo()
.create(
{
"name": "Test Room",
"hotel_id": self.demo_hotel_property.id,
"room_type_id": self.room_type_0.id,
}
)
)
# A room cannot be changed to another hotel
with self.assertRaises(ValidationError):
self.room_0.sudo().write({
'hotel_id': self.demo_room_type_0.hotel_id.id
})
self.room_0.sudo().write({"hotel_id": self.demo_room_type_0.hotel_id.id})
def test_rooms_by_room_type(self):
# A room cannot be changed to a room type of another hotel
with self.assertRaises(ValidationError):
self.room_0.sudo().write({
'room_type_id': self.demo_room_type_1.id
})
self.room_0.sudo().write({"room_type_id": self.demo_room_type_1.id})
def test_check_capacity(self):
# The capacity of the room must be greater than 0
with self.assertRaises(ValidationError):
self.room_0.sudo().write({
'capacity': 0
})
self.room_0.sudo().write({"capacity": 0})

View File

@@ -19,10 +19,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from .common import TestHotel
from psycopg2 import IntegrityError
from odoo.tools import mute_logger
from .common import TestHotel
class TestHotelRoomType(TestHotel):
@@ -30,15 +32,12 @@ class TestHotelRoomType(TestHotel):
# code type must be unique by hotel
def test_code_type_unique_by_hotel(self):
with self.assertRaises(IntegrityError), mute_logger('odoo.sql_db'):
self.room_type_0.sudo().write({
'code_type': self.room_type_1.code_type
})
with self.assertRaises(IntegrityError), mute_logger("odoo.sql_db"):
self.room_type_0.sudo().write({"code_type": self.room_type_1.code_type})
# code type can be used in other hotel
def test_code_type_shared_by_hotel(self):
test_result = self.demo_room_type_0.sudo().write({
'code_type': self.room_type_0.code_type
})
test_result = self.demo_room_type_0.sudo().write(
{"code_type": self.room_type_0.code_type}
)
self.assertEqual(test_result, True)

View File

@@ -1,11 +1,10 @@
# -*- coding: utf-8 -*-
from .common import TestHotel
class TestInheritedIrHttp(TestHotel):
def test_user_hotel_company(self):
admin_user = self.env.ref('base.user_root')
self.assertTrue(admin_user.hotel_id.company_id in admin_user.company_ids,
"Wrong hotel and company access settings for %s" % admin_user.name)
admin_user = self.env.ref("base.user_root")
self.assertTrue(
admin_user.hotel_id.company_id in admin_user.company_ids,
"Wrong hotel and company access settings for %s" % admin_user.name,
)

View File

@@ -1,7 +1,8 @@
from .common import TestHotel
from odoo import fields
from odoo.exceptions import ValidationError
from .common import TestHotel
class TestInheritedProductPricelist(TestHotel):
@@ -17,11 +18,13 @@ class TestInheritedProductPricelist(TestHotel):
self.list0.hotel_ids = False
# create a valid record using a daily pricelist
test_result = self.env['product.pricelist'].create({
'name': 'Test Daily Pricelist',
'hotel_ids': [(4, self.demo_hotel_property.id)]
})
self.assertEqual(test_result.pricelist_type, 'daily')
test_result = self.env["product.pricelist"].create(
{
"name": "Test Daily Pricelist",
"hotel_ids": [(4, self.demo_hotel_property.id)],
}
)
self.assertEqual(test_result.pricelist_type, "daily")
self.assertEqual(test_result.hotel_ids, self.demo_hotel_property)
def test_pricelist_by_hotel(self):

View File

@@ -1,7 +1,8 @@
from .common import TestHotel
from odoo import fields
from odoo.exceptions import ValidationError
from .common import TestHotel
class TestMassiveChanges(TestHotel):
@@ -10,59 +11,51 @@ class TestMassiveChanges(TestHotel):
# base massive change record
def base_massive_change_vals(self, hotel_id=None):
return {
'hotel_id': hotel_id and hotel_id.id or self.main_hotel_property.id,
'date_start': fields.Date.today(),
'date_end': fields.Date.today(),
"hotel_id": hotel_id and hotel_id.id or self.main_hotel_property.id,
"date_start": fields.Date.today(),
"date_end": fields.Date.today(),
}
def pricelist_massive_change_vals(self, pricelist_id=None):
return {
'pricelist_id': pricelist_id and pricelist_id.id or self.list0.id,
'price': 50.0,
"pricelist_id": pricelist_id and pricelist_id.id or self.list0.id,
"price": 50.0,
}
def test_daily_pricelist(self):
# Only daily pricelist can be manage by a massive change
self.list0.pricelist_type = ''
self.list0.pricelist_type = ""
with self.assertRaises(ValidationError):
vals = self.base_massive_change_vals()
vals.update(
self.pricelist_massive_change_vals()
)
self.env['hotel.wizard.massive.changes'].create(vals)
vals.update(self.pricelist_massive_change_vals())
self.env["hotel.wizard.massive.changes"].create(vals)
# create a valid record using a daily pricelist
self.list0.pricelist_type = 'daily'
test_result = self.env['hotel.wizard.massive.changes'].create(vals)
self.list0.pricelist_type = "daily"
test_result = self.env["hotel.wizard.massive.changes"].create(vals)
self.assertEqual(test_result.pricelist_id, self.list0)
def test_pricelist_by_hotel(self):
# Ensure the pricelist plan belongs to the current hotel #1
with self.assertRaises(ValidationError):
vals = self.base_massive_change_vals(self.demo_hotel_property)
vals.update(
self.pricelist_massive_change_vals()
)
self.env['hotel.wizard.massive.changes'].create(vals)
vals.update(self.pricelist_massive_change_vals())
self.env["hotel.wizard.massive.changes"].create(vals)
# Ensure the pricelist plan belongs to the current hotel #2
with self.assertRaises(ValidationError):
vals = self.base_massive_change_vals()
vals.update(
self.pricelist_massive_change_vals(self.list1)
)
vals.update(self.pricelist_massive_change_vals(self.list1))
self.list1.hotel_ids = self.demo_hotel_property
self.list1.pricelist_type = 'daily'
self.env['hotel.wizard.massive.changes'].create(vals)
self.list1.pricelist_type = "daily"
self.env["hotel.wizard.massive.changes"].create(vals)
# create a valid record using the current hotel
vals = self.base_massive_change_vals()
vals.update(
self.pricelist_massive_change_vals(self.list1)
)
vals.update(self.pricelist_massive_change_vals(self.list1))
self.list1.hotel_ids = self.main_hotel_property
self.list1.pricelist_type = 'daily'
test_result = self.env['hotel.wizard.massive.changes'].create(vals)
self.list1.pricelist_type = "daily"
test_result = self.env["hotel.wizard.massive.changes"].create(vals)
self.assertEqual(test_result.pricelist_id.hotel_ids, self.main_hotel_property)
def test_do_massive_change(self):

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
@@ -21,19 +20,23 @@
#
##############################################################################
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
from datetime import timedelta
import pytz
from openerp.exceptions import ValidationError
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
from odoo import fields
from odoo.addons.hotel import date_utils
from .common import TestHotel
_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)
@@ -45,25 +48,32 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_double_200,
"Reservation Test #1")
"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")
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")
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()
@@ -76,7 +86,8 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_double_200,
"Reservation Test #1")
"Reservation Test #1",
)
reserv_start_utc_dt = reserv_end_utc_dt
reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3)
@@ -87,7 +98,8 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_double_200,
"Reservation Test #2")
"Reservation Test #2",
)
reserv_end_utc_dt = now_utc_dt + timedelta(days=3)
reserv_start_utc_dt = reserv_end_utc_dt - timedelta(days=1)
@@ -98,7 +110,8 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_double_200,
"Reservation Test #3")
"Reservation Test #3",
)
reserv_start_utc_dt = now_utc_dt + timedelta(days=3)
reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3)
@@ -109,7 +122,8 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_simple_100,
"Reservation Test #4")
"Reservation Test #4",
)
def test_create_invalid_reservations(self):
now_utc_dt = date_utils.now()
@@ -123,7 +137,8 @@ class TestHotelReservations(TestHotel):
org_reserv_start_utc_dt,
org_reserv_end_utc_dt,
self.hotel_room_double_200,
"Original Reservation Test #1")
"Original Reservation Test #1",
)
# Same Dates
reserv_start_utc_dt = now_utc_dt + timedelta(days=3)
@@ -136,7 +151,8 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_double_200,
"Invalid Reservation Test #1")
"Invalid Reservation Test #1",
)
# Inside Org Reservation (Start Same Date)
reserv_start_utc_dt = now_utc_dt + timedelta(days=3)
@@ -149,7 +165,8 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_double_200,
"Invalid Reservation Test #2")
"Invalid Reservation Test #2",
)
# Inside Org Reservation (Start after)
reserv_start_utc_dt = now_utc_dt + timedelta(days=4)
@@ -162,7 +179,8 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_double_200,
"Invalid Reservation Test #3")
"Invalid Reservation Test #3",
)
# Intersect Org Reservation (Start before)
reserv_start_utc_dt = now_utc_dt + timedelta(days=2)
@@ -175,7 +193,8 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_double_200,
"Invalid Reservation Test #4")
"Invalid Reservation Test #4",
)
# Intersect Org Reservation (End Same)
reserv_start_utc_dt = org_reserv_end_utc_dt - timedelta(days=2)
@@ -188,7 +207,8 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_double_200,
"Invalid Reservation Test #5")
"Invalid Reservation Test #5",
)
# Intersect Org Reservation (End after)
reserv_start_utc_dt = org_reserv_end_utc_dt - timedelta(days=2)
@@ -201,7 +221,8 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_double_200,
"Invalid Reservation Test #6")
"Invalid Reservation Test #6",
)
# Overlays Org Reservation
reserv_start_utc_dt = org_reserv_start_utc_dt - timedelta(days=2)
@@ -214,7 +235,8 @@ class TestHotelReservations(TestHotel):
reserv_start_utc_dt,
reserv_end_utc_dt,
self.hotel_room_double_200,
"Invalid Reservation Test #7")
"Invalid Reservation Test #7",
)
# Checkin > Checkout
with self.assertRaises(ValidationError):
@@ -225,14 +247,17 @@ class TestHotelReservations(TestHotel):
org_reserv_end_utc_dt,
org_reserv_start_utc_dt,
self.hotel_room_simple_100,
"Invalid Reservation Test #8")
"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
room_type_prices = self.prices_tmp[self.hotel_room_double_200.price_room_type.id]
room_type_prices = self.prices_tmp[
self.hotel_room_double_200.price_room_type.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)
@@ -242,19 +267,28 @@ class TestHotelReservations(TestHotel):
org_reserv_start_utc_dt,
org_reserv_end_utc_dt,
self.hotel_room_double_200,
"Original Reservation Test #1")
"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, room_type_prices[r_k+1])
self.assertEqual(r_v.price, room_type_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})]
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),
})
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)

View File

@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Backend stuff -->
<template id="assets_backend" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/pms/static/src/js/views/list/list_controller.js"></script>
<script
type="text/javascript"
src="/pms/static/src/js/views/list/list_controller.js"
/>
</xpath>
</template>
</odoo>

View File

@@ -1,22 +1,34 @@
<?xml version="1.0"?>
<?xml version="1.0" ?>
<odoo>
<record id="move_form" model="ir.ui.view">
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='invoice_date']" position="after">
<field name="folio_ids" widget="many2many_tags"/>
<field name="from_folio" invisible="1" />
<field name="pms_property_id" invisible="1"/>
<field name="folio_ids" widget="many2many_tags" />
<field name="from_folio" invisible="1" />
<field name="pms_property_id" invisible="1" />
</xpath>
<xpath expr="//button[@name='action_invoice_register_payment']" position="attributes">
<attribute name="attrs">{'invisible': ['|',('from_folio','=',True)]}</attribute>
<xpath
expr="//button[@name='action_invoice_register_payment']"
position="attributes"
>
<attribute
name="attrs"
>{'invisible': ['|',('from_folio','=',True)]}</attribute>
</xpath>
<xpath expr="//field[@name='invoice_outstanding_credits_debits_widget']" position="before">
<field name="outstanding_folios_debits_widget" colspan="2" nolabel="1" widget="payment" attrs="{'invisible': [('state', 'not in', 'open')]}"/>
<xpath
expr="//field[@name='invoice_outstanding_credits_debits_widget']"
position="before"
>
<field
name="outstanding_folios_debits_widget"
colspan="2"
nolabel="1"
widget="payment"
attrs="{'invisible': [('state', 'not in', 'open')]}"
/>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,19 +1,17 @@
<?xml version="1.0"?>
<?xml version="1.0" ?>
<odoo>
<record id="account_payment_view_form" model="ir.ui.view">
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='communication']" position="after">
<field name="folio_id"/>
<field name="save_amount" invisible="1"/>
<field name="save_journal_id" invisible="1"/>
<field name="save_date" invisible="1"/>
</xpath>
</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='communication']" position="after">
<field name="folio_id" />
<field name="save_amount" invisible="1" />
<field name="save_journal_id" invisible="1" />
<field name="save_date" invisible="1" />
</xpath>
</field>
</record>
<record id="account_payment_view_form_folio" model="ir.ui.view">
<field name="name">account.payment.folio.form</field>
<field name="model">account.payment</field>
@@ -21,37 +19,92 @@
<field name="arch" type="xml">
<form string="Register Payment" version="7">
<header>
<button name="action_draft" class="oe_highlight" states="cancelled" string="Set To Draft" type="object"/>
<button string="Validate" name="post" type="object" class="btn-primary"
attrs="{'invisible': [('state','!=','draft')]}"/>
<button string="Modify" name="modify" type="object" class="oe_edit_only btn-primary"
attrs="{'invisible': [('state','=','draft')]}"/>
<button string="Return" name="return_payment_folio" type="object" class="oe_edit_only btn-primary"
attrs="{'invisible': [('state','=','draft')]}"/>
<button string="Delete" name="delete" type="object" class="oe_read_only btn-primary"
attrs="{'invisible': [('state','=','draft')]}"/>
<button string="Cancel" name="cancel" class="oe_read_only btn-default" special="cancel"/>
<field name="state" widget="statusbar" statusbar_visible="draft,posted,reconciled,cancelled"/>
<button
name="action_draft"
class="oe_highlight"
states="cancelled"
string="Set To Draft"
type="object"
/>
<button
string="Validate"
name="post"
type="object"
class="btn-primary"
attrs="{'invisible': [('state','!=','draft')]}"
/>
<button
string="Modify"
name="modify"
type="object"
class="oe_edit_only btn-primary"
attrs="{'invisible': [('state','=','draft')]}"
/>
<button
string="Return"
name="return_payment_folio"
type="object"
class="oe_edit_only btn-primary"
attrs="{'invisible': [('state','=','draft')]}"
/>
<button
string="Delete"
name="delete"
type="object"
class="oe_read_only btn-primary"
attrs="{'invisible': [('state','=','draft')]}"
/>
<button
string="Cancel"
name="cancel"
class="oe_read_only btn-default"
special="cancel"
/>
<field
name="state"
widget="statusbar"
statusbar_visible="draft,posted,reconciled,cancelled"
/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button" name="button_journal_entries"
string="Journal Items" type="object"
groups="account.group_account_user"
attrs="{'invisible':[('move_line_ids','=',[])]}" icon="fa-bars"/>
<field name="move_line_ids" invisible="1"/>
<button class="oe_stat_button" name="button_invoices"
string="Invoices" type="object"
attrs="{'invisible':[('has_invoices','=',False)]}" icon="fa-bars"/>
<button class="oe_stat_button" name="open_payment_matching_screen"
string="Payment Matching" type="object"
attrs="{'invisible':[('move_reconciled','=',True)]}" icon="fa-university"/>
<field name="has_invoices" invisible="1"/>
<field name="move_reconciled" invisible="1"/>
<button
class="oe_stat_button"
name="button_journal_entries"
string="Journal Items"
type="object"
groups="account.group_account_user"
attrs="{'invisible':[('move_line_ids','=',[])]}"
icon="fa-bars"
/>
<field name="move_line_ids" invisible="1" />
<button
class="oe_stat_button"
name="button_invoices"
string="Invoices"
type="object"
attrs="{'invisible':[('has_invoices','=',False)]}"
icon="fa-bars"
/>
<button
class="oe_stat_button"
name="open_payment_matching_screen"
string="Payment Matching"
type="object"
attrs="{'invisible':[('move_reconciled','=',True)]}"
icon="fa-university"
/>
<field name="has_invoices" invisible="1" />
<field name="move_reconciled" invisible="1" />
</div>
<field name="id" invisible="1"/>
<div class="oe_title" attrs="{'invisible': [('state', '=', 'draft')]}">
<h1><field name="name"/></h1>
<field name="id" invisible="1" />
<div
class="oe_title"
attrs="{'invisible': [('state', '=', 'draft')]}"
>
<h1>
<field name="name" />
</h1>
</div>
<group>
<group>
@@ -60,8 +113,14 @@
<field name="save_amount" invisible="1" />
<field name="save_date" invisible="1" />
<field name="save_journal_id" invisible="1" />
<field name="partner_type" widget="selection" invisible="1"/>
<field name="partner_id" attrs="{
<field
name="partner_type"
widget="selection"
invisible="1"
/>
<field
name="partner_id"
attrs="{
'required': [('state', '=', 'draft'), ('payment_type', 'in', ('inbound', 'outbound'))],
'invisible': [('payment_type', 'not in', ('inbound', 'outbound'))]
}"
@@ -69,32 +128,43 @@
'default_is_company': True,
'default_supplier': payment_type == 'outbound',
'default_customer': payment_type == 'inbound'
}"/>
<label for="amount"/>
}"
/>
<label for="amount" />
<div name="amount_div" class="o_row">
<field name="amount" />
<field name="currency_id"
options="{'no_create': True, 'no_open': True}"
groups="base.group_multi_currency"
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field
name="currency_id"
options="{'no_create': True, 'no_open': True}"
groups="base.group_multi_currency"
attrs="{'readonly': [('state', '!=', 'draft')]}"
/>
</div>
<field name="journal_id" widget="selection" />
<field name="destination_journal_id"
widget="selection"
attrs="{
<field
name="destination_journal_id"
widget="selection"
attrs="{
'required': [('payment_type', '=', 'transfer')],
'invisible': [('payment_type', '!=', 'transfer')],
'readonly': [('state', '!=', 'draft')]}"/>
<field name="hide_payment_method" invisible="1"/>
<field name="payment_method_id" string=" " widget="radio"
attrs="{'invisible': [('hide_payment_method', '=', True)]}"/>
<field name="payment_method_code" invisible="1"/>
'readonly': [('state', '!=', 'draft')]}"
/>
<field name="hide_payment_method" invisible="1" />
<field
name="payment_method_id"
string=" "
widget="radio"
attrs="{'invisible': [('hide_payment_method', '=', True)]}"
/>
<field name="payment_method_code" invisible="1" />
</group>
<group>
<field name="payment_date" />
<field name="communication"
attrs="{'invisible': [('state', '!=', 'draft'), ('communication', '=', False)]}"/>
<field name="folio_id" readonly="1" force_save="1"/>
<field
name="communication"
attrs="{'invisible': [('state', '!=', 'draft'), ('communication', '=', False)]}"
/>
<field name="folio_id" readonly="1" force_save="1" />
</group>
</group>
</sheet>
@@ -102,19 +172,26 @@
</footer>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
<field name="message_ids" widget="mail_thread"/>
</div>
<field
name="message_follower_ids"
widget="mail_followers"
groups="base.group_user"
/>
<field name="message_ids" widget="mail_thread" />
</div>
</form>
</field>
</record>
<record id="account_payment_view_tree_folio" model="ir.ui.view">
<field name="name">account.payment.folio.tree</field>
<field name="model">account.payment</field>
<field name="priority">20</field>
<field name="arch" type="xml">
<tree decoration-info="state == 'draft'" decoration-muted="state in ['reconciled', 'cancelled']" edit="false">
<tree
decoration-info="state == 'draft'"
decoration-muted="state in ['reconciled', 'cancelled']"
edit="false"
>
<field name="payment_date" />
<field name="name" />
<field name="journal_id" />
@@ -125,11 +202,13 @@
<field name="company_id" groups="base.group_multi_company" />
<field name="currency_id" invisible="1" />
<field name="partner_type" invisible="1" />
<button type="object" class="oe_stat_button"
icon="fa fa-2x fa-pencil"
name="modify_payment" />
<button
type="object"
class="oe_stat_button"
icon="fa fa-2x fa-pencil"
name="modify_payment"
/>
</tree>
</field>
</record>
</odoo>

View File

@@ -1,23 +1,25 @@
<?xml version="1.0"?>
<?xml version="1.0" ?>
<odoo>
<record id="product_pricelist_view_form" model="ir.ui.view">
<field name="model">product.pricelist</field>
<field name="inherit_id" ref="product.product_pricelist_view" />
<field name="arch" type="xml">
<xpath expr="//field[@name='country_group_ids']" position="before">
<field name="pms_property_ids" widget="many2many_tags"
options="{'no_create': True,'no_open': True}"/>
<field
name="pms_property_ids"
widget="many2many_tags"
options="{'no_create': True,'no_open': True}"
/>
<field name="pricelist_type" />
<field name="cancelation_rule_id" />
</xpath>
</field>
</record>
<menuitem name="Pricelist" id="pricelist_menu"
action="product.product_pricelist_action2" sequence="22"
parent="pms.configuration_others" />
<menuitem
name="Pricelist"
id="pricelist_menu"
action="product.product_pricelist_action2"
sequence="22"
parent="pms.configuration_others"
/>
</odoo>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="product_template_view_form" model="ir.ui.view">
<field name="name">view.product.template.form.inherited</field>
<field name="model">product.template</field>
@@ -10,8 +9,11 @@
<page string="Service">
<group colspan="4">
<group>
<field name="pms_property_ids" widget="many2many_tags"
options="{'no_create': True,'no_open': True}"/>
<field
name="pms_property_ids"
widget="many2many_tags"
options="{'no_create': True,'no_open': True}"
/>
<field name="is_extra_bed" />
<field name="daily_limit" />
<field name="show_in_calendar" />
@@ -19,13 +21,15 @@
<group>
<field name="per_day" />
<field name="per_person" />
<field name="consumed_on" widget="radio"
attrs="{'invisible': [('per_day','!=',True)]}"/>
<field
name="consumed_on"
widget="radio"
attrs="{'invisible': [('per_day','!=',True)]}"
/>
</group>
</group>
</page>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,47 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="pms_partner_reservations" model="ir.actions.act_window">
<field name="name">Reservations</field>
<field name="res_model">pms.reservation</field>
<field name="res_model">pms.reservation</field>
<field name="domain">[('partner_id', '=',active_id)]</field>
</record>
<record id="pms_partner_folios" model="ir.actions.act_window">
<field name="name">Folios</field>
<field name="res_model">pms.folio</field>
<field name="res_model">pms.folio</field>
<field name="domain">[('partner_id', '=',active_id)]</field>
</record>
<record id="res_partner_view_form" model="ir.ui.view">
<field name="name">res.partner.view.form </field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="arch" type="xml">
<xpath expr='//div[@name="button_box"]' position='inside'>
<button class="oe_stat_button" type="action" icon="fa-bed"
<button
class="oe_stat_button"
type="action"
icon="fa-bed"
name="%(pms.pms_partner_reservations)d"
help="Reservations related with this contact">
<field string="Reservations" name="reservations_count" widget="statinfo"/>
help="Reservations related with this contact"
>
<field
string="Reservations"
name="reservations_count"
widget="statinfo"
/>
</button>
<button class="oe_stat_button" type="action" icon="fa-file"
<button
class="oe_stat_button"
type="action"
icon="fa-file"
name="%(pms.pms_partner_folios)d"
help="Folios related with this contact">
<field string="Folios" name="folios_count" widget="statinfo"/>
help="Folios related with this contact"
>
<field string="Folios" name="folios_count" widget="statinfo" />
</button>
</xpath>
<xpath expr="//field[@name='user_id']" position="after">
<field name="company_type" invisible="1" />
<field name="is_tour_operator" attrs="{'invisible': [('company_type','!=','company')]}"/>
<field
name="is_tour_operator"
attrs="{'invisible': [('company_type','!=','company')]}"
/>
</xpath>
</field>
</record>
<menuitem name="Customers" id="menu_pms_customer"
action="base.action_partner_form" sequence="500"
parent="menu_all_folio"/>
<menuitem
name="Customers"
id="menu_pms_customer"
action="base.action_partner_form"
sequence="500"
parent="menu_all_folio"
/>
</odoo>

View File

@@ -1,17 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="res_users_view_form" model="ir.ui.view">
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form" />
<field name="arch" type="xml">
<xpath expr="//page[@name='access_rights']/group" position="after">
<group string="Multi Properties">
<field string="Allowed Properties" name="pms_property_ids" widget="many2many_tags"/>
<field string="Current Property" name="pms_property_id" context="{'user_preference': 0}"/>
<field
string="Allowed Properties"
name="pms_property_ids"
widget="many2many_tags"
/>
<field
string="Current Property"
name="pms_property_id"
context="{'user_preference': 0}"
/>
</group>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,9 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<template id="assets_backend" name="pms assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/pms/static/src/js/widgets/switch_pms_menu.js"></script>
<script
type="text/javascript"
src="/pms/static/src/js/widgets/switch_pms_menu.js"
/>
</xpath>
</template>
</data>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--==== Amenities Type ==== -->
<!-- Form view of pms room amenities type -->
<record model="ir.ui.view" id="pms_room_amenity_type_view_form">
@@ -11,8 +10,11 @@
<sheet>
<group>
<field name="name" string="Amenity Type" />
<field name="pms_property_ids" widget="many2many_tags"
options="{'no_create': True,'no_open': True}"/>
<field
name="pms_property_ids"
widget="many2many_tags"
options="{'no_create': True,'no_open': True}"
/>
<!-- <field name="parent_id" domain="[('isamenitytype','=',True)]" /> -->
<!-- <field name="isamenitytype" invisible="1" /> -->
</group>
@@ -20,7 +22,6 @@
</form>
</field>
</record>
<!-- Tree view of pms room amenities type -->
<record model="ir.ui.view" id="pms_room_amenity_type_view_list">
<field name="name">pms.room_amenity_type_list</field>
@@ -31,16 +32,17 @@
</tree>
</field>
</record>
<!-- Action for pms room amenities type -->
<record model="ir.actions.act_window" id="action_pms_room_amenity_type_view_form">
<field name="name">Room amenity Type</field>
<field name="res_model">pms.amenity.type</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Amenity Types"
id="menu_action_pms_room_amenity_type_view_form" action="action_pms_room_amenity_type_view_form"
sequence="3" parent="pms.menu_amenity" />
<menuitem
name="Amenity Types"
id="menu_action_pms_room_amenity_type_view_form"
action="action_pms_room_amenity_type_view_form"
sequence="3"
parent="pms.menu_amenity"
/>
</odoo>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="pms_amenity_view_form" model="ir.ui.view">
<field name="name">pms.amenity.form</field>
<field name="model">pms.amenity</field>
@@ -17,9 +16,16 @@
<notebook>
<page string="Information">
<group colspan="4" col="4">
<field name="pms_property_ids" widget="many2many_tags"
options="{'no_create': True,'no_open': True}"/>
<field name="room_amenity_type_id" select="2" string="Amenity Type" />
<field
name="pms_property_ids"
widget="many2many_tags"
options="{'no_create': True,'no_open': True}"
/>
<field
name="room_amenity_type_id"
select="2"
string="Amenity Type"
/>
<!-- <field name="categ_id" select="1"
domain="[('isamenitytype','=',True)]" /> -->
</group>
@@ -61,7 +67,6 @@
</form>
</field>
</record>
<record model="ir.ui.view" id="pms_amenity_search">
<field name="name">pms.room_amenity_search</field>
<field name="model">pms.amenity</field>
@@ -79,7 +84,6 @@
</search>
</field>
</record>
<record model="ir.ui.view" id="pms_amenity_view_list">
<field name="name">pms.room_amenity_list</field>
<field name="model">pms.amenity</field>
@@ -91,23 +95,26 @@
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_pms_room_amenity_view_form">
<field name="name">Room Amenities</field>
<field name="res_model">pms.amenity</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="pms_amenity_view_list" />
</record>
<menuitem id="menu_amenity" name="Amenity"
parent="pms.pms_configuration_menu" sequence="2" />
<menuitem name="Amenities" id="menu_action_pms_room_amenity_view_form"
action="action_pms_room_amenity_view_form" sequence="2"
parent="pms.menu_amenity" />
<menuitem
id="menu_amenity"
name="Amenity"
parent="pms.pms_configuration_menu"
sequence="2"
/>
<menuitem
name="Amenities"
id="menu_action_pms_room_amenity_view_form"
action="action_pms_room_amenity_view_form"
sequence="2"
parent="pms.menu_amenity"
/>
<!-- Amenities Categories -->
<!-- <record model="ir.actions.act_window" id="pms_ty_category_action">
<field name="name">Amenities by Category</field>
<field name="type">ir.actions.act_window</field>
@@ -116,15 +123,12 @@
<field name="view_type">tree</field>
<field name="view_id" ref="product_category_tree_view" />
</record> -->
<!--record id="ir_amenities_category_open" ref="model_product_category">
<field eval="'tree_but_open'" name="key2"/>
<field eval="'product.category'" name="model"/>
<field name="name">Amenities</field>
<field eval="'ir.actions.act_window,%d'%action_room_cate" name="value"/>
</record-->
<!-- <menuitem name="Amenities by Type" id="menu_pms_ty_category_action"
action="pms_ty_category_action" sequence="4" parent="pms.menu_amenity" /> -->
</odoo>

View File

@@ -1,17 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="pms_board_service_room_type_form">
<field name="name">pms.board.service.room.type.form</field>
<field name="model">pms.board.service.room.type</field>
<field name="arch" type="xml">
<form string="Board Service Line">
<group>
<field name="amount"/>
<field name="amount" />
<field name="board_service_line_ids">
<tree editable="bottom">
<field name="pms_board_service_room_type_id" invisible="1"/>
<field name="product_id"/>
<field
name="pms_board_service_room_type_id"
invisible="1"
/>
<field name="product_id" />
<field name="amount" />
</tree>
</field>
@@ -19,11 +21,9 @@
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_pms_board_service_room_type_view">
<field name="name">Board Service</field>
<field name="res_model">pms.board.service.room.type</field>
<field name="view_mode">form</field>
</record>
</odoo>

View File

@@ -1,19 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="pms_board_service_form">
<field name="name">pms.board.service.form</field>
<field name="model">pms.board.service</field>
<field name="arch" type="xml">
<form string="Board Service Line">
<group>
<field name="name" />
<field name="pms_property_ids" widget="many2many_tags"
options="{'no_create': True,'no_open': True}"/>
<field name="amount"/>
<field name="name" />
<field
name="pms_property_ids"
widget="many2many_tags"
options="{'no_create': True,'no_open': True}"
/>
<field name="amount" />
<field name="board_service_line_ids">
<tree editable="bottom">
<field name="product_id"/>
<field name="product_id" />
<field name="amount" />
</tree>
</field>
@@ -21,7 +23,6 @@
</form>
</field>
</record>
<record model="ir.ui.view" id="pms_board_service_view_tree">
<field name="name">pms.board.service.tree</field>
<field name="model">pms.board.service</field>
@@ -32,15 +33,16 @@
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="open_pms_board_service_form_tree">
<field name="name">Board Services</field>
<field name="res_model">pms.board.service</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Board Services" id="menu_open_pms_board_service_form_tree"
action="open_pms_board_service_form_tree" sequence="25"
parent="pms.configuration_others" />
<menuitem
name="Board Services"
id="menu_open_pms_board_service_form_tree"
action="open_pms_board_service_form_tree"
sequence="25"
parent="pms.configuration_others"
/>
</odoo>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--==================================================== Cancelation Rules ==================================================== -->
<!-- Form view of cancelation rules -->
<record model="ir.ui.view" id="pms_cancelation_rule_form">
@@ -11,8 +10,11 @@
<sheet>
<h3>
<field name="name" />
<field name="pms_property_ids" widget="many2many_tags"
options="{'no_create': True,'no_open': True}"/>
<field
name="pms_property_ids"
widget="many2many_tags"
options="{'no_create': True,'no_open': True}"
/>
<separator />
<label for="name" string="Max. days InTime before Checkin" />
<field name="days_intime" />
@@ -21,19 +23,24 @@
<group string="Late">
<field name="penalty_late" />
<field name="apply_on_late" />
<field name="days_late" attrs="{'invisible': [('apply_on_late','not in',('days'))]}" />
<field
name="days_late"
attrs="{'invisible': [('apply_on_late','not in',('days'))]}"
/>
</group>
<group string="No Show">
<field name="penalty_noshow" />
<field name="apply_on_noshow" />
<field name="days_noshow" attrs="{'invisible': [('apply_on_noshow','not in',('days'))]}" />
<field
name="days_noshow"
attrs="{'invisible': [('apply_on_noshow','not in',('days'))]}"
/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<!-- Tree view of cancelation rules -->
<record model="ir.ui.view" id="pms_cancelation_rule_view_tree">
<field name="name">pms.cancelation.rule.tree</field>
@@ -49,16 +56,17 @@
</tree>
</field>
</record>
<!-- Action of pms cancelation rules -->
<record model="ir.actions.act_window" id="action_pms_cancelation_rule">
<field name="name">Cancelation Rules</field>
<field name="res_model">pms.cancelation.rule</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Cancelation Rules" id="menu_pms_cancelation_rule"
action="action_pms_cancelation_rule" sequence="25"
parent="pms.configuration_others" />
<menuitem
name="Cancelation Rules"
id="menu_pms_cancelation_rule"
action="action_pms_cancelation_rule"
sequence="25"
parent="pms.configuration_others"
/>
</odoo>

View File

@@ -1,19 +1,18 @@
<?xml version="1.0"?>
<?xml version="1.0" ?>
<odoo>
<act_window
id="action_checkin_partner"
name="Action checkin"
res_model="pms.checkin.partner"
view_mode="tree,form" />
view_mode="tree,form"
/>
<menuitem
id="menu_pms_checkin_partner"
name="Checkins"
parent="pms.pms_reports_menu"
sequence="25"
action="action_checkin_partner" />
action="action_checkin_partner"
/>
<record id="pms_checkin_partner_view_form" model="ir.ui.view">
<field name="name">Checkin Form</field>
<field name="model">pms.checkin.partner</field>
@@ -22,34 +21,41 @@
<sheet>
<group name="group_top">
<group name="group_left">
<field name="partner_id" required="True"
domain="[('is_company','=', False)]"/>
<field name="pms_property_id" invisible="1"/>
<field name="enter_date"/>
<field name="exit_date"/>
<field name="arrival_hour"/>
<field name="departure_hour"/>
<field
name="partner_id"
required="True"
domain="[('is_company','=', False)]"
/>
<field name="pms_property_id" invisible="1" />
<field name="enter_date" />
<field name="exit_date" />
<field name="arrival_hour" />
<field name="departure_hour" />
</group>
<group name="group_left">
<field name="reservation_id"/>
<field name="reservation_id" />
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="pms_checkin_partner_reservation_view_tree" model="ir.ui.view">
<field name="name">pms.checkin.partner.reservation.view.tree</field>
<field name="model">pms.checkin.partner</field>
<field name="priority">20</field>
<field name="arch" type="xml">
<tree editable="bottom" create="1"
decoration-danger="state == 'draft'"
decoration-info="state == 'done'"
decoration-muted="state == 'cancelled'"
decoration-success="state == 'booking'">
<button type="object" class="oe_read_only oe_stat_button"
<tree
editable="bottom"
create="1"
decoration-danger="state == 'draft'"
decoration-info="state == 'done'"
decoration-muted="state == 'cancelled'"
decoration-success="state == 'booking'"
>
<button
type="object"
class="oe_read_only oe_stat_button"
icon="fa fa-2x fa-check-circle"
name="action_on_board"
help="Get in"
@@ -58,44 +64,49 @@
<field name="auto_booking" invisible="1" />
<field name="partner_id" required="True" />
<field name="mobile" />
<field name="email"/>
<field name="enter_date"/>
<field name="exit_date"/>
<field name="reservation_id" invisible="1"/>
<field name="folio_id" force_save="1" invisible="1"/>
<field name="state" invisible="1"/>
<field name="email" />
<field name="enter_date" />
<field name="exit_date" />
<field name="reservation_id" invisible="1" />
<field name="folio_id" force_save="1" invisible="1" />
<field name="state" invisible="1" />
</tree>
</field>
</record>
<record id="pms_checkin_partner_view_tree" model="ir.ui.view">
<field name="name">pms.checkin.partner.view.tree</field>
<field name="model">pms.checkin.partner</field>
<field name="priority">10</field>
<field name="arch" type="xml">
<tree create="false"
decoration-danger="state == 'draft'"
decoration-muted="state == 'cancelled' or state =='done'"
decoration-success="state == 'booking'">
<button type="object" class="oe_stat_button"
<tree
create="false"
decoration-danger="state == 'draft'"
decoration-muted="state == 'cancelled' or state =='done'"
decoration-success="state == 'booking'"
>
<button
type="object"
class="oe_stat_button"
icon="fa fa-2x fa-check-circle"
name="action_on_board"
attrs="{'invisible':[('state','not in', ['draft'])]}"
help="Get in"
/>
<field name="partner_id" required="True"
domain="[('is_company','=', False)]"/>
<field name="mobile"/>
<field name="email"/>
<field name="enter_date"/>
<field name="exit_date"/>
<field name="reservation_id"/>
<field name="folio_id" force_save="1" invisible="1"/>
<field name="state"/>
<field
name="partner_id"
required="True"
domain="[('is_company','=', False)]"
/>
<field name="mobile" />
<field name="email" />
<field name="enter_date" />
<field name="exit_date" />
<field name="reservation_id" />
<field name="folio_id" force_save="1" invisible="1" />
<field name="state" />
</tree>
</field>
</record>
<record model="ir.ui.view" id="pms_checkin_partner_view_search">
<field name="name">pms.checkin.partner.search</field>
<field name="model">pms.checkin.partner</field>
@@ -103,52 +114,90 @@
<search string="Checkin Detail">
<field name="partner_id" />
<field name="reservation_id" />
<filter string="On Board" name="on_board"
domain="[('state','=','booking')]"
help="Current Booking" />
<filter string="To enter" name="to_enter"
domain="[('state', '=', 'draft')]"
/>
<filter string="Out" name="out"
domain="[('state', '=', 'done')]"
/>
<filter string="Checkins Tomorrow" name="enter_tomorrow"
domain="[('enter_date', '=', (context_today()+datetime.timedelta(days=1)).strftime('%Y-%m-%d')),
<filter
string="On Board"
name="on_board"
domain="[('state','=','booking')]"
help="Current Booking"
/>
<filter
string="To enter"
name="to_enter"
domain="[('state', '=', 'draft')]"
/>
<filter string="Out" name="out" domain="[('state', '=', 'done')]" />
<filter
string="Checkins Tomorrow"
name="enter_tomorrow"
domain="[('enter_date', '=', (context_today()+datetime.timedelta(days=1)).strftime('%Y-%m-%d')),
('state', '=', 'confirm')]"
help="Show all checkins for enter tomorrow"/>
<filter string="Checkins to 7 days" name="next_res_week"
domain="[('enter_date', '&lt;', (context_today()+datetime.timedelta(days=7)).strftime('%Y-%m-%d')),
help="Show all checkins for enter tomorrow"
/>
<filter
string="Checkins to 7 days"
name="next_res_week"
domain="[('enter_date', '&lt;', (context_today()+datetime.timedelta(days=7)).strftime('%Y-%m-%d')),
('state', '=', 'confirm')]"
help="Show all reservations for which date enter is before than 7 days"/>
<filter string="On Board Tomorrow" name="next_res_2week"
domain="[('enter_date', '&lt;', (context_today()+datetime.timedelta(days=14)).strftime('%Y-%m-%d')),
help="Show all reservations for which date enter is before than 7 days"
/>
<filter
string="On Board Tomorrow"
name="next_res_2week"
domain="[('enter_date', '&lt;', (context_today()+datetime.timedelta(days=14)).strftime('%Y-%m-%d')),
('state', 'in', ['confirm','booking'])]"
help="Show all checkins for Tomorrow"/>
help="Show all checkins for Tomorrow"
/>
<group expand="0" string="Group By">
<filter string="Create by Month" name="create_date_by_month"
context="{'group_by':'create_date', 'default_order': 'create_date asc'}"/>
<filter string="Create by Week" name="create_date_by_week"
context="{'group_by':'create_date:week', 'default_order': 'create_date'}"/>
<filter string="Create by Day" name="create_date_by_week"
context="{'group_by':'create_date:day', 'default_order': 'create_date'}"/>
<separator/>
<filter string="Checkin by Month" name="checkin_by_month"
context="{'group_by':'checkin', 'default_order': 'checkin asc'}"/>
<filter string="Checkin by Week" name="checkin_by_week"
context="{'group_by':'checkin:week', 'default_order': 'checkin'}"/>
<filter string="Checkin by Day" name="checkin_by_week"
context="{'group_by':'checkin:day', 'default_order': 'checkin'}"/>
<separator/>
<filter string="Checkout by Month" name="checkout_by_month"
context="{'group_by':'checkout', 'default_order': 'checkout asc'}"/>
<filter string="Checkout by Week" name="checkout_by_week"
context="{'group_by':'checkout:week', 'default_order': 'checkout'}"/>
<filter string="Checkout by Day" name="checkout_by_week"
context="{'group_by':'checkout:day', 'default_order': 'checkout'}"/>
<separator/>
<filter
string="Create by Month"
name="create_date_by_month"
context="{'group_by':'create_date', 'default_order': 'create_date asc'}"
/>
<filter
string="Create by Week"
name="create_date_by_week"
context="{'group_by':'create_date:week', 'default_order': 'create_date'}"
/>
<filter
string="Create by Day"
name="create_date_by_week"
context="{'group_by':'create_date:day', 'default_order': 'create_date'}"
/>
<separator />
<filter
string="Checkin by Month"
name="checkin_by_month"
context="{'group_by':'checkin', 'default_order': 'checkin asc'}"
/>
<filter
string="Checkin by Week"
name="checkin_by_week"
context="{'group_by':'checkin:week', 'default_order': 'checkin'}"
/>
<filter
string="Checkin by Day"
name="checkin_by_week"
context="{'group_by':'checkin:day', 'default_order': 'checkin'}"
/>
<separator />
<filter
string="Checkout by Month"
name="checkout_by_month"
context="{'group_by':'checkout', 'default_order': 'checkout asc'}"
/>
<filter
string="Checkout by Week"
name="checkout_by_week"
context="{'group_by':'checkout:week', 'default_order': 'checkout'}"
/>
<filter
string="Checkout by Day"
name="checkout_by_week"
context="{'group_by':'checkout:day', 'default_order': 'checkout'}"
/>
<separator />
</group>
</search>
</field>
</record>
</odoo>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="pms_floor_view_form">
<field name="name">pms.floor.form</field>
<field name="model">pms.floor</field>
@@ -10,14 +9,16 @@
<group>
<field name="name" colspan="1" />
<field name="sequence" select="1" />
<field name="pms_property_ids" widget="many2many_tags"
options="{'no_create': True,'no_open': True}"/>
<field
name="pms_property_ids"
widget="many2many_tags"
options="{'no_create': True,'no_open': True}"
/>
</group>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="pms_floor_view_tree">
<field name="name">pms.floor.tree</field>
<field name="model">pms.floor</field>
@@ -28,15 +29,16 @@
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="open_pms_floor_form_tree">
<field name="name">Floor Structure</field>
<field name="res_model">pms.floor</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Ubitacions" id="menu_open_pms_floor_form_tree"
action="open_pms_floor_form_tree" sequence="21"
parent="pms.configuration_others" />
<menuitem
name="Ubitacions"
id="menu_open_pms_floor_form_tree"
action="open_pms_floor_form_tree"
sequence="21"
parent="pms.configuration_others"
/>
</odoo>

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<act_window id="action_view_folio_advance_payment_inv"
<act_window
id="action_view_folio_advance_payment_inv"
name="Invoice Folio"
binding_model="pms.folio"
res_model="folio.advance.payment.inv"
target="new"
view_mode="form" />
view_mode="form"
/>
<record model="ir.ui.view" id="pms_folio_view_form">
<field name="name">pms.folio.form</field>
<field name="model">pms.folio</field>
@@ -17,124 +17,203 @@
<!-- <field name="has_confirmed_reservations_to_send" invisible="1" /> -->
<!-- <field name="has_cancelled_reservations_to_send" invisible="1" /> -->
<!-- <field name="has_checkout_to_send" invisible="1" /> -->
<button name="action_confirm" states="draft" string="Confirm Sale"
class="btn-primary" type="object" />
<button
name="action_confirm"
states="draft"
string="Confirm Sale"
class="btn-primary"
type="object"
/>
<!-- <button name="send_reservation_mail" type="object" string="Send Confirmation Email"
attrs="{'invisible': [('has_confirmed_reservations_to_send', '=', False)]}" class="oe_highlight"/> -->
<!-- <button name="send_cancel_mail" type="object" string="Send Cancel Email"
attrs="{'invisible': [('has_cancelled_reservations_to_send', '=', False)]}" class="oe_highlight"/> -->
<!-- <button name="send_exit_mail" type="object" string="Send Exit Email"
attrs="{'invisible': [('has_checkout_to_send', '=', False)]}" class="oe_highlight"/> -->
<button name="%(pms.action_view_folio_advance_payment_inv)d"
string="Create Invoice" type="action" class="btn-primary"
attrs="{'invisible': [('state', '!=', 'confirm')]}"/>
<button
name="%(pms.action_view_folio_advance_payment_inv)d"
string="Create Invoice"
type="action"
class="btn-primary"
attrs="{'invisible': [('state', '!=', 'confirm')]}"
/>
<!-- <button name="action_cancel_draft" states="cancel,sale" string="Set to Draft"
type="object" icon="fa-undo" class="oe_highlight" /> -->
<button name="action_cancel" string="Cancel Folio"
<button
name="action_cancel"
string="Cancel Folio"
attrs="{'invisible': [('state', 'not in', ('confirm','draft'))]}"
type="object" />
<button name="action_done" type="object" string="Set to Done"
help="If a Folio is done, you cannot modify it manually anymore. However, you will still be able to invoice. This is used to freeze the Folio." />
type="object"
/>
<button
name="action_done"
type="object"
string="Set to Done"
help="If a Folio is done, you cannot modify it manually anymore. However, you will still be able to invoice. This is used to freeze the Folio."
/>
<!-- <button name="print_quotation" string="Print" type="object" states="sent,sale"/> -->
<field name="state" select="2" widget="statusbar"
statusbar_visible="draft,sent,sale,done" />
<field
name="state"
select="2"
widget="statusbar"
statusbar_visible="draft,sent,sale,done"
/>
</header>
<sheet>
<div class=" oe_button_box">
<button type="object" class="oe_stat_button"
<button
type="object"
class="oe_stat_button"
id="payment_smart_button"
icon="fa-money"
name="action_pay"
attrs="{'invisible': ['|',('pending_amount','&lt;=',0)]}">
attrs="{'invisible': ['|',('pending_amount','&lt;=',0)]}"
>
<div class="o_form_field o_stat_info">
<span class="o_stat_value">
<field name="pending_amount" nolabel="1"
widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field
name="pending_amount"
nolabel="1"
widget="monetary"
options="{'currency_field': 'currency_id'}"
/>
</span>
<span class="o_stat_text">Pending Payment</span>
</div>
</button>
<button type="object" class="oe_stat_button" id="invoice_button"
icon="fa-pencil-square-o" name="open_invoices_folio"
<button
type="object"
class="oe_stat_button"
id="invoice_button"
icon="fa-pencil-square-o"
name="open_invoices_folio"
attrs="{'invisible': [('invoice_count', '=', 0)]}"
context="{'default_folio_id': active_id}">
context="{'default_folio_id': active_id}"
>
<div class="o_form_field o_stat_info">
<span class="o_stat_value">
<field name="invoice_count"/>
<field name="invoice_count" />
</span>
<span class="o_stat_text">Invoices</span>
</div>
</button>
</button>
</div>
<h2><field name="name"/></h2>
<h2>
<field name="name" />
</h2>
<h1>
<field name="partner_id" default_focus="1" placeholder="Guest" attrs="{'invisible':[('reservation_type','in',('out'))]}"/>
<field name="closure_reason_id" placeholder="Closure reason" default_focus="1" attrs="{'invisible':[('reservation_type','not in',('out'))]}"/>
<field
name="partner_id"
default_focus="1"
placeholder="Guest"
attrs="{'invisible':[('reservation_type','in',('out'))]}"
/>
<field
name="closure_reason_id"
placeholder="Closure reason"
default_focus="1"
attrs="{'invisible':[('reservation_type','not in',('out'))]}"
/>
</h1>
<group>
<group>
<field name="email" placeholder="email"/>
<field name="mobile" placeholder="mobile"/>
<field name="email" placeholder="email" />
<field name="mobile" placeholder="mobile" />
<field name="phone" />
<field name="segmentation_ids" widget="many2many_tags" placeholder="Segmentation..."
options="{'no_create': True,'no_open': True}" />
<field name="cancelled_reason" attrs="{'invisible':[('state','not in',('cancel'))]}"/>
<field
name="segmentation_ids"
widget="many2many_tags"
placeholder="Segmentation..."
options="{'no_create': True,'no_open': True}"
/>
<field
name="cancelled_reason"
attrs="{'invisible':[('state','not in',('cancel'))]}"
/>
</group>
<group>
<field name="pms_property_id" invisible="0"/>
<field name="pms_property_id" invisible="0" />
<field name="pricelist_id" />
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
<field name="reservation_type" attrs="{'readonly':[('state','not in',('draft'))]}"/>
<field name="channel_type" attrs="{'required':[('reservation_type','=','normal')]}"/>
<field name="tour_operator_id"
options="{'no_create': True,'no_open': True}" />
<field
name="company_id"
options="{'no_create': True}"
groups="base.group_multi_company"
/>
<field
name="reservation_type"
attrs="{'readonly':[('state','not in',('draft'))]}"
/>
<field
name="channel_type"
attrs="{'required':[('reservation_type','=','normal')]}"
/>
<field
name="tour_operator_id"
options="{'no_create': True,'no_open': True}"
/>
</group>
<group>
<field name="partner_internal_comment"/>
<field name="partner_internal_comment" />
</group>
<group>
<field name="internal_comment"/>
<field name="credit_card_details" attrs="{'invisible':[('pending_amount','&lt;=',0)]}"/>
<field name="internal_comment" />
<field
name="credit_card_details"
attrs="{'invisible':[('pending_amount','&lt;=',0)]}"
/>
</group>
<group colspan="2" class="oe_subtotal_footer oe_right">
<field name="amount_untaxed" sum="Untaxed amount" widget='monetary' />
<field
name="amount_untaxed"
sum="Untaxed amount"
widget='monetary'
/>
<field name="amount_tax" widget='monetary' />
<div class="oe_subtotal_footer_separator oe_inline">
<label for="amount_total" />
</div>
<field name="amount_total" nolabel="1" sum="Total amount"
widget='monetary' />
<field
name="amount_total"
nolabel="1"
sum="Total amount"
widget='monetary'
/>
</group>
<div class="oe_clear" />
<group>
<field name="note" />
</group>
</group>
</group>
<group invisible="1">
<field name="move_ids" invisible="1"/>
<field name="move_ids" invisible="1" />
<field name="invoice_status" invisible="1" />
<field name="currency_id" invisible="1"/>
<field name="currency_id" invisible="1" />
<field name="refund_amount" invisible="1" />
<field name="invoices_paid" invisible="1" />
</group>
<notebook colspan="4" col="1">
<page string="Reservation Rooms">
<field name="reservation_ids" colspan="4" string="Room Line"
nolabel="1" context="{'from_folio':True,'reservation_ids':reservation_ids,'folio_id': id,'tree_view_ref':'pms.pms_reservation_view_bottom_tree', 'form_view_ref':'pms.pms_reservation_view_form'}"/>
<field
name="reservation_ids"
colspan="4"
string="Room Line"
nolabel="1"
context="{'from_folio':True,'reservation_ids':reservation_ids,'folio_id': id,'tree_view_ref':'pms.pms_reservation_view_bottom_tree', 'form_view_ref':'pms.pms_reservation_view_form'}"
/>
</page>
<page string="Services">
<separator string="Service Lines" colspan="4"/>
<field name="service_ids"
<separator string="Service Lines" colspan="4" />
<field
name="service_ids"
context="{'from_room':False,'folio_id': id,'tree_view_ref':'pms.pms_service_view_tree', 'form_view_ref':'pms.pms_service_view_form'}"
nolabel="1" />
nolabel="1"
/>
</page>
<!--TODO: Add precheckin with indeterminate select room?? -->
<page name="persons" string="Persons" invisible="1">
<field name="checkin_partner_ids"
context="{
<field
name="checkin_partner_ids"
context="{
'default_reservation_id': id,
'reservation_id': id,
'tree_view_ref':'pms.pms_checkin_partner_reservation_view_tree',
@@ -142,58 +221,106 @@
/>
</page>
<page name="invoicing" string="Invoicing">
<div class="alert alert-info" role="alert" style="margin-bottom:0px;">
<div
class="alert alert-info"
role="alert"
style="margin-bottom:0px;"
>
these are the billing information associated with the booking client or the company (if a company is assigned). If you want to bill an independent contact, you can select it in the billing assistant
</div>
<group>
<field name="partner_parent_id" />
<field name="partner_invoice_id"
string="Contact Invoiced"/>
<field
name="partner_invoice_id"
string="Contact Invoiced"
/>
</group>
<group>
<group>
<field name="partner_invoice_vat"
attrs="{'readonly': [('partner_invoice_id', '!=', False),
('partner_invoice_vat','!=', False)]}" />
<field name="partner_invoice_email"
attrs="{'readonly': [('partner_invoice_id', '!=', False),
('partner_invoice_email','!=', False)]}" />
<field
name="partner_invoice_vat"
attrs="{'readonly': [('partner_invoice_id', '!=', False),
('partner_invoice_vat','!=', False)]}"
/>
<field
name="partner_invoice_email"
attrs="{'readonly': [('partner_invoice_id', '!=', False),
('partner_invoice_email','!=', False)]}"
/>
</group>
<group>
<label for="partner_invoice_street" string="Address"/>
<label
for="partner_invoice_street"
string="Address"
/>
<div class="o_address_format">
<field name="partner_invoice_street" placeholder="Street..." class="o_address_street"
<field
name="partner_invoice_street"
placeholder="Street..."
class="o_address_street"
attrs="{'readonly': [('partner_invoice_id', '!=', False),
('partner_invoice_street','!=', False)]}"/>
<field name="partner_invoice_street2" placeholder="Street 2..." class="o_address_street"
('partner_invoice_street','!=', False)]}"
/>
<field
name="partner_invoice_street2"
placeholder="Street 2..."
class="o_address_street"
attrs="{'readonly': [('partner_invoice_id', '!=', False),
('partner_invoice_street2','!=', False)]}"/>
<field name="partner_invoice_city" placeholder="City" class="o_address_city"
('partner_invoice_street2','!=', False)]}"
/>
<field
name="partner_invoice_city"
placeholder="City"
class="o_address_city"
attrs="{'readonly': [('partner_invoice_id', '!=', False),
('partner_invoice_city','!=', False)]}"/>
<field name="partner_invoice_state_id" class="o_address_state" placeholder="State" options='{"no_open": True}'
('partner_invoice_city','!=', False)]}"
/>
<field
name="partner_invoice_state_id"
class="o_address_state"
placeholder="State"
options='{"no_open": True}'
attrs="{'readonly': [('partner_invoice_id', '!=', False),
('partner_invoice_state_id','!=', False)]}"/>
<field name="partner_invoice_zip" placeholder="ZIP" class="o_address_zip"
('partner_invoice_state_id','!=', False)]}"
/>
<field
name="partner_invoice_zip"
placeholder="ZIP"
class="o_address_zip"
attrs="{'readonly': [('partner_invoice_id', '!=', False),
('partner_invoice_zip','!=', False)]}"/>
<field name="partner_invoice_country_id" placeholder="Country" class="o_address_country" options='{"no_open": True, "no_create": True}'
('partner_invoice_zip','!=', False)]}"
/>
<field
name="partner_invoice_country_id"
placeholder="Country"
class="o_address_country"
options='{"no_open": True, "no_create": True}'
attrs="{'readonly': [('partner_invoice_id', '!=', False),
('partner_invoice_country_id','!=', False)]}"/>
('partner_invoice_country_id','!=', False)]}"
/>
</div>
</group>
<group>
</group>
</group>
</page>
<page name="payments" string="Payments" attrs="{'invisible': [('invoices_paid','&lt;=',0)]}">
<field name="payment_ids"
context="{'tree_view_ref':'pms.account_payment_view_tree_folio', 'form_view_ref':'pms.account_payment_view_form_folio'}"
options="{'no_create': True}" />
<page
name="payments"
string="Payments"
attrs="{'invisible': [('invoices_paid','&lt;=',0)]}"
>
<field
name="payment_ids"
context="{'tree_view_ref':'pms.account_payment_view_tree_folio', 'form_view_ref':'pms.account_payment_view_form_folio'}"
options="{'no_create': True}"
/>
</page>
<page name="returns" string="Retun Payments" attrs="{'invisible': [('refund_amount','&lt;=',0)]}">
<field name="return_ids"
options="{'no_create': True}" />
<page
name="returns"
string="Retun Payments"
attrs="{'invisible': [('refund_amount','&lt;=',0)]}"
>
<field name="return_ids" options="{'no_create': True}" />
</page>
<page string="Other data" invisible="1">
<group>
@@ -218,66 +345,87 @@
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="activity_ids" widget="mail_activity"/>
<field name="message_ids" widget="mail_thread"/>
<field name="message_follower_ids" widget="mail_followers" />
<field name="activity_ids" widget="mail_activity" />
<field name="message_ids" widget="mail_thread" />
</div>
</form>
</field>
</record>
<record model="ir.ui.view" id="pms_folio_view_tree">
<field name="name">pms.folio.tree</field>
<field name="model">pms.folio</field>
<field name="arch" type="xml">
<tree string="Folio" decoration-info="state == 'draft'"
decoration-muted="state == 'cancel'"
default_order="create_date desc">
<field name="state"/>
<field name="name"/>
<field name="partner_id" select="1"/>
<field name="date_order" select="1"/>
<tree
string="Folio"
decoration-info="state == 'draft'"
decoration-muted="state == 'cancel'"
default_order="create_date desc"
>
<field name="state" />
<field name="name" />
<field name="partner_id" select="1" />
<field name="date_order" select="1" />
<field name="reservation_ids" widget="many2many_tags" />
<field name="amount_total" sum="Total amount"/>
<field name="pending_amount" sum="Total debt"/>
<field name="amount_total" sum="Total amount" />
<field name="pending_amount" sum="Total debt" />
<field name="invoice_status" />
<field name="pms_property_id" invisible="0"/>
<field name="pms_property_id" invisible="0" />
</tree>
</field>
</record>
<!-- Folio Kanban View -->
<record model="ir.ui.view" id="pms_folio_view_kanban">
<field name="name">pms.folio.kanban</field>
<field name="model">pms.folio</field>
<field name="arch" type="xml">
<kanban class="o_res_partner_kanban" limit="80">
<field name="name"/>
<field name="partner_id"/>
<field name="reservation_ids"/>
<field name="service_ids"/>
<field name="pending_amount"/>
<field name="refund_amount"/>
<field name="invoices_paid"/>
<field name="booking_pending"/>
<field name="checkin_partner_count"/>
<field name="checkin_partner_pending_count"/>
<field name="partner_internal_comment"/>
<field name="cancelled_reason"/>
<field name="prepaid_warning_days"/>
<field name="date_order"/>
<field name="name" />
<field name="partner_id" />
<field name="reservation_ids" />
<field name="service_ids" />
<field name="pending_amount" />
<field name="refund_amount" />
<field name="invoices_paid" />
<field name="booking_pending" />
<field name="checkin_partner_count" />
<field name="checkin_partner_pending_count" />
<field name="partner_internal_comment" />
<field name="cancelled_reason" />
<field name="prepaid_warning_days" />
<field name="date_order" />
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click o_res_partner_kanban">
<div class="o_kanban_tags_section oe_kanban_partner_categories"/>
<div
class="o_kanban_tags_section oe_kanban_partner_categories"
/>
<div class="oe_kanban_details">
<strong class="oe_partner_heading"><field name="partner_id"/></strong>
<strong class="oe_partner_heading">
<field name="partner_id" />
</strong>
<ul>
<li t-if="record.name.raw_value"><field name="name"/></li>
<span t-if="record.checkin_partner_count.value&gt;0" class="badge"><i class="fa fa-fw fa-bed"/><t t-esc="record.checkin_partner_count.value"/></span>
<span t-if="record.checkin_partner_pending_count.value&gt;0" class="badge"><i class="fa fa-fw fa-user-plus"/><t t-esc="record.checkin_partner_pending_count.value"/></span>
<li t-if="record.name.raw_value">
<field name="name" />
</li>
<span
t-if="record.checkin_partner_count.value&gt;0"
class="badge"
>
<i class="fa fa-fw fa-bed" />
<t t-esc="record.checkin_partner_count.value" />
</span>
<span
t-if="record.checkin_partner_pending_count.value&gt;0"
class="badge"
>
<i class="fa fa-fw fa-user-plus" />
<t
t-esc="record.checkin_partner_pending_count.value"
/>
</span>
</ul>
<div class="oe_kanban_partner_links"/>
<div class="oe_kanban_partner_links" />
</div>
</div>
</t>
@@ -285,7 +433,6 @@
</kanban>
</field>
</record>
<record model="ir.ui.view" id="pms_folio_view_search">
<field name="name">pms.folio.search</field>
<field name="model">pms.folio</field>
@@ -294,22 +441,38 @@
<field name="partner_id" />
<field name="partner_invoice_id" />
<field name="tour_operator_id" />
<filter name="to_invoice" string="To invoice"
domain="[('invoice_status', '=', 'to invoice')]" />
<filter name="payment_pending" string="Payment Pending"
domain="[('pending_amount', '&gt;', 0)]" />
<filter
name="to_invoice"
string="To invoice"
domain="[('invoice_status', '=', 'to invoice')]"
/>
<filter
name="payment_pending"
string="Payment Pending"
domain="[('pending_amount', '&gt;', 0)]"
/>
<group expand="0" string="Group By">
<filter string="Customer" icon="terp-stock_symbol-selection"
name="group_customer" context="{'group_by':'partner_id'}" />
<filter string="Invoice Contact"
name="group_invoice_contact" context="{'group_by':'partner_invoice_id'}" />
<filter string="Tour Operator" domain="[]"
name="group_tour_operator" context="{'group_by':'tour_operator_id'}"/>
<filter
string="Customer"
icon="terp-stock_symbol-selection"
name="group_customer"
context="{'group_by':'partner_id'}"
/>
<filter
string="Invoice Contact"
name="group_invoice_contact"
context="{'group_by':'partner_invoice_id'}"
/>
<filter
string="Tour Operator"
domain="[]"
name="group_tour_operator"
context="{'group_by':'tour_operator_id'}"
/>
</group>
</search>
</field>
</record>
<record id="pms_folio_view_graph" model="ir.ui.view">
<field name="name">view.pms.folio.graph</field>
<field name="model">pms.folio</field>
@@ -318,10 +481,9 @@
</graph>
</field>
</record>
<!-- Add create invoice merge folio -->
<act_window name="Send Confirm Mail"
<act_window
name="Send Confirm Mail"
res_model="mail.compose.message"
binding_model="pms.folio"
view_mode="form"
@@ -335,17 +497,24 @@
'default_composition_mode': 'comment',
'force_send': True,
'mark_so_as_sent': True,
}" />
}"
/>
<record model="ir.actions.act_window" id="open_pms_folio1_form_tree_all">
<field name="name">Folio</field>
<field name="res_model">pms.folio</field>
<field name="view_mode">tree,form,graph</field>
</record>
<menuitem id="menu_all_folio" name="Reservations"
parent="pms.pms_management_menu" sequence="4"/>
<menuitem name="Folios" id="menu_open_pms_folio1_form_tree_all"
action="open_pms_folio1_form_tree_all" sequence="15" parent="menu_all_folio" />
<menuitem
id="menu_all_folio"
name="Reservations"
parent="pms.pms_management_menu"
sequence="4"
/>
<menuitem
name="Folios"
id="menu_open_pms_folio1_form_tree_all"
action="open_pms_folio1_form_tree_all"
sequence="15"
parent="menu_all_folio"
/>
</odoo>

View File

@@ -1,13 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="pms_property_views_form" model="ir.ui.view">
<field name="name">pms_property_views_form</field>
<field name="model">pms.property</field>
<field name="arch" type="xml">
<form string="Property Configuration">
<sheet>
<label for="name" class="oe_edit_only"/>
<label for="name" class="oe_edit_only" />
<h1>
<field name="name" class="oe_inline" />
</h1>
@@ -18,26 +17,30 @@
</group>
</page>
<page string="Settings" name="property_settings">
<group colspan="4" col="4" string="Price and Restriction Plans">
<group
colspan="4"
col="4"
string="Price and Restriction Plans"
>
<field name="default_pricelist_id" required="True" />
<field name="default_restriction_id" required="True" />
</group>
<group string="Timezone">
<field name="tz" widget="timezone_mismatch"/>
<field name="tz" widget="timezone_mismatch" />
</group>
<group colspan="4" col="4" string="Check-in hours">
<field name="default_arrival_hour" />
<field name="default_departure_hour" />
<field name="default_departure_hour" />
</group>
<group colspan="4" col="4" string="Cancellation policies">
<field name="default_cancel_policy_days" />
<field name="default_cancel_policy_percent" />
<field name="default_cancel_policy_percent" />
</group>
</page>
<page string="Rooms" name="property_rooms">
<group>
<field name="room_type_ids"/>
<field name="room_ids"/>
<field name="room_type_ids" />
<field name="room_ids" />
</group>
</page>
</notebook>
@@ -45,30 +48,28 @@
</form>
</field>
</record>
<record id="pms_property_views_tree" model="ir.ui.view">
<field name="name">pms_property_views_tree</field>
<field name="model">pms.property</field>
<field name="arch" type="xml">
<tree string="Property settings summary">
<field name="name"/>
<field name="company_id"/>
<field name="name" />
<field name="company_id" />
</tree>
</field>
</record>
<!-- actions -->
<record id="pms_property_action" model="ir.actions.act_window">
<field name="name">Properties</field>
<field name="res_model">pms.property</field>
<field name="view_mode">tree,form</field>
</record>
<!-- menus -->
<menuitem action="pms_property_action" id="pms_property_menu"
parent="base.menu_users" sequence="10"
name = "Properties"/>
<menuitem
action="pms_property_action"
id="pms_property_menu"
parent="base.menu_users"
sequence="10"
name="Properties"
/>
</odoo>

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="pms_room_closure_reason_view_form">
<field name="name">pms.room.closure.reason.form</field>
<field name="model">room.closure.reason</field>
@@ -9,31 +8,35 @@
<sheet>
<field name="name" />
<field name="description" />
<field name="pms_property_ids" widget="many2many_tags"
options="{'no_create': True,'no_open': True}"/>
<field
name="pms_property_ids"
widget="many2many_tags"
options="{'no_create': True,'no_open': True}"
/>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="pms_room_closure_reason_view_tree">
<field name="name">>pms.room.closure.reason.tree</field>
<field name="model">room.closure.reason</field>
<field name="arch" type="xml">
<tree string="Room Closure Reason">
<field name="name"/>
<field name="name" />
<field name="description" />
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="open_pms_room_closure_reason_form_tree">
<field name="name">Room Closure Reason</field>
<field name="res_model">room.closure.reason</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Closure Reasons" id="menu_pms_room_closure_reason_form_tree"
action="open_pms_room_closure_reason_form_tree" sequence="25"
parent="pms.configuration_others" />
<menuitem
name="Closure Reasons"
id="menu_pms_room_closure_reason_form_tree"
action="open_pms_room_closure_reason_form_tree"
sequence="25"
parent="pms.configuration_others"
/>
</odoo>

View File

@@ -1,57 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="pms_room_type_class_view_form">
<field name="name">pms.room.type.class.form</field>
<field name="model">pms.room.type.class</field>
<field name="arch" type="xml">
<form string="Room Class">
<sheet>
<div class="oe_button_box" name="button_box">
<button name="toggle_active" type="object"
class="oe_stat_button" icon="fa-archive">
<field name="active" widget="boolean_button"
options='{"terminology": "archive"}'/>
</button>
</div>
<div class="oe_button_box" name="button_box">
<button
name="toggle_active"
type="object"
class="oe_stat_button"
icon="fa-archive"
>
<field
name="active"
widget="boolean_button"
options='{"terminology": "archive"}'
/>
</button>
</div>
<group colspan="4">
<group>
<field name="pms_property_ids" widget="many2many_tags"
options="{'no_create': True,'no_open': True}"/>
<field name="name" />
<field name="code_class" />
</group>
<group>
<field
name="pms_property_ids"
widget="many2many_tags"
options="{'no_create': True,'no_open': True}"
/>
<field name="name" />
<field name="code_class" />
</group>
</group>
<group colspan="2">
<group>
<field name="room_type_ids" widget="many2many"/>
<field name="room_type_ids" widget="many2many" />
</group>
</group>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="pms_room_type_class_view_tree">
<field name="name">pms.room.type.class.tree</field>
<field name="model">pms.room.type.class</field>
<field name="arch" type="xml">
<tree string="Room Class">
<field name="sequence" widget="handle"/>
<field name="sequence" widget="handle" />
<field name="name" />
<field name="code_class"/>
<field name="room_type_ids"/>
<field name="code_class" />
<field name="room_type_ids" />
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="open_pms_room_type_class_form_tree">
<field name="name">Room Type Class</field>
<field name="res_model">pms.room.type.class</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Type Class" id="menu_open_pms_room_type_class_form_tree"
action="open_pms_room_type_class_form_tree" sequence="15"
parent="pms.menu_pms_room" />
<menuitem
name="Type Class"
id="menu_open_pms_room_type_class_form_tree"
action="open_pms_room_type_class_form_tree"
sequence="15"
parent="pms.menu_pms_room"
/>
</odoo>

View File

@@ -1,44 +1,41 @@
<?xml version="1.0"?>
<?xml version="1.0" ?>
<odoo>
<record id="room_type_restriction_item_view_form" model="ir.ui.view">
<field name="name">pms.room.type.restriction.item.form</field>
<field name="model">pms.room.type.restriction.item</field>
<field name="arch" type="xml">
<form string="Restrictions">
<group>
<field name="room_type_id" required="True"/>
</group>
<group>
<field name="date"/>
</group>
<group>
<group>
<field name="min_stay"/>
<field name="min_stay_arrival"/>
<field name="max_stay"/>
</group>
<group>
<field name="closed"/>
<field name="closed_departure"/>
<field name="closed_arrival"/>
</group>
</group>
</form>
</field>
</record>
<record id="room_type_restriction_item_view_tree" model="ir.ui.view">
<field name="name">pms.room.type.restriction.item.tree</field>
<field name="model">pms.room.type.restriction.item</field>
<field name="arch" type="xml">
<tree string="Restrictions">
<field name="room_type_id"/>
<field name="date"/>
<field name="min_stay"/>
<field name="closed"/>
</tree>
</field>
</record>
<record id="room_type_restriction_item_view_form" model="ir.ui.view">
<field name="name">pms.room.type.restriction.item.form</field>
<field name="model">pms.room.type.restriction.item</field>
<field name="arch" type="xml">
<form string="Restrictions">
<group>
<field name="room_type_id" required="True" />
</group>
<group>
<field name="date" />
</group>
<group>
<group>
<field name="min_stay" />
<field name="min_stay_arrival" />
<field name="max_stay" />
</group>
<group>
<field name="closed" />
<field name="closed_departure" />
<field name="closed_arrival" />
</group>
</group>
</form>
</field>
</record>
<record id="room_type_restriction_item_view_tree" model="ir.ui.view">
<field name="name">pms.room.type.restriction.item.tree</field>
<field name="model">pms.room.type.restriction.item</field>
<field name="arch" type="xml">
<tree string="Restrictions">
<field name="room_type_id" />
<field name="date" />
<field name="min_stay" />
<field name="closed" />
</tree>
</field>
</record>
</odoo>

View File

@@ -1,63 +1,72 @@
<?xml version="1.0"?>
<?xml version="1.0" ?>
<odoo>
<record id="room_type_restriction_view_form" model="ir.ui.view">
<field name="name">pms.room.type.restriction.form</field>
<field name="model">pms.room.type.restriction</field>
<field name="arch" type="xml">
<form string="Restrictions">
<sheet>
<div class="oe_button_box" name="button_box">
<button name="toggle_active" type="object"
class="oe_stat_button" icon="fa-archive">
<field name="active" widget="boolean_button"
options='{"terminology": "archive"}'/>
</button>
</div>
<div class="oe_title">
<label for="name" string="Name" />
<h1>
<field name="name" />
</h1>
</div>
<div>
<field name="pms_property_id" options="{'no_create': True,'no_open': True}"/>
<separator string="Restriction Items"/>
<field name="item_ids" nolabel="1">
<tree string="Restriction Items">
<field name="room_type_id"/>
<field name="date"/>
<field name="min_stay"/>
<field name="closed"/>
</tree>
</field>
</div>
</sheet>
</form>
</field>
</record>
<record id="room_type_restriction_view_tree" model="ir.ui.view">
<field name="name">pms.room.type.restriction.tree</field>
<field name="model">pms.room.type.restriction</field>
<field name="arch" type="xml">
<tree string="Restrictions">
<field name="name"/>
<field name="active"/>
</tree>
</field>
</record>
<!-- Action of reservation restriction -->
<record model="ir.actions.act_window" id="room_type_restriction_action">
<field name="name">Reservation restrictions</field>
<field name="res_model">pms.room.type.restriction</field>
<field name="view_mode">tree,form</field>
</record>
<!-- MENUS -->
<menuitem name="Restrictions" id="reservation_restriction_menu"
action="room_type_restriction_action" sequence="22"
parent="pms.configuration_others"/>
</odoo>
<record id="room_type_restriction_view_form" model="ir.ui.view">
<field name="name">pms.room.type.restriction.form</field>
<field name="model">pms.room.type.restriction</field>
<field name="arch" type="xml">
<form string="Restrictions">
<sheet>
<div class="oe_button_box" name="button_box">
<button
name="toggle_active"
type="object"
class="oe_stat_button"
icon="fa-archive"
>
<field
name="active"
widget="boolean_button"
options='{"terminology": "archive"}'
/>
</button>
</div>
<div class="oe_title">
<label for="name" string="Name" />
<h1>
<field name="name" />
</h1>
</div>
<div>
<field
name="pms_property_id"
options="{'no_create': True,'no_open': True}"
/>
<separator string="Restriction Items" />
<field name="item_ids" nolabel="1">
<tree string="Restriction Items">
<field name="room_type_id" />
<field name="date" />
<field name="min_stay" />
<field name="closed" />
</tree>
</field>
</div>
</sheet>
</form>
</field>
</record>
<record id="room_type_restriction_view_tree" model="ir.ui.view">
<field name="name">pms.room.type.restriction.tree</field>
<field name="model">pms.room.type.restriction</field>
<field name="arch" type="xml">
<tree string="Restrictions">
<field name="name" />
<field name="active" />
</tree>
</field>
</record>
<!-- Action of reservation restriction -->
<record model="ir.actions.act_window" id="room_type_restriction_action">
<field name="name">Reservation restrictions</field>
<field name="res_model">pms.room.type.restriction</field>
<field name="view_mode">tree,form</field>
</record>
<!-- MENUS -->
<menuitem
name="Restrictions"
id="reservation_restriction_menu"
action="room_type_restriction_action"
sequence="22"
parent="pms.configuration_others"
/>
</odoo>

View File

@@ -1,51 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="pms_room_type_view_form">
<field name="name">pms.room_type.form</field>
<field name="model">pms.room.type</field>
<field name="arch" type="xml">
<form string="Property Room Type">
<sheet>
<div class="oe_button_box" name="button_box">
<button name="toggle_active" type="object"
class="oe_stat_button" icon="fa-archive">
<field name="active" widget="boolean_button"
options='{"terminology": "archive"}'/>
</button>
</div>
<div class="oe_button_box" name="button_box">
<button
name="toggle_active"
type="object"
class="oe_stat_button"
icon="fa-archive"
>
<field
name="active"
widget="boolean_button"
options='{"terminology": "archive"}'
/>
</button>
</div>
<group colspan="4">
<group>
<field name="name" />
<field name="code_type" />
<field name="class_id" />
</group>
<group>
<field name="pms_property_id" invisible="0"/>
<field name="list_price" widget='monetary' options="{'currency_field': 'currency_id', 'field_digits': True}"/>
</group>
<group>
<field name="name" />
<field name="code_type" />
<field name="class_id" />
</group>
<group>
<field name="pms_property_id" invisible="0" />
<field
name="list_price"
widget='monetary'
options="{'currency_field': 'currency_id', 'field_digits': True}"
/>
</group>
</group>
<group colspan="2">
<group name="room_ids_group">
<field name="shared_room" />
<field name="room_ids" widget="many2many_tags"/>
<field name="total_rooms_count"/>
<field name="room_ids" widget="many2many_tags" />
<field name="total_rooms_count" />
</group>
</group>
<notebook>
<page string="Board Services">
<separator string="Board Services" />
<field name="board_service_room_type_ids" colspan="4" nolabel="1"
context="{'default_pms_room_type_id':id}">
<field
name="board_service_room_type_ids"
colspan="4"
nolabel="1"
context="{'default_pms_room_type_id':id}"
>
<tree editable="bottom">
<field name="pms_room_type_id" invisible="1"/>
<field name="pms_room_type_id" invisible="1" />
<field name="pms_board_service_id" />
<field name="price_type" />
<field name="amount" />
<field name="pricelist_id" />
<button type="object" class="oe_stat_button"
id="go_board_lines" icon="fa fa-2x fa-bars"
name="open_board_lines_form"/>
<button
type="object"
class="oe_stat_button"
id="go_board_lines"
icon="fa fa-2x fa-bars"
name="open_board_lines_form"
/>
</tree>
</field>
</page>
@@ -58,32 +76,37 @@
</form>
</field>
</record>
<record model="ir.ui.view" id="pms_room_type_view_tree">
<field name="name">pms.room_type.tree</field>
<field name="model">pms.room.type</field>
<field name="arch" type="xml">
<tree string=" Property Room Type">
<field name="sequence" widget="handle"/>
<field name="sequence" widget="handle" />
<field name="pms_property_id" />
<field name="name" />
<field name="code_type"/>
<field name="list_price"/>
<field name="room_ids"/>
<field name="total_rooms_count"/>
<field name="code_type" />
<field name="list_price" />
<field name="room_ids" />
<field name="total_rooms_count" />
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="open_pms_room_type_form_tree">
<field name="name">Room Type</field>
<field name="res_model">pms.room.type</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_pms_room" name="Room"
parent="pms.pms_configuration_menu" sequence="2" />
<menuitem name="Room Types" id="menu_open_pms_room_type_form_tree"
action="open_pms_room_type_form_tree" sequence="6"
parent="pms.menu_pms_room" />
<menuitem
id="menu_pms_room"
name="Room"
parent="pms.pms_configuration_menu"
sequence="2"
/>
<menuitem
name="Room Types"
id="menu_open_pms_room_type_form_tree"
action="open_pms_room_type_form_tree"
sequence="6"
parent="pms.menu_pms_room"
/>
</odoo>

View File

@@ -1,94 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="pms_room_view_form">
<field name="name">pms.room.form</field>
<field name="model">pms.room</field>
<field name="arch" type="xml">
<form string="Property Room">
<sheet>
<div class="oe_button_box" name="button_box">
<button name="toggle_active" type="object"
class="oe_stat_button" icon="fa-archive">
<field name="active" widget="boolean_button"
options='{"terminology": "archive"}'/>
</button>
</div>
<div class="oe_title">
<label for="name" string="Name" />
<h1>
<field name="name"
attrs="{'readonly':[('shared_room_id','!=', False)]}" />
<field name="shared_room_id" string="Ubication"
invisible='True' />
</h1>
<!-- <label for="to_be_cleaned" string="To be Cleaned" />
<field name="name">pms.room.form</field>
<field name="model">pms.room</field>
<field name="arch" type="xml">
<form string="Property Room">
<sheet>
<div class="oe_button_box" name="button_box">
<button
name="toggle_active"
type="object"
class="oe_stat_button"
icon="fa-archive"
>
<field
name="active"
widget="boolean_button"
options='{"terminology": "archive"}'
/>
</button>
</div>
<div class="oe_title">
<label for="name" string="Name" />
<h1>
<field
name="name"
attrs="{'readonly':[('shared_room_id','!=', False)]}"
/>
<field
name="shared_room_id"
string="Ubication"
invisible='True'
/>
</h1>
<!-- <label for="to_be_cleaned" string="To be Cleaned" />
<h2>
<field name="to_be_cleaned"/>
</h2> -->
</div>
<notebook>
<page name="information_pms_room" string="Information">
<group colspan="4" col="4">
<field name="pms_property_id" invisible="0" force_save="1"/>
<field name="floor_id" string="Ubication"
attrs="{'readonly':[('shared_room_id','!=', False)]}" />
<!-- <field name="categ_id" select="1" domain="[('isroomtype','=',True)]" string="Room Type" /> -->
<field name="room_type_id" string="Room Type"
attrs="{'readonly':[('shared_room_id','!=', False)]}"/>
<field name="capacity"
attrs="{'readonly':[('shared_room_id','!=', False)]}" />
<field name="extra_beds_allowed"
attrs="{'invisible':[('shared_room_id','!=', False)]}"/>
<!-- <field name="uom_id" invisible="1" /> -->
</group>
<group>
</div>
<notebook>
<page name="information_pms_room" string="Information">
<group colspan="4" col="4">
<field
name="pms_property_id"
invisible="0"
force_save="1"
/>
<field
name="floor_id"
string="Ubication"
attrs="{'readonly':[('shared_room_id','!=', False)]}"
/>
<!-- <field name="categ_id" select="1" domain="[('isroomtype','=',True)]" string="Room Type" /> -->
<field
name="room_type_id"
string="Room Type"
attrs="{'readonly':[('shared_room_id','!=', False)]}"
/>
<field
name="capacity"
attrs="{'readonly':[('shared_room_id','!=', False)]}"
/>
<field
name="extra_beds_allowed"
attrs="{'invisible':[('shared_room_id','!=', False)]}"
/>
<!-- <field name="uom_id" invisible="1" /> -->
</group>
<group>
<!-- <field name="sale_price_type" /> -->
<!--field name="price_room_type_domain" invisible="1" /-->
<!-- <field name="price_room_type" domain="[('room_ids.id', '=', active_id)]" attrs="{'invisible':[('sale_price_type', '!=', 'room_type')], 'required': [('sale_price_type', '=', 'room_type')]}" /> -->
<!-- <field name="price_room_type" domain="[('room_ids.id', '=', active_id)]" attrs="{'invisible':[('sale_price_type', '!=', 'room_type')], 'required': [('sale_price_type', '=', 'room_type')]}" /> -->
</group>
<newline />
<!-- <separator colspan='4' string="Customer Taxes" /> -->
<!-- <field name="taxes_id" colspan="4" nolabel='1'
<newline />
<!-- <separator colspan='4' string="Customer Taxes" /> -->
<!-- <field name="taxes_id" colspan="4" nolabel='1'
help='Customer taxes apply on the perticular room. ' /> -->
</page>
<page string="Descriptions">
<group>
<field name="description_sale" colspan="2" string="Name in reports"/>
<!-- <field name="description" colspan="2" string="Description Sales"/> -->
</group>
</page>
</notebook>
<group>
<field name="sequence" attrs="{'readonly':[('shared_room_id','!=', False)]}"/>
</group>
</sheet>
</form>
</field>
</page>
<page string="Descriptions">
<group>
<field
name="description_sale"
colspan="2"
string="Name in reports"
/>
<!-- <field name="description" colspan="2" string="Description Sales"/> -->
</group>
</page>
</notebook>
<group>
<field
name="sequence"
attrs="{'readonly':[('shared_room_id','!=', False)]}"
/>
</group>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="pms_room_view_kanban">
<field name="name">pms.room.kanban</field>
<field name="model">pms.room</field>
<field name="type">kanban</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile" >
<kanban class="o_kanban_mobile">
<attribute name="group_create">false</attribute>
<field name="id"/>
<field name="name"/>
<field name="extra_beds_allowed"/>
<field name="id" />
<field name="name" />
<field name="extra_beds_allowed" />
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_global_click">
<div class="oe_kanban_details">
<ul>
<li class="mb4">
<strong><field name="name"/></strong>
<strong>
<field name="name" />
</strong>
</li>
<li class="mb4">Room Type: <field name="room_type_id"/></li>
<li class="mb4">Room Type: <field
name="room_type_id"
/></li>
<li class="badge mb4">
<strong>Capacity <field name="capacity"/></strong>
<strong>Capacity <field
name="capacity"
/></strong>
</li>
</ul>
</div>
@@ -98,7 +135,6 @@
</kanban>
</field>
</record>
<record model="ir.ui.view" id="pms_room_view_search">
<field name="name">pms.room.search</field>
<field name="model">pms.room</field>
@@ -115,21 +151,19 @@
</search>
</field>
</record>
<record model="ir.ui.view" id="pms_room_view_tree">
<field name="name">pms.room.tree</field>
<field name="model">pms.room</field>
<field name="arch" type="xml">
<tree string="Property Room">
<field name="sequence" widget="handle"/>
<field name="pms_property_id"/>
<field name="sequence" widget="handle" />
<field name="pms_property_id" />
<field name="name" />
<field name="room_type_id" />
<field name="capacity" />
</tree>
</field>
</record>
<!-- <record model="ir.ui.view" id="view_pms_room_kanban">
<field name="name">pms.room.kanban</field>
<field name="model">pms.room</field>
@@ -196,8 +230,6 @@
</kanban>
</field>
</record> -->
<record model="ir.actions.act_window" id="action_pms_room_form">
<field name="name">pms Room</field>
<field name="res_model">pms.room</field>
@@ -206,12 +238,14 @@
<field name="view_id" ref="pms_room_view_tree" />
<field name="view_mode">kanban,tree,form</field>
</record>
<menuitem name="Rooms" id="menu_open_pms_room_form" action="action_pms_room_form"
sequence="5" parent="pms.menu_pms_room" />
<menuitem
name="Rooms"
id="menu_open_pms_room_form"
action="action_pms_room_form"
sequence="5"
parent="pms.menu_pms_room"
/>
<!-- Room Categories -->
<!-- <record id="product_category_tree_view" model="ir.ui.view">
<field name="name">product.category.tree</field>
<field name="model">product.category</field>
@@ -222,7 +256,6 @@
</tree>
</field>
</record> -->
<!-- <record model="ir.actions.act_window" id="pms_room_category_action">
<field name="name">Rooms by Category</field>
<field name="type">ir.actions.act_window</field>
@@ -231,7 +264,6 @@
<field name="view_type">tree</field>
<field name="view_id" ref="product_category_tree_view" />
</record> -->
<!-- <record id="action_room_cate" model="ir.actions.act_window">
<field name="name">Category Items</field>
<field name="res_model">product.product</field>
@@ -239,15 +271,12 @@
<field name="domain">['|','|',('isroom','=',True), ('iscategid' , '=', True), ('isservice', '=', True)]</field>
<field name="context">{'search_default_categ_id':active_id, 'default_categ_id':active_id}</field>
</record> -->
<!--record id="ir_room_category_open" model="ir.default">
<field eval="'tree_but_open'" name="key2"/>
<field eval="'product.category'" name="model"/>
<field name="name">Rooms</field>
<field eval="'ir.actions.act_window,%d'%action_room_cate" name="value"/>
</record-->
<!-- <menuitem name="Room by Type" id="menu_pms_room_category_action"
action="pms_room_category_action" sequence="7" parent="pms.menu_pms_room" /> -->
</odoo>

View File

@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="pms_service_line_view_form">
<field name="name">pms.service.line.form</field>
<field name="model">pms.service.line</field>
@@ -9,28 +7,26 @@
<form string="Service Line">
<group>
<field name="product_id" />
<field name="day_qty"/>
<field name="day_qty" />
<field name="date" />
<field name="price_unit" />
<field name="pms_property_id" invisible="1"/>
<field name="pms_property_id" invisible="1" />
</group>
</form>
</field>
</record>
<record model="ir.ui.view" id="pms_service_line_view_tree">
<field name="name">pms.service.line.tree</field>
<field name="model">pms.service.line</field>
<field name="arch" type="xml">
<tree string="Service By Day">
<field name="product_id" />
<field name="day_qty"/>
<field name="day_qty" />
<field name="date" />
<field name="pms_property_id" invisible="1"/>
<field name="pms_property_id" invisible="1" />
</tree>
</field>
</record>
<record model="ir.ui.view" id="pms_service_line_report_view_tree">
<field name="name">pms.service.line.report.tree</field>
<field name="model">pms.service.line</field>
@@ -38,77 +34,88 @@
<tree string="Service By Day">
<field name="product_id" />
<field name="date" />
<field name="day_qty"/>
<field name="day_qty" />
<field name="price_unit" />
<field name="service_id" />
<field name="room_id" />
<field name="tax_ids" invisible="1"/>
<field name="tax_ids" invisible="1" />
<field name="discount" />
<field name="price_total" />
</tree>
</field>
</record>
<!-- Search Views -->
<record model="ir.ui.view" id="pms_service_line_view_search">
<field name="name">pms.service.line.search</field>
<field name="model">pms.service.line</field>
<field name="arch" type="xml">
<search string="Services By Day">
<field name="service_id" />
<filter string="Today"
name="today"
domain="[('date', '=', context_today().strftime('%Y-%m-%d'))]"
help="Current Booking" />
<filter string="Tomorrow"
name="tomorrow"
domain="[('date', '=', (context_today()+datetime.timedelta(days=1)).strftime('%Y-%m-%d'))]"
/>
<filter string="Next 7 days"
name="next_7_days"
domain="[('date', '&gt;', context_today().strftime('%Y-%m-%d')),
<filter
string="Today"
name="today"
domain="[('date', '=', context_today().strftime('%Y-%m-%d'))]"
help="Current Booking"
/>
<filter
string="Tomorrow"
name="tomorrow"
domain="[('date', '=', (context_today()+datetime.timedelta(days=1)).strftime('%Y-%m-%d'))]"
/>
<filter
string="Next 7 days"
name="next_7_days"
domain="[('date', '&gt;', context_today().strftime('%Y-%m-%d')),
('date', '&lt;', (context_today()+datetime.timedelta(days=7)).strftime('%Y-%m-%d'))]"
/>
/>
<group expand="0" string="Group By">
<filter string="By Month" name="date_by_month"
context="{'group_by':'date', 'default_order': 'date asc'}"/>
<filter string="By Week" name="date_by_week"
context="{'group_by':'date:week', 'default_order': 'date'}"/>
<filter string="By Day" name="date_by_week"
context="{'group_by':'date:day', 'default_order': 'date'}"/>
<filter string="Product" name="product_id"
context="{'group_by':'product_id', 'default_order': 'product_id'}"/>
<filter
string="By Month"
name="date_by_month"
context="{'group_by':'date', 'default_order': 'date asc'}"
/>
<filter
string="By Week"
name="date_by_week"
context="{'group_by':'date:week', 'default_order': 'date'}"
/>
<filter
string="By Day"
name="date_by_week"
context="{'group_by':'date:day', 'default_order': 'date'}"
/>
<filter
string="Product"
name="product_id"
context="{'group_by':'product_id', 'default_order': 'product_id'}"
/>
</group>
</search>
</field>
</record>
<!-- Action for service line from Form Folio/Reservation-->
<record model="ir.actions.act_window" id="action_pms_service_line_form">
<field name="name">Services</field>
<field name="res_model">pms.service.line</field>
<field name="view_mode">tree,form</field>
</record>
<!--
<!--
<menuitem name="Services as Products" id="menu_open_pms_service_line_form"
action="action_pms_service_line_form" sequence="8"
parent="pms.menu_pms_service" />
-->
<act_window
id="action_service_line"
name="Services By Day"
res_model="pms.service.line"
view_mode="tree,form"
view_id = "pms.pms_service_line_report_view_tree" />
view_id="pms.pms_service_line_report_view_tree"
/>
<menuitem
id="menu_pms_service_line"
name="Services by Day"
parent="pms.pms_reports_menu"
sequence="30"
action="action_service_line" />
action="action_service_line"
/>
</odoo>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="pms_service_view_form">
<field name="name">.pms.service.form</field>
<field name="model">pms.service</field>
@@ -8,33 +7,36 @@
<form string="Reservation Service">
<sheet>
<h1>
<field name="name" readonly="1"/>
<field name="name" readonly="1" />
</h1>
<field name="per_day" invisible="1"/>
<field name="per_day" invisible="1" />
<field name="is_board_service" invisible="1" />
<field name="folio_id" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="pms_property_id" invisible="1"/>
<field name="product_id"
<field name="folio_id" invisible="1" />
<field name="company_id" invisible="1" />
<field name="pms_property_id" invisible="1" />
<field
name="product_id"
domain="[('sale_ok', '=', True)]"
options="{'create': False, 'create_edit': False}"
invisible="1" />
invisible="1"
/>
<!-- <field name="layout_category_id" groups="sale.group_sale_layout"/> -->
<group>
<field name="product_qty"
<field
name="product_qty"
attrs="{'readonly': [('per_day','=',True)]}"
force_save="1"/>
force_save="1"
/>
</group>
<field name="days_qty" invisible="1"/>
<field name="days_qty" invisible="1" />
<field name="price_unit" invisible="1" />
<field name="discount" invisible="1"/>
<field name="tax_ids" widget="many2many_tags"
invisible="1"/>
<field name="price_subtotal" invisible="1"/>
<field name="price_tax" invisible="1"/>
<field name="price_total" invisible="1"/>
<field name="discount" invisible="1" />
<field name="tax_ids" widget="many2many_tags" invisible="1" />
<field name="price_subtotal" invisible="1" />
<field name="price_tax" invisible="1" />
<field name="price_total" invisible="1" />
<field name="service_line_ids" nolabel="1">
<tree string="Days" editable="bottom" >
<tree string="Days" editable="bottom">
<field name="date" />
<field name="day_qty" />
</tree>
@@ -43,43 +45,59 @@
</form>
</field>
</record>
<record model="ir.ui.view" id="pms_service_view_tree">
<field name="name">.pms.service.view.tree</field>
<field name="model">pms.service</field>
<field name="arch" type="xml">
<tree string="Services" editable="bottom"
decoration-success="is_board_service == True">
<tree
string="Services"
editable="bottom"
decoration-success="is_board_service == True"
>
<field name="is_board_service" invisible="1" />
<field name="to_print" />
<button type="object" class="oe_stat_button"
<button
type="object"
class="oe_stat_button"
icon="fa fa-1x fa-bed"
name="open_service_ids"
attrs="{'invisible':[('is_board_service','=', False)]}" />
<field name="per_day" invisible="1" readonly="1"/>
<field name="folio_id" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="pms_property_id" invisible="1"/>
<field name="reservation_id"
attrs = "{'required': [('per_day','=',True)]}" />
<field name="product_id"
attrs="{'invisible':[('is_board_service','=', False)]}"
/>
<field name="per_day" invisible="1" readonly="1" />
<field name="folio_id" invisible="1" />
<field name="company_id" invisible="1" />
<field name="pms_property_id" invisible="1" />
<field
name="reservation_id"
attrs="{'required': [('per_day','=',True)]}"
/>
<field
name="product_id"
domain="[('sale_ok', '=', True)]"
options="{'create': False, 'create_edit': False}"/>
<field name="name"/>
<field name="product_qty" attrs="{'readonly': [('per_day','=',True)]}" force_save="1"/>
<button type="object" class="oe_stat_button"
options="{'create': False, 'create_edit': False}"
/>
<field name="name" />
<field
name="product_qty"
attrs="{'readonly': [('per_day','=',True)]}"
force_save="1"
/>
<button
type="object"
class="oe_stat_button"
icon="fa fa-2x fa-bars"
name="open_service_ids"
attrs="{'invisible': [('per_day','=',False)]}"/>
<field name="days_qty" invisible="1"/>
attrs="{'invisible': [('per_day','=',False)]}"
/>
<field name="days_qty" invisible="1" />
<field name="price_unit" />
<field name="discount" />
<field name="tax_ids" widget="many2many_tags"/>
<field name="tax_ids" widget="many2many_tags" />
<field name="price_subtotal" />
<field name="price_tax" />
<field name="price_total" />
<field name="service_line_ids" invisible="1">
<tree string="Days" >
<tree string="Days">
<field name="date" />
<field name="day_qty" />
</tree>
@@ -87,15 +105,14 @@
</tree>
</field>
</record>
<record model="ir.ui.view" id="pms_service_view_search">
<field name="name">pms.service.search</field>
<field name="model">pms.service</field>
<field name="arch" type="xml">
<search string="Reservation Service">
<field name="name" />
<field name="product_id"/>
<field name="product_qty" />
<field name="product_id" />
<field name="product_qty" />
<newline />
<group expand="0" string="Group By...">
<!-- <filter name="categ_id" string="Catagory"
@@ -105,15 +122,9 @@
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_pms_services_form">
<field name="name">Services</field>
<field name="res_model">pms.service</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>

View File

@@ -1,68 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="pms_shared_room_view_form">
<field name="name">pms.shared.room.form</field>
<field name="model">pms.shared.room</field>
<field name="arch" type="xml">
<form string="Shared Room">
<sheet>
<div class="oe_button_box" name="button_box">
<button name="toggle_active" type="object"
class="oe_stat_button" icon="fa-archive">
<field name="active" widget="boolean_button"
options='{"terminology": "archive"}'/>
</button>
</div>
<div class="oe_title">
<label for="name" string="Name" />
<h1>
<field name="name" />
</h1>
</div>
<notebook>
<page name="information_pms_shared_shared_room" string="Information">
<group colspan="4" col="4">
<field name="floor_id" string="Ubication" />
<field name="room_type_id" string="Room Type" />
<field name="beds" />
<field name="sequence" />
</group>
<group>
<field name="bed_ids" />
</group>
</page>
<page string="Descriptions">
<group>
<field name="description_sale" colspan="2" string="Name in reports"/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
<field name="name">pms.shared.room.form</field>
<field name="model">pms.shared.room</field>
<field name="arch" type="xml">
<form string="Shared Room">
<sheet>
<div class="oe_button_box" name="button_box">
<button
name="toggle_active"
type="object"
class="oe_stat_button"
icon="fa-archive"
>
<field
name="active"
widget="boolean_button"
options='{"terminology": "archive"}'
/>
</button>
</div>
<div class="oe_title">
<label for="name" string="Name" />
<h1>
<field name="name" />
</h1>
</div>
<notebook>
<page
name="information_pms_shared_shared_room"
string="Information"
>
<group colspan="4" col="4">
<field name="floor_id" string="Ubication" />
<field name="room_type_id" string="Room Type" />
<field name="beds" />
<field name="sequence" />
</group>
<group>
<field name="bed_ids" />
</group>
</page>
<page string="Descriptions">
<group>
<field
name="description_sale"
colspan="2"
string="Name in reports"
/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="pms_shared_shared_room_view_kanban">
<field name="name">pms.shared.room.kanban</field>
<field name="model">pms.shared.room</field>
<field name="type">kanban</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile" >
<kanban class="o_kanban_mobile">
<attribute name="group_create">false</attribute>
<field name="id"/>
<field name="name"/>
<field name="id" />
<field name="name" />
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_global_click">
<div class="oe_kanban_details">
<ul>
<li class="mb4">
<strong><field name="name"/></strong>
<strong>
<field name="name" />
</strong>
</li>
<li class="mb4">Room Type: <field name="room_type_id"/></li>
<li class="mb4">Room Type: <field
name="room_type_id"
/></li>
<li class="badge mb4">
<strong>Beds <field name="beds"/></strong>
<strong>Beds <field name="beds" /></strong>
</li>
</ul>
</div>
@@ -72,7 +88,6 @@
</kanban>
</field>
</record>
<record model="ir.ui.view" id="pms_shared_shared_room_view_search">
<field name="name">pms.shared.room.search</field>
<field name="model">pms.shared.room</field>
@@ -84,7 +99,6 @@
</search>
</field>
</record>
<record model="ir.ui.view" id="pms_shared_room_view_tree">
<field name="name">pms.shared.room.tree</field>
<field name="model">pms.shared.room</field>
@@ -97,8 +111,6 @@
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_pms_shared_room_form">
<field name="name">Shared Room</field>
<field name="res_model">pms.shared.room</field>
@@ -107,8 +119,11 @@
<field name="view_id" ref="pms_shared_room_view_tree" />
<field name="view_mode">kanban,tree,form</field>
</record>
<menuitem name="Shared Rooms" id="menu_open_pms_shared_room_form" action="action_pms_shared_room_form"
sequence="5" parent="pms.menu_pms_room" />
<menuitem
name="Shared Rooms"
id="menu_open_pms_shared_room_form"
action="action_pms_shared_room_form"
sequence="5"
parent="pms.menu_pms_room"
/>
</odoo>

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution

View File

@@ -1,11 +1,12 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import time
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
from datetime import timedelta
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
class FolioAdvancePaymentInv(models.TransientModel):
_name = "folio.advance.payment.inv"
@@ -13,30 +14,36 @@ class FolioAdvancePaymentInv(models.TransientModel):
@api.model
def _get_advance_payment_method(self):
return 'all'
return "all"
@api.model
def _default_product_id(self):
product_id = self.env['ir.config_parameter'].sudo().get_param('sale.default_deposit_product_id')
return self.env['product.product'].browse(int(product_id))
product_id = (
self.env["ir.config_parameter"]
.sudo()
.get_param("sale.default_deposit_product_id")
)
return self.env["product.product"].browse(int(product_id))
@api.model
def _get_default_folio(self):
if self._context.get('default_reservation_id'):
folio_ids = self._context.get('default_folio_id', [])
if self._context.get("default_reservation_id"):
folio_ids = self._context.get("default_folio_id", [])
else:
folio_ids = self._context.get('active_ids', [])
folio_ids = self._context.get("active_ids", [])
folios = self.env['pms.folio'].browse(folio_ids)
folios = self.env["pms.folio"].browse(folio_ids)
return folios
@api.model
def _get_default_reservation(self):
if self._context.get('default_reservation_id'):
reservations = self.env['pms.reservation'].browse(self._context.get('active_ids', []))
if self._context.get("default_reservation_id"):
reservations = self.env["pms.reservation"].browse(
self._context.get("active_ids", [])
)
else:
folios = self._get_default_folio()
reservations = self.env['pms.reservation']
reservations = self.env["pms.reservation"]
for folio in folios:
reservations |= folio.reservation_ids
return reservations
@@ -56,162 +63,213 @@ class FolioAdvancePaymentInv(models.TransientModel):
def _default_deposit_taxes_id(self):
return self._default_product_id().taxes_id
advance_payment_method = fields.Selection([
('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)
auto_invoice = fields.Boolean('Auto Payment Invoice',
default=True,
help='Automatic validation and link payment to invoice')
count = fields.Integer(compute='_count', store=True, string='# of Orders')
folio_ids = fields.Many2many("pms.folio", string="Folios",
help="Folios grouped",
default=_get_default_folio)
reservation_ids = fields.Many2many("pms.reservation", string="Rooms",
help="Folios grouped",
default=_get_default_reservation)
group_folios = fields.Boolean('Group Folios')
partner_invoice_id = fields.Many2one('res.partner',
string='Invoice Address', required=True,
default=_get_default_partner_invoice,
help="Invoice address for current Invoice.")
line_ids = fields.One2many('line.advance.inv',
'advance_inv_id',
string="Invoice Lines")
#Advance Payment
product_id = fields.Many2one('product.product', string="Product",
domain=[('type', '=', 'service')], default=_default_product_id)
amount = fields.Float('Down Payment Amount',
digits=('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)
advance_payment_method = fields.Selection(
[
("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,
)
auto_invoice = fields.Boolean(
"Auto Payment Invoice",
default=True,
help="Automatic validation and link payment to invoice",
)
count = fields.Integer(compute="_count", store=True, string="# of Orders")
folio_ids = fields.Many2many(
"pms.folio", string="Folios", help="Folios grouped", default=_get_default_folio
)
reservation_ids = fields.Many2many(
"pms.reservation",
string="Rooms",
help="Folios grouped",
default=_get_default_reservation,
)
group_folios = fields.Boolean("Group Folios")
partner_invoice_id = fields.Many2one(
"res.partner",
string="Invoice Address",
required=True,
default=_get_default_partner_invoice,
help="Invoice address for current Invoice.",
)
line_ids = fields.One2many(
"line.advance.inv", "advance_inv_id", string="Invoice Lines"
)
# Advance Payment
product_id = fields.Many2one(
"product.product",
string="Product",
domain=[("type", "=", "service")],
default=_default_product_id,
)
amount = fields.Float(
"Down Payment Amount",
digits=("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.depends('folio_ids')
@api.depends("folio_ids")
def _count(self):
for record in self:
record.update({'count': len(self.folio_ids)})
record.update({"count": len(self.folio_ids)})
@api.onchange('advance_payment_method')
@api.onchange("advance_payment_method")
def onchange_advance_payment_method(self):
if self.advance_payment_method == 'percentage':
return {'value': {'amount': 0}}
if self.advance_payment_method == "percentage":
return {"value": {"amount": 0}}
return {}
def _create_invoice(self, folio, service, amount):
inv_obj = self.env['account.invoice']
ir_property_obj = self.env['ir.property']
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 \
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 = folio.fiscal_position_id.map_account(inc_acc).id if inc_acc else False
inc_acc = ir_property_obj.get(
"property_account_income_categ_id", "product.category"
)
account_id = (
folio.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,))
_(
'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': folio.partner_id.lang}
if self.advance_payment_method == 'percentage':
raise UserError(_("The value of the down payment amount must be positive."))
context = {"lang": folio.partner_id.lang}
if self.advance_payment_method == "percentage":
amount = folio.amount_untaxed * self.amount / 100
name = _("Down payment of %s%%") % (self.amount,)
else:
amount = self.amount
name = _('Down Payment')
name = _("Down Payment")
del context
taxes = self.product_id.taxes_id.filtered(
lambda r: not folio.company_id or r.company_id == folio.company_id)
lambda r: not folio.company_id or r.company_id == folio.company_id
)
if folio.fiscal_position_id and taxes:
tax_ids = folio.fiscal_position_id.map_tax(taxes).ids
else:
tax_ids = taxes.ids
invoice = inv_obj.create({
'name': folio.client_order_ref or folio.name,
'invoice_origin': folio.name,
'type': 'out_invoice',
'reference': False,
'folio_ids': [(6, 0, [folio.id])], #REVIEW: Folio_ids is a computed field, Why need this value?
'account_id': folio.partner_id.property_account_receivable_id.id,
'partner_id': folio.partner_invoice_id.id,
'invoice_line_ids': [(0, 0, {
'name': name,
'invoice_origin': folio.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,
'service_ids': [(6, 0, [service.id])],
'invoice_line_tax_ids': [(6, 0, tax_ids)],
'account_analytic_id': folio.analytic_account_id.id or False,
})],
'currency_id': folio.pricelist_id.currency_id.id,
'invoice_payment_term_id': folio.payment_term_id.id,
'fiscal_position_id': folio.fiscal_position_id.id \
invoice = inv_obj.create(
{
"name": folio.client_order_ref or folio.name,
"invoice_origin": folio.name,
"type": "out_invoice",
"reference": False,
"folio_ids": [
(6, 0, [folio.id])
], # REVIEW: Folio_ids is a computed field, Why need this value?
"account_id": folio.partner_id.property_account_receivable_id.id,
"partner_id": folio.partner_invoice_id.id,
"invoice_line_ids": [
(
0,
0,
{
"name": name,
"invoice_origin": folio.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,
"service_ids": [(6, 0, [service.id])],
"invoice_line_tax_ids": [(6, 0, tax_ids)],
"account_analytic_id": folio.analytic_account_id.id
or False,
},
)
],
"currency_id": folio.pricelist_id.currency_id.id,
"invoice_payment_term_id": folio.payment_term_id.id,
"fiscal_position_id": folio.fiscal_position_id.id
or folio.partner_id.property_account_position_id.id,
'team_id': folio.team_id.id,
'user_id': folio.user_id.id,
'comment': folio.note,
})
#invoice.compute_taxes() #TODO: Review method (view sales module)
"team_id": folio.team_id.id,
"user_id": folio.user_id.id,
"comment": folio.note,
}
)
# invoice.compute_taxes() #TODO: Review method (view sales module)
invoice.message_post_with_view(
'mail.message_origin_link',
values={'self': invoice, 'invoice_origin': folio},
subtype_id=self.env.ref('mail.mt_note').id)
"mail.message_origin_link",
values={"self": invoice, "invoice_origin": folio},
subtype_id=self.env.ref("mail.mt_note").id,
)
return invoice
@api.model
def _validate_invoices(self, invoice):
if self.auto_invoice:
invoice.action_invoice_open()
payment_ids = self.folio_ids.mapped('payment_ids.id')
payment_ids = self.folio_ids.mapped("payment_ids.id")
domain = [
('account_id', '=', invoice.account_id.id),
('payment_id', 'in', payment_ids),
('reconciled', '=', False),
'|', ('amount_residual', '!=', 0.0),
('amount_residual_currency', '!=', 0.0)
]
if invoice.type in ('out_invoice', 'in_refund'):
domain.extend([('credit', '>', 0), ('debit', '=', 0)])
type_payment = _('Outstanding credits')
("account_id", "=", invoice.account_id.id),
("payment_id", "in", payment_ids),
("reconciled", "=", False),
"|",
("amount_residual", "!=", 0.0),
("amount_residual_currency", "!=", 0.0),
]
if invoice.type in ("out_invoice", "in_refund"):
domain.extend([("credit", ">", 0), ("debit", "=", 0)])
type_payment = _("Outstanding credits")
else:
domain.extend([('credit', '=', 0), ('debit', '>', 0)])
type_payment = _('Outstanding debits')
info = {'title': '', 'outstanding': True, 'content': [], 'invoice_id': invoice.id}
lines = self.env['account.move.line'].search(domain)
domain.extend([("credit", "=", 0), ("debit", ">", 0)])
type_payment = _("Outstanding debits")
info = {
"title": "",
"outstanding": True,
"content": [],
"invoice_id": invoice.id,
}
lines = self.env["account.move.line"].search(domain)
currency_id = invoice.currency_id
for line in lines:
invoice.assign_outstanding_credit(line.id)
return True
def create_invoices(self):
inv_obj = self.env['account.move']
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
inv_obj = self.env["account.move"]
precision = self.env["decimal.precision"].precision_get(
"Product Unit of Measure"
)
folios = self.folio_ids
if not self.partner_invoice_id or not self.partner_invoice_id.vat:
vat_error = _("We need the VAT of the customer")
raise ValidationError(vat_error)
if self.advance_payment_method == 'all':
if self.advance_payment_method == "all":
inv_data = self._prepare_invoice()
invoice = inv_obj.create(inv_data)
for line in self.line_ids:
@@ -220,45 +278,57 @@ class FolioAdvancePaymentInv(models.TransientModel):
# Create deposit product if necessary
if not self.product_id:
vals = self._prepare_deposit_product()
self.product_id = self.env['product.product'].sudo().create(vals)
self.env['ir.config_parameter'].sudo().set_param(
'sale.default_deposit_product_id', self.product_id.id)
self.product_id = self.env["product.product"].sudo().create(vals)
self.env["ir.config_parameter"].sudo().set_param(
"sale.default_deposit_product_id", self.product_id.id
)
service_obj = self.env['pms.service']
service_obj = self.env["pms.service"]
for folio in folios:
if self.advance_payment_method == 'percentage':
if self.advance_payment_method == "percentage":
amount = folio.amount_untaxed * folio.amount_total / 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."))
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 folio.company_id or r.company_id == folio.company_id)
lambda r: not folio.company_id or r.company_id == folio.company_id
)
if folio.fiscal_position_id and taxes:
tax_ids = folio.fiscal_position_id.map_tax(taxes).ids
else:
tax_ids = taxes.ids
context = {'lang': folio.partner_id.lang}
service_line = service_obj.create({
'name': _('Advance: %s') % (time.strftime('%m %Y'),),
'price_unit': amount,
'product_qty': 0.0,
'folio_id': folio.id,
'discount': 0.0,
'product_uom': self.product_id.uom_id.id,
'product_id': self.product_id.id,
'tax_id': [(6, 0, tax_ids)],
})
context = {"lang": folio.partner_id.lang}
service_line = service_obj.create(
{
"name": _("Advance: %s") % (time.strftime("%m %Y"),),
"price_unit": amount,
"product_qty": 0.0,
"folio_id": folio.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
invoice = self._create_invoice(folio, service_line, amount)
#invoice.compute_taxes() #TODO: Review Method
# invoice.compute_taxes() #TODO: Review Method
if not invoice.invoice_line_ids:
raise UserError(_('There is no invoiceable line.'))
raise UserError(_("There is no invoiceable line."))
# If invoice is negative, do a refund invoice instead
if invoice.amount_total < 0:
invoice.type = 'out_refund'
invoice.type = "out_refund"
for line in invoice.invoice_line_ids:
line.quantity = -line.quantity
# Use additional field helper function (for account extensions)
@@ -266,101 +336,127 @@ class FolioAdvancePaymentInv(models.TransientModel):
line._set_additional_fields(invoice)
# Necessary to force computation of taxes. In account_invoice, they are triggered
# by onchanges, which are not triggered when doing a create.
#invoice.compute_taxes() TODO: REVIEW method
# invoice.compute_taxes() TODO: REVIEW method
self._validate_invoices(invoice)
invoice.message_post_with_view('mail.message_origin_link',
values={'self': invoice, 'invoice_origin': folios},
subtype_id=self.env.ref('mail.mt_note').id)
if self._context.get('open_invoices', False):
invoice.message_post_with_view(
"mail.message_origin_link",
values={"self": invoice, "invoice_origin": folios},
subtype_id=self.env.ref("mail.mt_note").id,
)
if self._context.get("open_invoices", False):
return folios.open_invoices_folio()
return {'type': 'ir.actions.act_window_close'}
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)],
"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)],
}
@api.onchange('reservation_ids')
@api.onchange("reservation_ids")
def prepare_invoice_lines(self):
vals = [(5,0,0)]
vals = [(5, 0, 0)]
folios = self.folio_ids
invoice_lines = {}
for folio in folios:
for service in folio.service_ids.filtered(
lambda x: x.is_board_service == False and \
x.qty_to_invoice != 0 and \
(x.reservation_id.id in self.reservation_ids.ids or \
not x.reservation_id.id)):
lambda x: x.is_board_service == False
and x.qty_to_invoice != 0
and (
x.reservation_id.id in self.reservation_ids.ids
or not x.reservation_id.id
)
):
invoice_lines[service.id] = {
'description': service.name,
'product_id': service.product_id.id,
'qty': service.qty_to_invoice,
'discount': service.discount,
'price_unit': service.price_unit,
'service_id': service.id,
}
"description": service.name,
"product_id": service.product_id.id,
"qty": service.qty_to_invoice,
"discount": service.discount,
"price_unit": service.price_unit,
"service_id": service.id,
}
for reservation in folio.reservation_ids.filtered(
lambda x: x._origin.id in self.reservation_ids.ids and
x.invoice_status == 'to invoice'):
lambda x: x._origin.id in self.reservation_ids.ids
and x.invoice_status == "to invoice"
):
board_service = reservation.board_service_room_id
for day in reservation.reservation_line_ids.filtered(
lambda x: not x.move_line_ids).sorted('date'):
lambda x: not x.move_line_ids
).sorted("date"):
extra_price = 0
if board_service:
services = reservation.service_ids.filtered(
lambda x: x.is_board_service == True)
lambda x: x.is_board_service == True
)
for service in services:
service_date = day.date
if service.product_id.consumed_on == 'after':
service_date = (fields.Date.from_string(day.date) + \
timedelta(days=1)).strftime(DEFAULT_SERVER_DATE_FORMAT)
extra_price += service.price_unit * \
service.service_line_ids.filtered(
lambda x: x.date == service_date).day_qty
#group_key: if group by reservation, We no need group by room_type
group_key = (reservation.id, reservation.room_type_id.id,
day.price + extra_price, day.discount,
day.cancel_discount)
if service.product_id.consumed_on == "after":
service_date = (
fields.Date.from_string(day.date)
+ timedelta(days=1)
).strftime(DEFAULT_SERVER_DATE_FORMAT)
extra_price += (
service.price_unit
* service.service_line_ids.filtered(
lambda x: x.date == service_date
).day_qty
)
# group_key: if group by reservation, We no need group by room_type
group_key = (
reservation.id,
reservation.room_type_id.id,
day.price + extra_price,
day.discount,
day.cancel_discount,
)
if day.cancel_discount == 100:
continue
discount_factor = 1.0
for discount in [day.discount, day.cancel_discount]:
discount_factor = (
discount_factor * ((100.0 - discount) / 100.0))
discount_factor = discount_factor * ((100.0 - discount) / 100.0)
final_discount = 100.0 - (discount_factor * 100.0)
description = folio.name + ' ' + reservation.room_type_id.name + ' (' + \
reservation.board_service_room_id.pms_board_service_id.name + ')' \
if board_service else folio.name + ' ' + reservation.room_type_id.name
description = (
folio.name
+ " "
+ reservation.room_type_id.name
+ " ("
+ reservation.board_service_room_id.pms_board_service_id.name
+ ")"
if board_service
else folio.name + " " + reservation.room_type_id.name
)
if group_key not in invoice_lines:
invoice_lines[group_key] = {
'description': description,
'reservation_id': reservation.id,
'room_type_id': reservation.room_type_id,
'product_id': self.env['product.product'].browse(
reservation.room_type_id.product_id.id),
'discount': final_discount,
'price_unit': day.price + extra_price,
'reservation_line_ids': [(4, day.id)]
"description": description,
"reservation_id": reservation.id,
"room_type_id": reservation.room_type_id,
"product_id": self.env["product.product"].browse(
reservation.room_type_id.product_id.id
),
"discount": final_discount,
"price_unit": day.price + extra_price,
"reservation_line_ids": [(4, day.id)],
}
else:
invoice_lines[group_key][('reservation_line_ids')].append((4,day.id))
invoice_lines[group_key][("reservation_line_ids")].append(
(4, day.id)
)
for group_key in invoice_lines:
vals.append((0, False, invoice_lines[group_key]))
self.line_ids = vals
self.line_ids.onchange_reservation_line_ids()
@api.onchange('folio_ids')
@api.onchange("folio_ids")
def onchange_folio_ids(self):
vals = []
folios = self.folio_ids
invoice_lines = {}
reservations = self.env['pms.reservation']
services = self.env['pms.service']
old_folio_ids = self.reservation_ids.mapped('folio_id.id')
reservations = self.env["pms.reservation"]
services = self.env["pms.service"]
old_folio_ids = self.reservation_ids.mapped("folio_id.id")
for folio in folios.filtered(lambda r: r.id not in old_folio_ids):
folio_reservations = folio.reservation_ids
if folio_reservations:
@@ -376,10 +472,12 @@ class FolioAdvancePaymentInv(models.TransientModel):
a clean extension chain).
"""
journal_id = self.env['account.move'].default_get(['journal_id'])['journal_id']
journal_id = self.env["account.move"].default_get(["journal_id"])["journal_id"]
if not journal_id:
raise UserError(_('Please define an accounting sales journal for this company.'))
origin = ' '.join(self.folio_ids.mapped('name'))
raise UserError(
_("Please define an accounting sales journal for this company.")
)
origin = " ".join(self.folio_ids.mapped("name"))
pricelist = self.folio_ids[0].pricelist_id
currency = self.folio_ids[0].currency_id
payment_term = self.folio_ids[0].payment_term_id
@@ -392,64 +490,75 @@ class FolioAdvancePaymentInv(models.TransientModel):
# if folio.pricelist_id != pricelist:
# raise UserError(_('All Folios must hace the same pricelist'))
invoice_vals = {
'name': self.folio_ids[0].client_order_ref or '',
'invoice_origin': origin,
'type': 'out_invoice',
'partner_id': self.partner_invoice_id.id,
'journal_id': journal_id,
'currency_id': currency.id,
'invoice_payment_term_id': payment_term.id,
'fiscal_position_id': fiscal_position.id or self.partner_invoice_id.property_account_position_id.id,
'company_id': company.id,
'user_id': user and user.id,
'team_id': team.id,
'narration': self.folio_ids[0].note
"name": self.folio_ids[0].client_order_ref or "",
"invoice_origin": origin,
"type": "out_invoice",
"partner_id": self.partner_invoice_id.id,
"journal_id": journal_id,
"currency_id": currency.id,
"invoice_payment_term_id": payment_term.id,
"fiscal_position_id": fiscal_position.id
or self.partner_invoice_id.property_account_position_id.id,
"company_id": company.id,
"user_id": user and user.id,
"team_id": team.id,
"narration": self.folio_ids[0].note,
}
return invoice_vals
class LineAdvancePaymentInv(models.TransientModel):
_name = "line.advance.inv"
_description = "Lines Advance Invoice"
room_type_id = fields.Many2one('pms.room.type')
product_id = fields.Many2one('product.product', string='Down Payment Product',
domain=[('type', '=', 'service')])
qty = fields.Integer('Quantity')
price_unit = fields.Float('Price Unit')
price_total = fields.Float('Price Total', compute='_compute_price_total')
price_tax = fields.Float('Price Tax', compute='_compute_price_total')
price_subtotal = fields.Float('Price Subtotal',
compute='_compute_price_total',
store=True)
advance_inv_id = fields.Many2one('folio.advance.payment.inv')
price_room = fields.Float(compute='_compute_price_room')
discount = fields.Float(
string='Discount (%)',
digits=('Discount'), default=0.0)
to_invoice = fields.Boolean('To Invoice')
description = fields.Text('Description')
description_dates = fields.Text('Range')
reservation_id = fields.Many2one('pms.reservation')
service_id = fields.Many2one('pms.service')
folio_id = fields.Many2one('pms.folio', compute='_compute_folio_id')
room_type_id = fields.Many2one("pms.room.type")
product_id = fields.Many2one(
"product.product",
string="Down Payment Product",
domain=[("type", "=", "service")],
)
qty = fields.Integer("Quantity")
price_unit = fields.Float("Price Unit")
price_total = fields.Float("Price Total", compute="_compute_price_total")
price_tax = fields.Float("Price Tax", compute="_compute_price_total")
price_subtotal = fields.Float(
"Price Subtotal", compute="_compute_price_total", store=True
)
advance_inv_id = fields.Many2one("folio.advance.payment.inv")
price_room = fields.Float(compute="_compute_price_room")
discount = fields.Float(string="Discount (%)", digits=("Discount"), default=0.0)
to_invoice = fields.Boolean("To Invoice")
description = fields.Text("Description")
description_dates = fields.Text("Range")
reservation_id = fields.Many2one("pms.reservation")
service_id = fields.Many2one("pms.service")
folio_id = fields.Many2one("pms.folio", compute="_compute_folio_id")
reservation_line_ids = fields.Many2many(
'pms.reservation.line',
string='Reservation Lines')
"pms.reservation.line", string="Reservation Lines"
)
@api.depends('qty', 'price_unit', 'discount')
@api.depends("qty", "price_unit", "discount")
def _compute_price_total(self):
for record in self:
origin = record.reservation_id if record.reservation_id.id else record.service_id
origin = (
record.reservation_id if record.reservation_id.id else record.service_id
)
amount_line = record.price_unit * record.qty
if amount_line != 0:
product = record.product_id
price = amount_line * (1 - (record.discount or 0.0) * 0.01)
taxes = origin.tax_ids.compute_all(price, origin.currency_id, 1, product=product)
record.update({
'price_tax': sum(t.get('amount', 0.0) for t in taxes.get('taxes', [])),
'price_total': taxes['total_included'],
'price_subtotal': taxes['total_excluded'],
})
taxes = origin.tax_ids.compute_all(
price, origin.currency_id, 1, product=product
)
record.update(
{
"price_tax": sum(
t.get("amount", 0.0) for t in taxes.get("taxes", [])
),
"price_total": taxes["total_included"],
"price_subtotal": taxes["total_excluded"],
}
)
def _compute_price_room(self):
self.price_room = False
@@ -459,20 +568,27 @@ class LineAdvancePaymentInv(models.TransientModel):
def _compute_folio_id(self):
for record in self:
origin = record.reservation_id if record.reservation_id.id else record.service_id
origin = (
record.reservation_id if record.reservation_id.id else record.service_id
)
record.folio_id = origin.folio_id
@api.onchange('reservation_line_ids')
@api.onchange("reservation_line_ids")
def onchange_reservation_line_ids(self):
for record in self:
if record.reservation_id:
if not record.reservation_line_ids:
raise UserError(_('If you want drop the line, use the trash icon'))
raise UserError(_("If you want drop the line, use the trash icon"))
record.qty = len(record.reservation_line_ids)
record.description_dates = (record.reservation_line_ids[0].date).strftime(DEFAULT_SERVER_DATE_FORMAT) + ' - ' + \
((record.reservation_line_ids[-1].date) + \
timedelta(days=1)).strftime(DEFAULT_SERVER_DATE_FORMAT)
record.description_dates = (
(record.reservation_line_ids[0].date).strftime(
DEFAULT_SERVER_DATE_FORMAT
)
+ " - "
+ (
(record.reservation_line_ids[-1].date) + timedelta(days=1)
).strftime(DEFAULT_SERVER_DATE_FORMAT)
)
def invoice_line_create(self, invoice_id, qty):
""" Create an invoice line.
@@ -481,41 +597,55 @@ class LineAdvancePaymentInv(models.TransientModel):
:returns recordset of account.move.line created
"""
self.ensure_one()
invoice_lines = self.env['account.move.line']
invoice_lines = self.env["account.move.line"]
origin = self.reservation_id if self.reservation_id.id else self.service_id
product = self.product_id
account = product.property_account_income_id or product.categ_id.property_account_income_categ_id
account = (
product.property_account_income_id
or product.categ_id.property_account_income_categ_id
)
if not account:
raise UserError(_('Please define income account for this product: "%s" (id:%d) - or for its category: "%s".') %
(product.name, product.id, product.categ_id.name))
raise UserError(
_(
'Please define income account for this product: "%s" (id:%d) - or for its category: "%s".'
)
% (product.name, product.id, product.categ_id.name)
)
fpos = self.folio_id.fiscal_position_id or self.folio_id.partner_id.property_account_position_id
fpos = (
self.folio_id.fiscal_position_id
or self.folio_id.partner_id.property_account_position_id
)
if fpos:
account = fpos.map_account(account)
vals = {
'sequence': origin.sequence,
'invoice_origin': origin.name,
'price_unit': self.price_unit,
'quantity': self.qty,
'discount': self.discount,
'uom_id': product.uom_id.id,
'product_id': product.id or False,
'invoice_line_tax_ids': [(6, 0, origin.tax_ids.ids)],
'account_analytic_id': self.folio_id.analytic_account_id.id or False,
'analytic_tag_ids': [(6, 0, origin.analytic_tag_ids.ids)]
"sequence": origin.sequence,
"invoice_origin": origin.name,
"price_unit": self.price_unit,
"quantity": self.qty,
"discount": self.discount,
"uom_id": product.uom_id.id,
"product_id": product.id or False,
"invoice_line_tax_ids": [(6, 0, origin.tax_ids.ids)],
"account_analytic_id": self.folio_id.analytic_account_id.id or False,
"analytic_tag_ids": [(6, 0, origin.analytic_tag_ids.ids)],
}
if self.reservation_id:
vals.update({
'name': self.description + ' (' + self.description_dates + ')',
'move_id': invoice_id,
'reservation_ids': [(6, 0, [origin.id])],
'reservation_line_ids': [(6, 0, self.reservation_line_ids.ids)]
})
vals.update(
{
"name": self.description + " (" + self.description_dates + ")",
"move_id": invoice_id,
"reservation_ids": [(6, 0, [origin.id])],
"reservation_line_ids": [(6, 0, self.reservation_line_ids.ids)],
}
)
elif self.service_id:
vals.update({
'name': self.description,
'move_id': invoice_id,
'service_ids': [(6, 0, [origin.id])]
})
invoice_lines |= self.env['account.move.line'].create(vals)
vals.update(
{
"name": self.description,
"move_id": invoice_id,
"service_ids": [(6, 0, [origin.id])],
}
)
invoice_lines |= self.env["account.move.line"].create(vals)
return invoice_lines

View File

@@ -1,99 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="view_folio_advance_payment_inv" model="ir.ui.view">
<field name="name">Invoice Orders</field>
<field name="model">folio.advance.payment.inv</field>
<field name="arch" type="xml">
<form string="Invoice Folio">
<record id="view_folio_advance_payment_inv" model="ir.ui.view">
<field name="name">Invoice Orders</field>
<field name="model">folio.advance.payment.inv</field>
<field name="arch" type="xml">
<form string="Invoice Folio">
<group>
<group>
<group>
<field name="partner_invoice_id" />
<field
name="count"
invisible="[('count','=',1)]"
readonly="True"
/>
<field
name="advance_payment_method"
class="oe_inline"
widget="radio"
attrs="{'invisible': [('count','&gt;',1)]}"
/>
<field
name="product_id"
string="Down Payment Product"
context="{'search_default_services': 1, 'default_type': 'service', 'default_invoice_policy': 'order'}"
class="oe_inline"
attrs="{'invisible': 1}"
/>
<label
for="amount"
attrs="{'invisible': [('advance_payment_method', 'not in', ('fixed','percentage'))]}"
/>
<div
attrs="{'invisible': [('advance_payment_method', 'not in', ('fixed','percentage'))]}"
>
<field
name="amount"
attrs="{'required': [('advance_payment_method', 'in', ('fixed','percentage'))]}"
class="oe_inline"
widget="monetary"
/>
<label
for=""
string="%%"
attrs="{'invisible': [('advance_payment_method', '!=', 'percentage')]}"
class="oe_inline"
/>
</div>
<field
name="deposit_account_id"
class="oe_inline"
attrs="{'invisible': ['|', ('advance_payment_method', 'not in', ('fixed', 'percentage')), ('product_id', '!=', False)]}"
groups="account.group_account_manager"
/>
<field
name="deposit_taxes_id"
class="oe_inline"
widget="many2many_tags"
domain="[('type_tax_use','=','sale')]"
attrs="{'invisible': ['|', ('advance_payment_method', 'not in', ('fixed', 'percentage')), ('product_id', '!=', False)]}"
/>
</group>
<group>
<field
name="group_folios"
string="Add Folios"
attrs="{'invisible': [('advance_payment_method', 'in', ('fixed','percentage'))]}"
/>
</group>
<field
name="folio_ids"
attrs="{'invisible': [('group_folios', '=', False)]}"
domain="[('invoice_status','=','to invoice')]"
context="{'search_default_partner_invoice_id': partner_invoice_id}"
>
<tree
string="Folios"
editable="bottom"
decoration-danger="partner_invoice_id != parent.partner_invoice_id"
>
<field name="partner_invoice_id" />
<field name="count" invisible="[('count','=',1)]" readonly="True"/>
<field name="advance_payment_method" class="oe_inline" widget="radio"
attrs="{'invisible': [('count','&gt;',1)]}"/>
<field name="product_id" string="Down Payment Product"
context="{'search_default_services': 1, 'default_type': 'service', 'default_invoice_policy': 'order'}" class="oe_inline"
attrs="{'invisible': 1}"/>
<label for="amount" attrs="{'invisible': [('advance_payment_method', 'not in', ('fixed','percentage'))]}"/>
<div attrs="{'invisible': [('advance_payment_method', 'not in', ('fixed','percentage'))]}">
<field name="amount"
attrs="{'required': [('advance_payment_method', 'in', ('fixed','percentage'))]}" class="oe_inline" widget="monetary"/>
<label for="" string="%%"
attrs="{'invisible': [('advance_payment_method', '!=', 'percentage')]}" class="oe_inline"/>
</div>
<field name="deposit_account_id" class="oe_inline"
attrs="{'invisible': ['|', ('advance_payment_method', 'not in', ('fixed', 'percentage')), ('product_id', '!=', False)]}" groups="account.group_account_manager"/>
<field name="deposit_taxes_id" class="oe_inline" widget="many2many_tags"
domain="[('type_tax_use','=','sale')]"
attrs="{'invisible': ['|', ('advance_payment_method', 'not in', ('fixed', 'percentage')), ('product_id', '!=', False)]}"/>
</group>
<group>
<field name="group_folios" string="Add Folios"
attrs="{'invisible': [('advance_payment_method', 'in', ('fixed','percentage'))]}"/>
</group>
<field name="folio_ids"
attrs="{'invisible': [('group_folios', '=', False)]}"
domain="[('invoice_status','=','to invoice')]"
context="{'search_default_partner_invoice_id': partner_invoice_id}"
>
<tree string="Folios" editable="bottom"
decoration-danger="partner_invoice_id != parent.partner_invoice_id">
<field name="partner_invoice_id" />
<field name="name" />
<field name="state" />
<field name="pending_amount" />
<field name="amount_total" />
</tree>
</field>
<field name="reservation_ids" widget="many2many_tags"
domain="[('folio_id', 'in', folio_ids)]"
attrs="{'invisible': [('advance_payment_method', 'in', ('fixed','percentage'))]}"/>
</group>
<group>
<field name="line_ids" attrs="{'invisible': [('advance_payment_method', 'in', ('fixed','percentage'))]}"
nolabel="1" >
<tree string="Lines" editable="bottom" create="false" >
<field name="product_id" invisible="1" />
<field name="price_room" invisible="1" />
<field name="reservation_id"
options="{'no_create': True,'no_open': True}"/>
<field name="service_id"
options="{'no_create': True,'no_open': True}"/>
<field name="description" />
<field name="description_dates" readonly="1" force_save="1"/>
<field name="reservation_line_ids"
widget="many2many_tags" string="Nights"
domain="[('reservation_id','=',reservation_id),
<field name="name" />
<field name="state" />
<field name="pending_amount" />
<field name="amount_total" />
</tree>
</field>
<field
name="reservation_ids"
widget="many2many_tags"
domain="[('folio_id', 'in', folio_ids)]"
attrs="{'invisible': [('advance_payment_method', 'in', ('fixed','percentage'))]}"
/>
</group>
<group>
<field
name="line_ids"
attrs="{'invisible': [('advance_payment_method', 'in', ('fixed','percentage'))]}"
nolabel="1"
>
<tree string="Lines" editable="bottom" create="false">
<field name="product_id" invisible="1" />
<field name="price_room" invisible="1" />
<field
name="reservation_id"
options="{'no_create': True,'no_open': True}"
/>
<field
name="service_id"
options="{'no_create': True,'no_open': True}"
/>
<field name="description" />
<field
name="description_dates"
readonly="1"
force_save="1"
/>
<field
name="reservation_line_ids"
widget="many2many_tags"
string="Nights"
domain="[('reservation_id','=',reservation_id),
('price','=', price_room)]"
options="{'no_create': True,'no_open': True}"/>
<field name="qty" />
<field name="price_unit" />
<field name="discount" />
<field name="price_total" />
</tree>
</field>
</group>
<group>
<field name="auto_invoice" />
</group>
<footer>
<button name="create_invoices" string="Create and View Invoices" type="object"
context="{'open_invoices': True}" class="btn-primary"/>
<button name="create_invoices" string="Create Invoices" type="object"
class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_view_folio_advance_payment_inv" model="ir.actions.act_window">
<field name="name">Invoice Order</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">folio.advance.payment.inv</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="groups_id" eval="[(4,ref('pms.group_pms_user'))]"/>
</record>
options="{'no_create': True,'no_open': True}"
/>
<field name="qty" />
<field name="price_unit" />
<field name="discount" />
<field name="price_total" />
</tree>
</field>
</group>
<group>
<field name="auto_invoice" />
</group>
<footer>
<button
name="create_invoices"
string="Create and View Invoices"
type="object"
context="{'open_invoices': True}"
class="btn-primary"
/>
<button
name="create_invoices"
string="Create Invoices"
type="object"
class="btn-primary"
/>
<button string="Cancel" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_view_folio_advance_payment_inv" model="ir.actions.act_window">
<field name="name">Invoice Order</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">folio.advance.payment.inv</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="groups_id" eval="[(4,ref('pms.group_pms_user'))]" />
</record>
</odoo>

View File

@@ -1,14 +1,15 @@
# Copyright 2017 Alexandre Díaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import timedelta
from odoo import models, fields, api, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
class MassiveChangesWizard(models.TransientModel):
_name = 'pms.wizard.massive.changes'
_description = 'Massive Changes'
_name = "pms.wizard.massive.changes"
_description = "Massive Changes"
# Default methods
@api.model
@@ -16,77 +17,119 @@ class MassiveChangesWizard(models.TransientModel):
return self.env.user.pms_property_id
# Fields declaration
pms_property_id = fields.Many2one('pms.property', 'Property', required=True, default=_get_default_pms_property)
pms_property_id = fields.Many2one(
"pms.property", "Property", required=True, default=_get_default_pms_property
)
pricelist_id = fields.Many2one(
'product.pricelist', 'Pricelist Plan',
domain="[('pricelist_type', '=', 'daily'), ('pms_property_ids.id', '=', context.get('pms_property_id'))]")
"product.pricelist",
"Pricelist Plan",
domain="[('pricelist_type', '=', 'daily'), ('pms_property_ids.id', '=', context.get('pms_property_id'))]",
)
restriction_id = fields.Many2one(
'pms.room.type.restriction', 'Restriction Plan',
domain="[('pms_property_id.id', '=', context.get('pms_property_id'))]")
"pms.room.type.restriction",
"Restriction Plan",
domain="[('pms_property_id.id', '=', context.get('pms_property_id'))]",
)
room_type_ids = fields.Many2many(
'pms.room.type', string="Room Types",
domain="[('pms_property_id.id', '=', context.get('pms_property_id'))]")
"pms.room.type",
string="Room Types",
domain="[('pms_property_id.id', '=', context.get('pms_property_id'))]",
)
section = fields.Selection([
('restrictions', 'Restrictions'),
('prices', 'Pricelist'),
], string='Section', default='prices')
date_start = fields.Date('Start Date', required=True)
date_end = fields.Date('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', 'Room Type'),
], string='Applied On', default='0')
section = fields.Selection(
[("restrictions", "Restrictions"), ("prices", "Pricelist"),],
string="Section",
default="prices",
)
date_start = fields.Date("Start Date", required=True)
date_end = fields.Date("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", "Room Type"),], string="Applied On", default="0"
)
# Restriction fields
change_min_stay = fields.Boolean(default=False, help="Mark for a massive change in this field.")
change_min_stay = fields.Boolean(
default=False, help="Mark for a massive change in this field."
)
min_stay = fields.Integer("Min. Stay")
change_min_stay_arrival = fields.Boolean(default=False, help="Mark for a massive change in this field.")
change_min_stay_arrival = fields.Boolean(
default=False, help="Mark for a massive change in this field."
)
min_stay_arrival = fields.Integer("Min. Stay Arrival")
change_max_stay = fields.Boolean(default=False, help="Mark for a massive change in this field.")
change_max_stay = fields.Boolean(
default=False, help="Mark for a massive change in this field."
)
max_stay = fields.Integer("Max. Stay")
change_max_stay_arrival = fields.Boolean(default=False, help="Mark for a massive change in this field.")
change_max_stay_arrival = fields.Boolean(
default=False, help="Mark for a massive change in this field."
)
max_stay_arrival = fields.Integer("Max. Stay Arrival")
change_closed = fields.Boolean(default=False, help="Mark for a massive change in this field.")
closed = fields.Boolean('Closed')
change_closed_departure = fields.Boolean(default=False, help="Mark for a massive change in this field.")
closed_departure = fields.Boolean('Closed Departure')
change_closed_arrival = fields.Boolean(default=False, help="Mark for a massive change in this field.")
closed_arrival = fields.Boolean('Closed Arrival')
change_closed = fields.Boolean(
default=False, help="Mark for a massive change in this field."
)
closed = fields.Boolean("Closed")
change_closed_departure = fields.Boolean(
default=False, help="Mark for a massive change in this field."
)
closed_departure = fields.Boolean("Closed Departure")
change_closed_arrival = fields.Boolean(
default=False, help="Mark for a massive change in this field."
)
closed_arrival = fields.Boolean("Closed Arrival")
# Pricelist fields
price = fields.Char('Price', help="Can use '+','-' \
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")
\t\t> Sets the price to 45",
)
# Constraints and onchanges
@api.constrains('pricelist_id')
@api.constrains("pricelist_id")
def _check_pricelist_id(self):
for record in self:
if record.pricelist_id.pricelist_type != 'daily':
raise ValidationError(_("A daily pricelist plan is required for massive changes.") + " " +
_("Please review the property configuration before proceed."))
if record.pricelist_id.pricelist_type != "daily":
raise ValidationError(
_("A daily pricelist plan is required for massive changes.")
+ " "
+ _("Please review the property configuration before proceed.")
)
@api.constrains('hotepms_property_idl_id')
@api.constrains("hotepms_property_idl_id")
def _check_pms_property_id(self):
for record in self:
if record.section == 'prices' and record.pricelist_id.pms_property_ids != record.pms_property_id:
raise ValidationError(_("Mismatch between property and pricelist plan.") + " " +
_("The pricelist plan does not belongs to the current property."))
if record.section == 'restriction' and record.restriction_id.pms_property_id != record.pms_property_id:
raise ValidationError(_("Mismatch between property and restriction plan.") + " " +
_("The restriction plan does not belongs to the current property."))
if (
record.section == "prices"
and record.pricelist_id.pms_property_ids != record.pms_property_id
):
raise ValidationError(
_("Mismatch between property and pricelist plan.")
+ " "
+ _("The pricelist plan does not belongs to the current property.")
)
if (
record.section == "restriction"
and record.restriction_id.pms_property_id != record.pms_property_id
):
raise ValidationError(
_("Mismatch between property and restriction plan.")
+ " "
+ _(
"The restriction plan does not belongs to the current property."
)
)
@api.onchange('date_start')
@api.onchange("date_start")
def onchange_date_start(self):
self.ensure_one()
self.date_end = self.date_start
@@ -97,28 +140,28 @@ class MassiveChangesWizard(models.TransientModel):
self.ensure_one()
vals = {}
if record.change_min_stay:
vals.update({'min_stay': record.min_stay})
vals.update({"min_stay": record.min_stay})
if record.change_min_stay_arrival:
vals.update({'min_stay_arrival': record.min_stay_arrival})
vals.update({"min_stay_arrival": record.min_stay_arrival})
if record.change_max_stay:
vals.update({'max_stay': record.max_stay})
vals.update({"max_stay": record.max_stay})
if record.change_max_stay_arrival:
vals.update({'max_stay_arrival': record.max_stay_arrival})
vals.update({"max_stay_arrival": record.max_stay_arrival})
if record.change_closed:
vals.update({'closed': record.closed})
vals.update({"closed": record.closed})
if record.change_closed_departure:
vals.update({'closed_departure': record.closed_departure})
vals.update({"closed_departure": record.closed_departure})
if record.change_closed_arrival:
vals.update({'closed_arrival': record.closed_arrival})
vals.update({"closed_arrival": record.closed_arrival})
return vals
@api.model
def _save_restrictions(self, ndate, room_types, record):
pms_room_type_re_it_obj = self.env['pms.room.type.restriction.item']
pms_room_type_re_it_obj = self.env["pms.room.type.restriction.item"]
domain = [
('date', '>=', ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)),
('date', '<=', ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)),
('restriction_id', '=', record.restriction_id.id),
("date", ">=", ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)),
("date", "<=", ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)),
("restriction_id", "=", record.restriction_id.id),
]
for room_type in room_types:
vals = self._get_restrictions_values(record)
@@ -126,103 +169,118 @@ class MassiveChangesWizard(models.TransientModel):
continue
rrest_item_ids = pms_room_type_re_it_obj.search(
domain+[('room_type_id', '=', room_type.id)])
domain + [("room_type_id", "=", room_type.id)]
)
if any(rrest_item_ids):
rrest_item_ids.write(vals)
else:
vals.update({
'date': ndate.strftime(DEFAULT_SERVER_DATE_FORMAT),
'restriction_id': record.restriction_id.id,
'room_type_id': room_type.id,
})
vals.update(
{
"date": ndate.strftime(DEFAULT_SERVER_DATE_FORMAT),
"restriction_id": record.restriction_id.id,
"room_type_id": room_type.id,
}
)
pms_room_type_re_it_obj.create(vals)
@api.model
def _save_prices(self, ndate, room_types, record):
product_pricelist_item_obj = self.env['product.pricelist.item']
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] == '%':
operation = "a"
if record.price[0] == "+" or record.price[0] == "-":
if record.price[-1] == "%":
price = float(record.price[1:-1])
operation = 'ap' if (record.price[0] == '+') else 'sp'
operation = "ap" if (record.price[0] == "+") else "sp"
else:
price = float(record.price[1:])
operation = 'a' if (record.price[0] == '+') else 's'
operation = "a" if (record.price[0] == "+") else "s"
else:
if record.price[-1] == '%':
if record.price[-1] == "%":
price = float(record.price[:-1])
operation = 'np'
operation = "np"
else:
price = float(record.price)
operation = 'n'
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'),
("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"),
]
for room_type in room_types:
prod_tmpl_id = room_type.product_id.product_tmpl_id
pricelist_item_ids = product_pricelist_item_obj.search(
domain+[('product_tmpl_id', '=', prod_tmpl_id.id)])
domain + [("product_tmpl_id", "=", prod_tmpl_id.id)]
)
if any(pricelist_item_ids):
if operation != 'n':
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})
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})
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,
})
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 _save(self, ndate, room_types, record):
if record.section == 'restrictions':
if record.section == "restrictions":
self._save_restrictions(ndate, room_types, record)
elif record.section == 'prices':
elif record.section == "prices":
self._save_prices(ndate, room_types, record)
def _do_massive_change(self):
pms_room_type_obj = self.env['pms.room.type']
pms_room_type_obj = self.env["pms.room.type"]
for record in self:
date_start_dt = fields.Date.from_string(record.date_start)
date_end_dt = fields.Date.from_string(record.date_end)
# Use min '1' for same date
diff_days = abs((date_end_dt - date_start_dt).days) + 1
wedays = (record.dmo, record.dtu, record.dwe, record.dth,
record.dfr, record.dsa, record.dsu)
wedays = (
record.dmo,
record.dtu,
record.dwe,
record.dth,
record.dfr,
record.dsa,
record.dsu,
)
# filter room types to the pricelist or restriction property
room_types = record.room_type_ids if record.applied_on == '1' \
else pms_room_type_obj.search([('pms_property_id', '=', record.pms_property_id.id)])
room_types = (
record.room_type_ids
if record.applied_on == "1"
else pms_room_type_obj.search(
[("pms_property_id", "=", record.pms_property_id.id)]
)
)
for i in range(0, diff_days):
ndate = date_start_dt + timedelta(days=i)
@@ -231,14 +289,12 @@ class MassiveChangesWizard(models.TransientModel):
self._save(ndate, room_types, record)
return True
def massive_change(self):
self._do_massive_change()
return {
"type": "ir.actions.do_nothing",
}
def massive_change_close(self):
self._do_massive_change()
return True
@@ -248,7 +304,5 @@ class MassiveChangesWizard(models.TransientModel):
def is_valid_date(self, chkdate):
self.ensure_one()
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])
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]

View File

@@ -1,81 +1,123 @@
<?xml version="1.0" ?>
<odoo>
<record model="ir.ui.view" id="view_pms_massive_changes_wizard">
<field name="name">pms.wizard.massive.changes</field>
<field name="model">pms.wizard.massive.changes</field>
<field name="arch" type="xml">
<form string="Massive Changes" >
<group>
<field name="pms_property_id" readonly="1" />
<field name="section" required="1" />
<field name="applied_on" required="1" />
<field name="room_type_ids" widget="many2many_tags"
attrs="{'invisible':[('applied_on', '!=', '1')], 'required':[('applied_on', '=', '1')]}"
options="{'no_create': True,'no_open': True}"
/>
</group>
<group colspan="8" col="8">
<field name="date_start" required="1" colspan="4"/>
<field name="date_end" required="1" colspan="4" />
<field name="dmo" />
<field name="dtu" />
<field name="dwe" />
<field name="dth" />
<field name="dfr" />
<field name="dsa" />
<field name="dsu" />
</group>
<!-- Restriction Fields -->
<group col="8" attrs="{'invisible':[('section', '!=', 'restrictions')]}">
<field name="restriction_id"
attrs="{'required':[('section', '=', 'restrictions')]}"
options="{'no_create': True,'no_open': True}"
colspan="8"
/>
<field colspan="2" name="change_min_stay" />
<field colspan="2" name="min_stay" attrs="{'readonly':[('change_min_stay', '=', False)]}" />
<field colspan="2" name="change_max_stay" />
<field colspan="2" name="max_stay" attrs="{'readonly':[('change_max_stay', '=', False)]}" />
<field colspan="2" name="change_min_stay_arrival" />
<field colspan="2" name="min_stay_arrival" attrs="{'readonly':[('change_min_stay_arrival', '=', False)]}" />
<field colspan="2" name="change_max_stay_arrival" />
<field colspan="2" name="max_stay_arrival" attrs="{'readonly':[('change_max_stay_arrival', '=', False)]}" />
<field colspan="2" name="change_closed" />
<field colspan="6" name="closed" attrs="{'readonly':[('change_closed', '=', False)]}" />
<field colspan="2" name="change_closed_departure" />
<field colspan="6" name="closed_departure" attrs="{'readonly':[('change_closed_departure', '=', False)]}" />
<field colspan="2" name="change_closed_arrival" />
<field colspan="6" name="closed_arrival" attrs="{'readonly':[('change_closed_arrival', '=', False)]}" />
</group>
<!-- Pricelist Fields -->
<group attrs="{'invisible':[('section', '!=', 'prices')]}">
<field name="pricelist_id"
attrs="{'required':[('section', '=', 'prices')]}"
options="{'no_create': True,'no_open': True}"
/>
<field name="price" attrs="{'required':[('section', '=', 'prices')]}"/>
</group>
<footer>
<button name="massive_change" string="Massive Change" type="object"
class="oe_highlight" />
<button name="massive_change_close" string="Massive Change &amp; Close" type="object"
class="oe_highlight" />
<record model="ir.ui.view" id="view_pms_massive_changes_wizard">
<field name="name">pms.wizard.massive.changes</field>
<field name="model">pms.wizard.massive.changes</field>
<field name="arch" type="xml">
<form string="Massive Changes">
<group>
<field name="pms_property_id" readonly="1" />
<field name="section" required="1" />
<field name="applied_on" required="1" />
<field
name="room_type_ids"
widget="many2many_tags"
attrs="{'invisible':[('applied_on', '!=', '1')], 'required':[('applied_on', '=', '1')]}"
options="{'no_create': True,'no_open': True}"
/>
</group>
<group colspan="8" col="8">
<field name="date_start" required="1" colspan="4" />
<field name="date_end" required="1" colspan="4" />
<field name="dmo" />
<field name="dtu" />
<field name="dwe" />
<field name="dth" />
<field name="dfr" />
<field name="dsa" />
<field name="dsu" />
</group>
<!-- Restriction Fields -->
<group
col="8"
attrs="{'invisible':[('section', '!=', 'restrictions')]}"
>
<field
name="restriction_id"
attrs="{'required':[('section', '=', 'restrictions')]}"
options="{'no_create': True,'no_open': True}"
colspan="8"
/>
<field colspan="2" name="change_min_stay" />
<field
colspan="2"
name="min_stay"
attrs="{'readonly':[('change_min_stay', '=', False)]}"
/>
<field colspan="2" name="change_max_stay" />
<field
colspan="2"
name="max_stay"
attrs="{'readonly':[('change_max_stay', '=', False)]}"
/>
<field colspan="2" name="change_min_stay_arrival" />
<field
colspan="2"
name="min_stay_arrival"
attrs="{'readonly':[('change_min_stay_arrival', '=', False)]}"
/>
<field colspan="2" name="change_max_stay_arrival" />
<field
colspan="2"
name="max_stay_arrival"
attrs="{'readonly':[('change_max_stay_arrival', '=', False)]}"
/>
<field colspan="2" name="change_closed" />
<field
colspan="6"
name="closed"
attrs="{'readonly':[('change_closed', '=', False)]}"
/>
<field colspan="2" name="change_closed_departure" />
<field
colspan="6"
name="closed_departure"
attrs="{'readonly':[('change_closed_departure', '=', False)]}"
/>
<field colspan="2" name="change_closed_arrival" />
<field
colspan="6"
name="closed_arrival"
attrs="{'readonly':[('change_closed_arrival', '=', False)]}"
/>
</group>
<!-- Pricelist Fields -->
<group attrs="{'invisible':[('section', '!=', 'prices')]}">
<field
name="pricelist_id"
attrs="{'required':[('section', '=', 'prices')]}"
options="{'no_create': True,'no_open': True}"
/>
<field
name="price"
attrs="{'required':[('section', '=', 'prices')]}"
/>
</group>
<footer>
<button
name="massive_change"
string="Massive Change"
type="object"
class="oe_highlight"
/>
<button
name="massive_change_close"
string="Massive Change &amp; Close"
type="object"
class="oe_highlight"
/>
or
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_pms_massive_change" model="ir.actions.act_window">
<field name="name">Massive Change</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pms.wizard.massive.changes</field>
<field name="view_id" ref="view_pms_massive_changes_wizard"/>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</form>
</field>
</record>
<record id="action_pms_massive_change" model="ir.actions.act_window">
<field name="name">Massive Change</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pms.wizard.massive.changes</field>
<field name="view_id" ref="view_pms_massive_changes_wizard" />
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>

View File

@@ -1,37 +1,39 @@
# Copyright 2017 Alexandre Díaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api
from openerp import api, fields, models
class MassivePriceChangeWizard(models.TransientModel):
_name = 'pms.wizard.massive.price.reservation.days'
_description = 'Massive Price Changes'
new_price = fields.Float('New Price', default=1, min=1)
change_price = fields.Boolean('Change Prices', default=False)
new_discount = fields.Float('New Discount', default=0, min=1)
change_discount = fields.Boolean('Change Discounts', default=False)
_name = "pms.wizard.massive.price.reservation.days"
_description = "Massive Price Changes"
new_price = fields.Float("New Price", default=1, min=1)
change_price = fields.Boolean("Change Prices", default=False)
new_discount = fields.Float("New Discount", default=0, min=1)
change_discount = fields.Boolean("Change Discounts", default=False)
def massive_price_change_days(self):
self.ensure_one()
pms_reservation_obj = self.env['pms.reservation']
reservation_id = pms_reservation_obj.browse(
self.env.context.get('active_id'))
pms_reservation_obj = self.env["pms.reservation"]
reservation_id = pms_reservation_obj.browse(self.env.context.get("active_id"))
if not reservation_id:
return False
cmds = []
for rline in reservation_id.reservation_line_ids:
cmds.append((
1,
rline.id,
{
'price': self.new_price if self.change_price == True else rline.price,
'discount': self.new_discount if self.change_discount == True else rline.discount
}
))
reservation_id.write({
'reservation_line_ids': cmds
})
cmds.append(
(
1,
rline.id,
{
"price": self.new_price
if self.change_price == True
else rline.price,
"discount": self.new_discount
if self.change_discount == True
else rline.discount,
},
)
)
reservation_id.write({"reservation_line_ids": cmds})
return True

View File

@@ -1,38 +1,48 @@
<?xml version="1.0" ?>
<odoo>
<record model="ir.ui.view" id="view_pms_massive_price_change_wizard">
<field name="name">pms.wizard.massive.price.reservation.days</field>
<field name="model">pms.wizard.massive.price.reservation.days</field>
<field name="arch" type="xml">
<form string="Massive Price Change" >
<group>
<field name="change_price"/>
<field name="new_price" required="1"
attrs="{'readonly':[('change_price','=', False)]}" />
</group>
<record model="ir.ui.view" id="view_pms_massive_price_change_wizard">
<field name="name">pms.wizard.massive.price.reservation.days</field>
<field name="model">pms.wizard.massive.price.reservation.days</field>
<field name="arch" type="xml">
<form string="Massive Price Change">
<group>
<field name="change_discount"/>
<field name="new_discount" required="1"
attrs="{'readonly':[('change_discount','=', False)]}" />
</group>
<footer>
<button name="massive_price_change_days" string="Massive Change" type="object"
class="oe_highlight" />
<field name="change_price" />
<field
name="new_price"
required="1"
attrs="{'readonly':[('change_price','=', False)]}"
/>
</group>
<group>
<field name="change_discount" />
<field
name="new_discount"
required="1"
attrs="{'readonly':[('change_discount','=', False)]}"
/>
</group>
<footer>
<button
name="massive_price_change_days"
string="Massive Change"
type="object"
class="oe_highlight"
/>
or
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_pms_massive_price_change_reservation_days" model="ir.actions.act_window">
<field name="name">Massive Price Change</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pms.wizard.massive.price.reservation.days</field>
<field name="view_id" ref="view_pms_massive_price_change_wizard"/>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</form>
</field>
</record>
<record
id="action_pms_massive_price_change_reservation_days"
model="ir.actions.act_window"
>
<field name="name">Massive Price Change</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pms.wizard.massive.price.reservation.days</field>
<field name="view_id" ref="view_pms_massive_price_change_wizard" />
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>

Some files were not shown because too many files have changed in this diff Show More