mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[IMP] Precommit
This commit is contained in:
36
.travis.yml
36
.travis.yml
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",],
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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."
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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.",
|
||||
)
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!")
|
||||
]
|
||||
|
||||
@@ -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.",
|
||||
)
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,}
|
||||
)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
.. [ This file is optional and contains additional credits, other than
|
||||
authors, contributors, and maintainers. ]
|
||||
authors, contributors, and maintainers. ]
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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. ]
|
||||
|
||||
- [ ]
|
||||
- [ ]
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<report
|
||||
|
||||
@@ -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>&nbsp;<span>on</span>&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>&nbsp;<span
|
||||
>on</span>&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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 <%s>' % (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 <%s>' % (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>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
|
||||
@@ -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": ""}
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from .common import TestHotel
|
||||
from odoo import fields
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
from .common import TestHotel
|
||||
|
||||
|
||||
class TestHotelProperty(TestHotel):
|
||||
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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', '<', (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', '<', (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', '<', (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', '<', (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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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','<=',0)]}">
|
||||
attrs="{'invisible': ['|',('pending_amount','<=',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','<=',0)]}"/>
|
||||
<field name="internal_comment" />
|
||||
<field
|
||||
name="credit_card_details"
|
||||
attrs="{'invisible':[('pending_amount','<=',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','<=',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','<=',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','<=',0)]}">
|
||||
<field name="return_ids"
|
||||
options="{'no_create': True}" />
|
||||
<page
|
||||
name="returns"
|
||||
string="Retun Payments"
|
||||
attrs="{'invisible': [('refund_amount','<=',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>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>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>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>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', '>', 0)]" />
|
||||
<filter
|
||||
name="to_invoice"
|
||||
string="To invoice"
|
||||
domain="[('invoice_status', '=', 'to invoice')]"
|
||||
/>
|
||||
<filter
|
||||
name="payment_pending"
|
||||
string="Payment Pending"
|
||||
domain="[('pending_amount', '>', 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>
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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', '>', 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', '>', context_today().strftime('%Y-%m-%d')),
|
||||
('date', '<', (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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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','>',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','>',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>
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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 & 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 & 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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user