mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[DEL] Cleanup
This commit is contained in:
@@ -1,97 +0,0 @@
|
||||
====================
|
||||
multi_pms_properties
|
||||
====================
|
||||
|
||||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
||||
:target: https://odoo-community.org/page/development-status
|
||||
:alt: Beta
|
||||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpms-lightgray.png?logo=github
|
||||
:target: https://github.com/OCA/pms/tree/14.0/multi_pms_properties
|
||||
:alt: OCA/pms
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/pms-14-0/pms-14-0-multi_pms_properties
|
||||
:alt: Translate me on Weblate
|
||||
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
|
||||
:target: https://runbot.odoo-community.org/runbot/293/14.0
|
||||
:alt: Try me on Runbot
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
Technical addon to support multiproperty in property management system (PMS).
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
To install this module, you only need to add it to your addons, and load it as
|
||||
a server-wide module.
|
||||
|
||||
This can be done with the ``server_wide_modules`` parameter in ``/etc/odoo.conf``
|
||||
or with the ``--load`` command-line parameter
|
||||
|
||||
``server_wide_modules = "multi_pms_properties"``
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
* Use the standard multicompany guidelines applied to pms.property:
|
||||
|
||||
``_check_pms_properties_auto like model attribute to autocheck on create/write``
|
||||
``check_pms_properties like field attribute to check relational record properties consistence``
|
||||
``This module not implement propety dependent fields``
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/pms/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed
|
||||
`feedback <https://github.com/OCA/pms/issues/new?body=module:%20multi_pms_properties%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
Do not contact contributors directly about support or help with technical issues.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Authors
|
||||
~~~~~~~
|
||||
|
||||
* Commit [Sun]
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* `Commit [Sun] <https://www.commitsun.com>`:
|
||||
|
||||
* Dario Lodeiros
|
||||
* Eric Antones
|
||||
* Sara Lago
|
||||
|
||||
Maintainers
|
||||
~~~~~~~~~~~
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.
|
||||
|
||||
This module is part of the `OCA/pms <https://github.com/OCA/pms/tree/14.0/multi_pms_properties>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
@@ -1,64 +0,0 @@
|
||||
# Copyright 2021 Dario Lodeiros
|
||||
# Copyright 2021 Eric Antones
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import logging
|
||||
|
||||
from odoo import fields
|
||||
from odoo.tools import config
|
||||
|
||||
from . import models
|
||||
|
||||
|
||||
def _description_domain(self, env):
|
||||
if self.check_company and not self.domain:
|
||||
if self.company_dependent:
|
||||
if self.comodel_name == "res.users":
|
||||
# user needs access to current company (self.env.company)
|
||||
return "[('company_ids', 'in', allowed_company_ids[0])]"
|
||||
else:
|
||||
return "[('company_id', 'in', [allowed_company_ids[0], False])]"
|
||||
else:
|
||||
# when using check_company=True on a field on 'res.company', the
|
||||
# company_id comes from the id of the current record
|
||||
cid = "id" if self.model_name == "res.company" else "company_id"
|
||||
if self.comodel_name == "res.users":
|
||||
# User allowed company ids = user.company_ids
|
||||
return f"['|', (not {cid}, '=', True), ('company_ids', 'in', [{cid}])]"
|
||||
else:
|
||||
return f"[('company_id', 'in', [{cid}, False])]"
|
||||
|
||||
if self.check_pms_properties and not self.domain:
|
||||
record = env[self.model_name]
|
||||
# Skip company_id domain to avoid domain multiproperty error in inherited views
|
||||
if (
|
||||
self.check_pms_properties
|
||||
and not self.domain
|
||||
and self.name not in ["company_id"]
|
||||
):
|
||||
if self.model_name == "pms.property":
|
||||
prop1 = "id"
|
||||
prop2 = f"[{prop1}]"
|
||||
elif "pms_property_id" in record._fields:
|
||||
prop1 = "pms_property_id"
|
||||
prop2 = f"[{prop1}]"
|
||||
else:
|
||||
prop1 = prop2 = "pms_property_ids"
|
||||
coprop = (
|
||||
"pms_property_id"
|
||||
if "pms_property_id" in env[self.comodel_name]._fields
|
||||
else "pms_property_ids"
|
||||
)
|
||||
return f"['|', '|', \
|
||||
(not {prop1}, '=', True), \
|
||||
('{coprop}', 'in', {prop2}), \
|
||||
('{coprop}', '=', False)]"
|
||||
|
||||
return self.domain(env[self.model_name]) if callable(self.domain) else self.domain
|
||||
|
||||
|
||||
if "multi_pms_properties" in config.get("server_wide_modules"):
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger.info("monkey patching fields._Relational")
|
||||
|
||||
fields._Relational.check_pms_properties = False
|
||||
fields._Relational._description_domain = _description_domain
|
||||
@@ -1,17 +0,0 @@
|
||||
# © 2013 Therp BV
|
||||
# © 2014 ACSONE SA/NV
|
||||
# Copyright 2018 Quartile Limited
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
{
|
||||
"name": "multi_pms_properties",
|
||||
"summary": "Multi Properties Manager",
|
||||
"version": "14.0.1.0.0",
|
||||
"website": "https://github.com/OCA/pms",
|
||||
"author": "Commit [Sun], Odoo Community Association (OCA)",
|
||||
"license": "AGPL-3",
|
||||
"category": "Pms",
|
||||
"depends": ["base"],
|
||||
"auto_install": False,
|
||||
"installable": True,
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * multi_pms_properties
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 14.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: multi_pms_properties
|
||||
#: code:addons/multi_pms_properties/models.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"- %(record)r belongs to properties %(pms_properties)r and\n"
|
||||
" %(field)r (%(fname)s: %(values)s) belongs to another properties."
|
||||
msgstr ""
|
||||
|
||||
#. module: multi_pms_properties
|
||||
#: code:addons/multi_pms_properties/models.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"- Record is properties %(pms_properties)r and %(field)r\n"
|
||||
" (%(fname)s: %(values)s) belongs to another properties."
|
||||
msgstr ""
|
||||
|
||||
#. module: multi_pms_properties
|
||||
#: model:ir.model,name:multi_pms_properties.model_base
|
||||
msgid "Base"
|
||||
msgstr ""
|
||||
|
||||
#. module: multi_pms_properties
|
||||
#: code:addons/multi_pms_properties/models.py:0
|
||||
#, python-format
|
||||
msgid "Incompatible properties on records:"
|
||||
msgstr ""
|
||||
|
||||
#. module: multi_pms_properties
|
||||
#: code:addons/multi_pms_properties/models.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot establish a company other than the one with the established "
|
||||
"properties"
|
||||
msgstr ""
|
||||
@@ -1,186 +0,0 @@
|
||||
# Copyright 2021 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class BaseModel(models.AbstractModel):
|
||||
_inherit = "base"
|
||||
_check_pms_properties_auto = False
|
||||
"""On write and create, call ``_check_pms_properties_auto`` to ensure properties
|
||||
consistency on the relational fields having ``check_pms_properties=True``
|
||||
as attribute.
|
||||
"""
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
records = super(BaseModel, self).create(vals_list)
|
||||
if self._check_pms_properties_auto:
|
||||
records._check_pms_properties()
|
||||
return records
|
||||
|
||||
def write(self, vals):
|
||||
res = super(BaseModel, self).write(vals)
|
||||
check_pms_properties = False
|
||||
for fname in vals:
|
||||
field = self._fields.get(fname)
|
||||
if (
|
||||
fname == "pms_property_id"
|
||||
or fname == "pms_property_ids"
|
||||
or fname == "company_id"
|
||||
or (field.relational and field.check_pms_properties)
|
||||
):
|
||||
check_pms_properties = True
|
||||
if res and check_pms_properties and self._check_pms_properties_auto:
|
||||
self._check_pms_properties()
|
||||
return res
|
||||
|
||||
def _check_pms_properties(self, fnames=None):
|
||||
"""Check the properties of the values of the given field names.
|
||||
|
||||
:param list fnames: names of relational fields to check
|
||||
:raises UserError: if the `pms_properties` of the value of any field is not
|
||||
in `[False, self.pms_property_id]` (or `self` if
|
||||
:class:`~odoo.addons.base.models.pms_property`).
|
||||
|
||||
For :class:`~odoo.addons.base.models.res_users` relational fields,
|
||||
verifies record company is in `company_ids` fields.
|
||||
|
||||
User with main pms property A, having access to pms property A and B, could be
|
||||
assigned or linked to records in property B.
|
||||
"""
|
||||
if fnames is None:
|
||||
fnames = self._fields
|
||||
|
||||
regular_fields = self._get_regular_fields(fnames)
|
||||
|
||||
if not regular_fields:
|
||||
return
|
||||
|
||||
inconsistencies = self._check_inconsistencies(regular_fields)
|
||||
|
||||
if inconsistencies:
|
||||
lines = [_("Incompatible properties on records:")]
|
||||
property_msg = _(
|
||||
"""- Record is properties %(pms_properties)r and %(field)r
|
||||
(%(fname)s: %(values)s) belongs to another properties."""
|
||||
)
|
||||
record_msg = _(
|
||||
"""- %(record)r belongs to properties %(pms_properties)r and
|
||||
%(field)r (%(fname)s: %(values)s) belongs to another properties."""
|
||||
)
|
||||
for record, name, corecords in inconsistencies[:5]:
|
||||
if record._name == "pms.property":
|
||||
msg, pms_properties = property_msg, record
|
||||
else:
|
||||
msg, pms_properties = (
|
||||
record_msg,
|
||||
record.pms_property_id.name
|
||||
if "pms_property_id" in record
|
||||
else ", ".join(repr(p.name) for p in record.pms_property_ids),
|
||||
)
|
||||
field = self.env["ir.model.fields"]._get(self._name, name)
|
||||
lines.append(
|
||||
msg
|
||||
% {
|
||||
"record": record.display_name,
|
||||
"pms_properties": pms_properties,
|
||||
"field": field.field_description,
|
||||
"fname": field.name,
|
||||
"values": ", ".join(
|
||||
repr(rec.display_name) for rec in corecords
|
||||
),
|
||||
}
|
||||
)
|
||||
raise UserError("\n".join(lines))
|
||||
|
||||
def _get_regular_fields(self, fnames):
|
||||
regular_fields = []
|
||||
for name in fnames:
|
||||
field = self._fields[name]
|
||||
if (
|
||||
field.relational
|
||||
and field.check_pms_properties
|
||||
and (
|
||||
"pms_property_id" in self.env[field.comodel_name]
|
||||
or "pms_property_ids" in self.env[field.comodel_name]
|
||||
)
|
||||
):
|
||||
regular_fields.append(name)
|
||||
return regular_fields
|
||||
|
||||
def _check_inconsistencies(self, regular_fields):
|
||||
inconsistencies = []
|
||||
for record in self:
|
||||
pms_properties = False
|
||||
if record._name == "pms.property":
|
||||
pms_properties = record
|
||||
if "pms_property_id" in record:
|
||||
pms_properties = record.pms_property_id
|
||||
if "pms_property_ids" in record:
|
||||
pms_properties = record.pms_property_ids
|
||||
# Check the property & company consistence
|
||||
if "company_id" in self._fields:
|
||||
if record.company_id and pms_properties:
|
||||
property_companies = pms_properties.mapped("company_id.id")
|
||||
if (
|
||||
len(property_companies) > 1
|
||||
or record.company_id.id != property_companies[0]
|
||||
):
|
||||
raise UserError(
|
||||
_(
|
||||
"You cannot establish a company other than "
|
||||
"the one with the established properties"
|
||||
)
|
||||
)
|
||||
# Check verifies that all
|
||||
# records linked via relation fields are compatible
|
||||
# with the properties of the origin document,
|
||||
for name in regular_fields:
|
||||
field = self._fields[name]
|
||||
co_pms_properties = False
|
||||
|
||||
corecord = record.sudo()[name]
|
||||
# TODO:res.users management properties
|
||||
if "pms_property_id" in corecord:
|
||||
co_pms_properties = corecord.pms_property_id
|
||||
if "pms_property_ids" in corecord:
|
||||
co_pms_properties = corecord.pms_property_ids
|
||||
if (
|
||||
# There is an inconsistency if:
|
||||
#
|
||||
# - Record has properties and corecord too and
|
||||
# there's no match between them:
|
||||
# X Pms_room_class with Property1 cannot contain
|
||||
# Pms_room with property2 X
|
||||
#
|
||||
# - Record has a relation one2many with corecord and
|
||||
# corecord properties aren't included in record properties
|
||||
# or what is the same, subtraction between corecord properties
|
||||
# and record properties must be False:
|
||||
# X Pricelist with Prop1 and Prop2 cannot contain
|
||||
# Pricelist_item with Prop1 and Prop3 X
|
||||
# X Pricelist with Prop1 and Prop2 cannot contain
|
||||
# Pricelist_item with Prop1, Prop2 and Prop3 X
|
||||
# -In case that record has a relation many2one
|
||||
# with corecord the condition is the same as avobe
|
||||
(
|
||||
pms_properties
|
||||
and co_pms_properties
|
||||
and (not pms_properties & co_pms_properties)
|
||||
)
|
||||
or (
|
||||
corecord
|
||||
and field.type == "one2many"
|
||||
and pms_properties
|
||||
and (co_pms_properties - pms_properties)
|
||||
)
|
||||
or (
|
||||
field.type == "many2one"
|
||||
and co_pms_properties
|
||||
and ((pms_properties - co_pms_properties) or not pms_properties)
|
||||
)
|
||||
):
|
||||
inconsistencies.append((record, name, corecord))
|
||||
return inconsistencies
|
||||
@@ -1,5 +0,0 @@
|
||||
* `Commit [Sun] <https://www.commitsun.com>`:
|
||||
|
||||
* Dario Lodeiros
|
||||
* Eric Antones
|
||||
* Sara Lago
|
||||
@@ -1 +0,0 @@
|
||||
Technical addon to support multiproperty in property management system (PMS).
|
||||
@@ -1,7 +0,0 @@
|
||||
To install this module, you only need to add it to your addons, and load it as
|
||||
a server-wide module.
|
||||
|
||||
This can be done with the ``server_wide_modules`` parameter in ``/etc/odoo.conf``
|
||||
or with the ``--load`` command-line parameter
|
||||
|
||||
``server_wide_modules = "multi_pms_properties"``
|
||||
@@ -1,5 +0,0 @@
|
||||
* Use the standard multicompany guidelines applied to pms.property:
|
||||
|
||||
``_check_pms_properties_auto like model attribute to autocheck on create/write``
|
||||
``check_pms_properties like field attribute to check relational record properties consistence``
|
||||
``This module not implement propety dependent fields``
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.2 KiB |
@@ -1,444 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
|
||||
<title>multi_pms_properties</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
|
||||
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
.subscript {
|
||||
vertical-align: sub;
|
||||
font-size: smaller }
|
||||
|
||||
.superscript {
|
||||
vertical-align: super;
|
||||
font-size: smaller }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title, .code .error {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left, table.align-left {
|
||||
clear: left ;
|
||||
float: left ;
|
||||
margin-right: 1em }
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right, table.align-right {
|
||||
clear: right ;
|
||||
float: right ;
|
||||
margin-left: 1em }
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left }
|
||||
|
||||
.align-center {
|
||||
clear: both ;
|
||||
text-align: center }
|
||||
|
||||
.align-right {
|
||||
text-align: right }
|
||||
|
||||
/* reset inner alignment in figures */
|
||||
div.align-right {
|
||||
text-align: inherit }
|
||||
|
||||
/* div.align-center * { */
|
||||
/* text-align: left } */
|
||||
|
||||
.align-top {
|
||||
vertical-align: top }
|
||||
|
||||
.align-middle {
|
||||
vertical-align: middle }
|
||||
|
||||
.align-bottom {
|
||||
vertical-align: bottom }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font: inherit }
|
||||
|
||||
pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
pre.code .ln { color: grey; } /* line numbers */
|
||||
pre.code, code { background-color: #eeeeee }
|
||||
pre.code .comment, code .comment { color: #5C6576 }
|
||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||
pre.code .literal.string, code .literal.string { color: #0C5404 }
|
||||
pre.code .name.builtin, code .name.builtin { color: #352B84 }
|
||||
pre.code .deleted, code .deleted { background-color: #DEB0A1}
|
||||
pre.code .inserted, code .inserted { background-color: #A3D289}
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
/* "booktabs" style (no vertical lines) */
|
||||
table.docutils.booktabs {
|
||||
border: 0px;
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.docutils.booktabs * {
|
||||
border: 0px;
|
||||
}
|
||||
table.docutils.booktabs th {
|
||||
border-bottom: thin solid;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="multi-pms-properties">
|
||||
<h1 class="title">multi_pms_properties</h1>
|
||||
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/pms/tree/14.0/multi_pms_properties"><img alt="OCA/pms" src="https://img.shields.io/badge/github-OCA%2Fpms-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/pms-14-0/pms-14-0-multi_pms_properties"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/293/14.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
|
||||
<p>Technical addon to support multiproperty in property management system (PMS).</p>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#installation" id="id1">Installation</a></li>
|
||||
<li><a class="reference internal" href="#usage" id="id2">Usage</a></li>
|
||||
<li><a class="reference internal" href="#bug-tracker" id="id3">Bug Tracker</a></li>
|
||||
<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul>
|
||||
<li><a class="reference internal" href="#authors" id="id5">Authors</a></li>
|
||||
<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="id7">Maintainers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="installation">
|
||||
<h1><a class="toc-backref" href="#id1">Installation</a></h1>
|
||||
<p>To install this module, you only need to add it to your addons, and load it as
|
||||
a server-wide module.</p>
|
||||
<p>This can be done with the <tt class="docutils literal">server_wide_modules</tt> parameter in <tt class="docutils literal">/etc/odoo.conf</tt>
|
||||
or with the <tt class="docutils literal"><span class="pre">--load</span></tt> command-line parameter</p>
|
||||
<p><tt class="docutils literal">server_wide_modules = "multi_pms_properties"</tt></p>
|
||||
</div>
|
||||
<div class="section" id="usage">
|
||||
<h1><a class="toc-backref" href="#id2">Usage</a></h1>
|
||||
<ul>
|
||||
<li><p class="first">Use the standard multicompany guidelines applied to pms.property:</p>
|
||||
<p><tt class="docutils literal">_check_pms_properties_auto like model attribute to autocheck on create/write</tt>
|
||||
<tt class="docutils literal">check_pms_properties like field attribute to check relational record properties consistence</tt>
|
||||
<tt class="docutils literal">This module not implement propety dependent fields</tt></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="bug-tracker">
|
||||
<h1><a class="toc-backref" href="#id3">Bug Tracker</a></h1>
|
||||
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/pms/issues">GitHub Issues</a>.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed
|
||||
<a class="reference external" href="https://github.com/OCA/pms/issues/new?body=module:%20multi_pms_properties%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
|
||||
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
||||
</div>
|
||||
<div class="section" id="credits">
|
||||
<h1><a class="toc-backref" href="#id4">Credits</a></h1>
|
||||
<div class="section" id="authors">
|
||||
<h2><a class="toc-backref" href="#id5">Authors</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Commit [Sun]</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributors">
|
||||
<h2><a class="toc-backref" href="#id6">Contributors</a></h2>
|
||||
<ul class="simple">
|
||||
<li><cite>Commit [Sun] <https://www.commitsun.com></cite>:<ul>
|
||||
<li>Dario Lodeiros</li>
|
||||
<li>Eric Antones</li>
|
||||
<li>Sara Lago</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
<h2><a class="toc-backref" href="#id7">Maintainers</a></h2>
|
||||
<p>This module is maintained by the OCA.</p>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
|
||||
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.</p>
|
||||
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/pms/tree/14.0/multi_pms_properties">OCA/pms</a> project on GitHub.</p>
|
||||
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +0,0 @@
|
||||
# Copyright 2021 Eric Antones
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import common
|
||||
from . import test_multi_pms_properties
|
||||
@@ -1,20 +0,0 @@
|
||||
# Copyright 2021 Eric Antones
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
def setup_test_model(env, model_clses):
|
||||
for model_cls in model_clses:
|
||||
model_cls._build_model(env.registry, env.cr)
|
||||
|
||||
env.registry.setup_models(env.cr)
|
||||
env.registry.init_models(
|
||||
env.cr,
|
||||
[model_cls._name for model_cls in model_clses],
|
||||
dict(env.context, update_custom_fields=True),
|
||||
)
|
||||
|
||||
|
||||
def teardown_test_model(env, model_clses):
|
||||
for model_cls in model_clses:
|
||||
del env.registry.models[model_cls._name]
|
||||
env.registry.setup_models(env.cr)
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright 2021 Eric Antones
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ParentTester(models.Model):
|
||||
_name = "pms.parent.tester"
|
||||
|
||||
name = fields.Char(required=True)
|
||||
|
||||
|
||||
class ChildTester(models.Model):
|
||||
_name = "pms.child.tester"
|
||||
|
||||
name = fields.Char(required=True)
|
||||
parent_id = fields.Many2one("pms.parent.tester", check_pms_properties=True)
|
||||
@@ -1,41 +0,0 @@
|
||||
# Copyright 2021 Eric Antones
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import logging
|
||||
|
||||
from odoo.tests import common
|
||||
|
||||
from .common import setup_test_model # , teardown_test_model
|
||||
from .multi_pms_properties_tester import ChildTester, ParentTester
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@common.tagged("-at_install", "post_install")
|
||||
class TestMultiPMSProperties(common.SavepointCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestMultiPMSProperties, cls).setUpClass()
|
||||
model_classes = [ParentTester, ChildTester]
|
||||
setup_test_model(cls.env, model_classes)
|
||||
for mdl_cls in model_classes:
|
||||
tester_model = cls.env["ir.model"].search([("model", "=", mdl_cls._name)])
|
||||
# Access record
|
||||
cls.env["ir.model.access"].create(
|
||||
{
|
||||
"name": "access.%s" % mdl_cls._name,
|
||||
"model_id": tester_model.id,
|
||||
"perm_read": 1,
|
||||
"perm_write": 1,
|
||||
"perm_create": 1,
|
||||
"perm_unlink": 1,
|
||||
}
|
||||
)
|
||||
|
||||
# @classmethod
|
||||
# def tearDownClass(cls):
|
||||
# teardown_test_model(cls.env, [ParentTester])
|
||||
# super(TestMultiPMSProperties, cls).tearDownClass()
|
||||
|
||||
# def test_exist_attribute(self):
|
||||
# parent = self.env["pms.parent.tester"].create({"name": "parent test"})
|
||||
@@ -1,81 +0,0 @@
|
||||
==============================
|
||||
Payment Acquirer Multiproperty
|
||||
==============================
|
||||
|
||||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
||||
:target: https://odoo-community.org/page/development-status
|
||||
:alt: Beta
|
||||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpms-lightgray.png?logo=github
|
||||
:target: https://github.com/OCA/pms/tree/14.0/payment_acquirer_multi_pms_properties
|
||||
:alt: OCA/pms
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/pms-14-0/pms-14-0-payment_acquirer_multi_pms_properties
|
||||
:alt: Translate me on Weblate
|
||||
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
|
||||
:target: https://runbot.odoo-community.org/runbot/293/14.0
|
||||
:alt: Try me on Runbot
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
Set the pms property in the payment acquirer to filter on website payments
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Sets one or more properties in the payment acquirer so that payment method is only available for documents of those properties.
|
||||
If you leave it blank, it will be available to everyone.
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/pms/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed
|
||||
`feedback <https://github.com/OCA/pms/issues/new?body=module:%20payment_acquirer_multi_pms_properties%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
Do not contact contributors directly about support or help with technical issues.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Authors
|
||||
~~~~~~~
|
||||
|
||||
* Commit [Sun]
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* `Commit [Sun] <https://www.commitsun.com>`:
|
||||
|
||||
* Dario Lodeiros
|
||||
|
||||
Maintainers
|
||||
~~~~~~~~~~~
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.
|
||||
|
||||
This module is part of the `OCA/pms <https://github.com/OCA/pms/tree/14.0/payment_acquirer_multi_pms_properties>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
@@ -1,2 +0,0 @@
|
||||
from . import models
|
||||
from . import controllers
|
||||
@@ -1,18 +0,0 @@
|
||||
# Copyright 2009-2020 Noviat.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
"name": "Payment Acquirer Multiproperty",
|
||||
"author": "Commit [Sun], Odoo Community Association (OCA)",
|
||||
"website": "https://github.com/OCA/pms",
|
||||
"category": "Generic Modules/Property Management System",
|
||||
"version": "14.0.1.0.1",
|
||||
"license": "AGPL-3",
|
||||
"depends": [
|
||||
"pms",
|
||||
],
|
||||
"data": [
|
||||
"views/payment_acquirer.xml",
|
||||
],
|
||||
"installable": True,
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import portal
|
||||
@@ -1,23 +0,0 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.addons.account.controllers.portal import PortalAccount
|
||||
|
||||
|
||||
class PortalAccount(PortalAccount):
|
||||
def _invoice_get_page_view_values(self, invoice, access_token, **kwargs):
|
||||
"""
|
||||
Override to add the pms property filter
|
||||
"""
|
||||
values = super(PortalAccount, self)._invoice_get_page_view_values(
|
||||
invoice, access_token, **kwargs
|
||||
)
|
||||
for acquirer in values["acquirers"]:
|
||||
if (
|
||||
acquirer.pms_property_ids
|
||||
and invoice.pms_property_id.id not in acquirer.pms_property_ids.ids
|
||||
):
|
||||
values["acquirers"] -= acquirer
|
||||
for pms in values["pms"]:
|
||||
if pms.acquirer_id not in values["acquirers"].ids:
|
||||
values["pms"] -= pms
|
||||
return values
|
||||
@@ -1,45 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * payment_acquirer_multi_pms_properties
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 14.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: payment_acquirer_multi_pms_properties
|
||||
#: model:ir.model.fields,field_description:payment_acquirer_multi_pms_properties.field_payment_acquirer__display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: payment_acquirer_multi_pms_properties
|
||||
#: model:ir.model.fields,field_description:payment_acquirer_multi_pms_properties.field_payment_acquirer__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: payment_acquirer_multi_pms_properties
|
||||
#: model:ir.model.fields,field_description:payment_acquirer_multi_pms_properties.field_payment_acquirer____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr ""
|
||||
|
||||
#. module: payment_acquirer_multi_pms_properties
|
||||
#: model:ir.model,name:payment_acquirer_multi_pms_properties.model_payment_acquirer
|
||||
msgid "Payment Acquirer"
|
||||
msgstr ""
|
||||
|
||||
#. module: payment_acquirer_multi_pms_properties
|
||||
#: model:ir.model.fields,field_description:payment_acquirer_multi_pms_properties.field_payment_acquirer__pms_property_ids
|
||||
msgid "Properties"
|
||||
msgstr ""
|
||||
|
||||
#. module: payment_acquirer_multi_pms_properties
|
||||
#: model:ir.model.fields,help:payment_acquirer_multi_pms_properties.field_payment_acquirer__pms_property_ids
|
||||
msgid ""
|
||||
"Properties with access to the element; if not set, all properties can access"
|
||||
msgstr ""
|
||||
@@ -1 +0,0 @@
|
||||
from . import payment_acquirer
|
||||
@@ -1,21 +0,0 @@
|
||||
# Copyright 2009-2020 Noviat
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class PaymentAcquirer(models.Model):
|
||||
_inherit = "payment.acquirer"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
required=False,
|
||||
comodel_name="pms.property",
|
||||
relation="pms_acquirer_property_rel",
|
||||
column1="acquirer_id",
|
||||
column2="property_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
@@ -1,3 +0,0 @@
|
||||
* `Commit [Sun] <https://www.commitsun.com>`:
|
||||
|
||||
* Dario Lodeiros
|
||||
@@ -1 +0,0 @@
|
||||
Set the pms property in the payment acquirer to filter on website payments
|
||||
@@ -1,2 +0,0 @@
|
||||
Sets one or more properties in the payment acquirer so that payment method is only available for documents of those properties.
|
||||
If you leave it blank, it will be available to everyone.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.2 KiB |
@@ -1,428 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
|
||||
<title>Payment Acquirer Multiproperty</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
|
||||
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
.subscript {
|
||||
vertical-align: sub;
|
||||
font-size: smaller }
|
||||
|
||||
.superscript {
|
||||
vertical-align: super;
|
||||
font-size: smaller }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title, .code .error {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left, table.align-left {
|
||||
clear: left ;
|
||||
float: left ;
|
||||
margin-right: 1em }
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right, table.align-right {
|
||||
clear: right ;
|
||||
float: right ;
|
||||
margin-left: 1em }
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left }
|
||||
|
||||
.align-center {
|
||||
clear: both ;
|
||||
text-align: center }
|
||||
|
||||
.align-right {
|
||||
text-align: right }
|
||||
|
||||
/* reset inner alignment in figures */
|
||||
div.align-right {
|
||||
text-align: inherit }
|
||||
|
||||
/* div.align-center * { */
|
||||
/* text-align: left } */
|
||||
|
||||
.align-top {
|
||||
vertical-align: top }
|
||||
|
||||
.align-middle {
|
||||
vertical-align: middle }
|
||||
|
||||
.align-bottom {
|
||||
vertical-align: bottom }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font: inherit }
|
||||
|
||||
pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
pre.code .ln { color: grey; } /* line numbers */
|
||||
pre.code, code { background-color: #eeeeee }
|
||||
pre.code .comment, code .comment { color: #5C6576 }
|
||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||
pre.code .literal.string, code .literal.string { color: #0C5404 }
|
||||
pre.code .name.builtin, code .name.builtin { color: #352B84 }
|
||||
pre.code .deleted, code .deleted { background-color: #DEB0A1}
|
||||
pre.code .inserted, code .inserted { background-color: #A3D289}
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
/* "booktabs" style (no vertical lines) */
|
||||
table.docutils.booktabs {
|
||||
border: 0px;
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.docutils.booktabs * {
|
||||
border: 0px;
|
||||
}
|
||||
table.docutils.booktabs th {
|
||||
border-bottom: thin solid;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="payment-acquirer-multiproperty">
|
||||
<h1 class="title">Payment Acquirer Multiproperty</h1>
|
||||
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/pms/tree/14.0/payment_acquirer_multi_pms_properties"><img alt="OCA/pms" src="https://img.shields.io/badge/github-OCA%2Fpms-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/pms-14-0/pms-14-0-payment_acquirer_multi_pms_properties"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/293/14.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
|
||||
<p>Set the pms property in the payment acquirer to filter on website payments</p>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li>
|
||||
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li>
|
||||
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul>
|
||||
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li>
|
||||
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="usage">
|
||||
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
|
||||
<p>Sets one or more properties in the payment acquirer so that payment method is only available for documents of those properties.
|
||||
If you leave it blank, it will be available to everyone.</p>
|
||||
</div>
|
||||
<div class="section" id="bug-tracker">
|
||||
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1>
|
||||
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/pms/issues">GitHub Issues</a>.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed
|
||||
<a class="reference external" href="https://github.com/OCA/pms/issues/new?body=module:%20payment_acquirer_multi_pms_properties%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
|
||||
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
||||
</div>
|
||||
<div class="section" id="credits">
|
||||
<h1><a class="toc-backref" href="#id3">Credits</a></h1>
|
||||
<div class="section" id="authors">
|
||||
<h2><a class="toc-backref" href="#id4">Authors</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Commit [Sun]</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributors">
|
||||
<h2><a class="toc-backref" href="#id5">Contributors</a></h2>
|
||||
<ul class="simple">
|
||||
<li><cite>Commit [Sun] <https://www.commitsun.com></cite>:<ul>
|
||||
<li>Dario Lodeiros</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
<h2><a class="toc-backref" href="#id6">Maintainers</a></h2>
|
||||
<p>This module is maintained by the OCA.</p>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
|
||||
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.</p>
|
||||
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/pms/tree/14.0/payment_acquirer_multi_pms_properties">OCA/pms</a> project on GitHub.</p>
|
||||
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
|
||||
<record id="payment_acquirer_form" model="ir.ui.view">
|
||||
<field name="name">muliproperty.payment.acquirer.form</field>
|
||||
<field name="model">payment.acquirer</field>
|
||||
<field name="inherit_id" ref="payment.acquirer_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="company_id" position="after">
|
||||
<field name="pms_property_ids" widget="many2many_tags" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
109
pms/README.rst
109
pms/README.rst
@@ -1,109 +0,0 @@
|
||||
================================
|
||||
PMS (Property Management System)
|
||||
================================
|
||||
|
||||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
|
||||
:target: https://odoo-community.org/page/development-status
|
||||
:alt: Alpha
|
||||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpms-lightgray.png?logo=github
|
||||
:target: https://github.com/OCA/pms/tree/14.0/pms
|
||||
:alt: OCA/pms
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/pms-14-0/pms-14-0-pms
|
||||
:alt: Translate me on Weblate
|
||||
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
|
||||
:target: https://runbot.odoo-community.org/runbot/293/14.0
|
||||
:alt: Try me on Runbot
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
This module is an all-in-one property management system (PMS) focused on medium-sized properties
|
||||
for managing every aspect of your property's daily operations.
|
||||
|
||||
You can manage properties with multi-property and multi-company support, including your rooms inventory,
|
||||
reservations, check-in, daily reports, board services, rate and availability plans among other property functionalities.
|
||||
|
||||
.. IMPORTANT::
|
||||
This is an alpha version, the data model and design can change at any time without warning.
|
||||
Only for development or testing purpose, do not use in production.
|
||||
`More details on development status <https://odoo-community.org/page/development-status>`_
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
This module depends on modules ``base``, ``mail``, ``sale`` and ``multi_pms_properties``.
|
||||
Ensure yourself to have all them in your addons list.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
You will find the hotel settings in PMS Management > Configuration > Properties > Your Property.
|
||||
|
||||
This module required additional configuration for company, accounting, invoicing and user privileges.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
To use this module, please, read the complete user guide at `<roomdoo.com>`_.
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/pms/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed
|
||||
`feedback <https://github.com/OCA/pms/issues/new?body=module:%20pms%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
Do not contact contributors directly about support or help with technical issues.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Authors
|
||||
~~~~~~~
|
||||
|
||||
* Commit [Sun]
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* Alexandre Díaz
|
||||
* Pablo Quesada
|
||||
* Jose Luis Algara
|
||||
* `Commit [Sun] <https://www.commitsun.com>`:
|
||||
|
||||
* Dario Lodeiros
|
||||
* Eric Antones
|
||||
* Sara Lago
|
||||
* Brais Abeijon
|
||||
* Miguel Padin
|
||||
|
||||
Maintainers
|
||||
~~~~~~~~~~~
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.
|
||||
|
||||
This module is part of the `OCA/pms <https://github.com/OCA/pms/tree/14.0/pms>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
@@ -1,6 +0,0 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import models
|
||||
from . import wizards
|
||||
from . import controllers
|
||||
from .init_hook import pre_init_hook
|
||||
@@ -1,103 +0,0 @@
|
||||
# Copyright 2019 Darío Lodeiros, Alexandre Díaz, Jose Luis Algara, Pablo Quesada
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
"name": "PMS (Property Management System)",
|
||||
"summary": "A property management system",
|
||||
"version": "14.0.2.22.0",
|
||||
"development_status": "Alpha",
|
||||
"category": "Generic Modules/Property Management System",
|
||||
"website": "https://github.com/OCA/pms",
|
||||
"author": "Commit [Sun], Odoo Community Association (OCA)",
|
||||
"license": "AGPL-3",
|
||||
"application": True,
|
||||
"installable": True,
|
||||
"depends": [
|
||||
"base",
|
||||
"base_automation",
|
||||
"mail",
|
||||
# "account_payment_return",
|
||||
# "email_template_qweb",
|
||||
"sale",
|
||||
"multi_pms_properties",
|
||||
"partner_identification",
|
||||
"partner_firstname",
|
||||
"partner_second_lastname",
|
||||
"partner_contact_gender",
|
||||
"partner_contact_birthdate",
|
||||
"partner_contact_nationality",
|
||||
# "partner_identification_unique_by_category",
|
||||
],
|
||||
"data": [
|
||||
"security/pms_security.xml",
|
||||
"security/ir.model.access.csv",
|
||||
"data/cron_jobs.xml",
|
||||
"data/pms_sequence.xml",
|
||||
"data/pms_confirmed_reservation_email_template.xml",
|
||||
"data/pms_modified_reservation_email_template.xml",
|
||||
"data/pms_cancelled_reservation_email_template.xml",
|
||||
"data/pms_precheckin_invitation_email_template.xml",
|
||||
"data/pms_data.xml",
|
||||
"data/traveller_report_paperformat.xml",
|
||||
"report/pms_folio.xml",
|
||||
"report/pms_folio_templates.xml",
|
||||
"report/traveller_report_action.xml",
|
||||
# "templates/pms_email_template.xml",
|
||||
"data/menus.xml",
|
||||
"wizards/wizard_payment_folio.xml",
|
||||
"wizards/folio_make_invoice_advance_views.xml",
|
||||
"wizards/pms_booking_engine_views.xml",
|
||||
"wizards/wizard_folio_changes.xml",
|
||||
"wizards/wizard_several_partners.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_ubication_views.xml",
|
||||
"views/pms_property_views.xml",
|
||||
"views/pms_reservation_views.xml",
|
||||
"views/pms_service_views.xml",
|
||||
"views/pms_service_line_views.xml",
|
||||
"views/pms_folio_views.xml",
|
||||
"views/pms_room_type_views.xml",
|
||||
"views/pms_room_views.xml",
|
||||
"views/pms_room_closure_reason_views.xml",
|
||||
"views/account_payment_views.xml",
|
||||
"views/account_move_views.xml",
|
||||
"views/account_bank_statement_views.xml",
|
||||
"views/res_users_views.xml",
|
||||
"views/pms_room_type_class_views.xml",
|
||||
"views/pms_availability_plan_views.xml",
|
||||
"views/pms_availability_plan_rule_views.xml",
|
||||
"views/res_partner_views.xml",
|
||||
"views/product_pricelist_views.xml",
|
||||
"views/product_pricelist_item_views.xml",
|
||||
"views/pms_sale_channel.xml",
|
||||
"views/product_template_views.xml",
|
||||
"views/webclient_templates.xml",
|
||||
"views/account_journal_views.xml",
|
||||
"views/folio_portal_templates.xml",
|
||||
"views/reservation_portal_templates.xml",
|
||||
"views/res_company_views.xml",
|
||||
"views/traveller_report_template.xml",
|
||||
"views/assets.xml",
|
||||
"wizards/wizard_split_join_swap_reservation.xml",
|
||||
"views/pms_automated_mails_views.xml",
|
||||
"views/precheckin_portal_templates.xml",
|
||||
"wizards/wizard_massive_changes.xml",
|
||||
"wizards/wizard_advanced_filters.xml",
|
||||
"views/payment_transaction_views.xml",
|
||||
],
|
||||
"demo": [
|
||||
"demo/pms_master_data.xml",
|
||||
"demo/pms_folio.xml",
|
||||
"demo/pms_reservation.xml",
|
||||
],
|
||||
"qweb": [
|
||||
"static/src/xml/pms_base_templates.xml",
|
||||
"static/src/xml/reservation_group_button_views.xml",
|
||||
],
|
||||
"pre_init_hook": "pre_init_hook",
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
from . import pms_portal
|
||||
@@ -1,719 +0,0 @@
|
||||
import re
|
||||
|
||||
from odoo import _, fields, http, tools
|
||||
from odoo.exceptions import AccessError, MissingError
|
||||
from odoo.http import request
|
||||
|
||||
from odoo.addons.payment.controllers.portal import PaymentProcessing
|
||||
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
|
||||
|
||||
|
||||
class PortalFolio(CustomerPortal):
|
||||
def _prepare_home_portal_values(self, counters):
|
||||
partner = request.env.user.partner_id
|
||||
values = super()._prepare_home_portal_values(counters)
|
||||
Folio = request.env["pms.folio"]
|
||||
if "folio_count" in counters:
|
||||
values["folio_count"] = (
|
||||
Folio.search_count(
|
||||
[
|
||||
("partner_id", "=", partner.id),
|
||||
]
|
||||
)
|
||||
if Folio.check_access_rights("read", raise_exception=False)
|
||||
else 0
|
||||
)
|
||||
return values
|
||||
|
||||
def _folio_get_page_view_values(self, folio, access_token, **kwargs):
|
||||
values = {"folio": folio, "token": access_token}
|
||||
payment_inputs = request.env["payment.acquirer"]._get_available_payment_input(
|
||||
partner=folio.partner_id, company=folio.company_id
|
||||
)
|
||||
is_public_user = request.env.user._is_public()
|
||||
if is_public_user:
|
||||
payment_inputs.pop("pms", None)
|
||||
token_count = (
|
||||
request.env["payment.token"]
|
||||
.sudo()
|
||||
.search_count(
|
||||
[
|
||||
("acquirer_id.company_id", "=", folio.company_id.id),
|
||||
("partner_id", "=", folio.partner_id.id),
|
||||
]
|
||||
)
|
||||
)
|
||||
values["existing_token"] = token_count > 0
|
||||
values.update(payment_inputs)
|
||||
values["partner_id"] = (
|
||||
folio.partner_id if is_public_user else request.env.user.partner_id,
|
||||
)
|
||||
return self._get_page_view_values(
|
||||
folio, access_token, values, "my_folios_history", False, **kwargs
|
||||
)
|
||||
|
||||
@http.route(
|
||||
"/folio/pay/<int:folio_id>/form_tx", type="json", auth="public", website=True
|
||||
)
|
||||
def folio_pay_form(
|
||||
self, acquirer_id, folio_id, save_token=False, access_token=None, **kwargs
|
||||
):
|
||||
folio_sudo = request.env["pms.folio"].sudo().browse(folio_id)
|
||||
if not folio_sudo:
|
||||
return False
|
||||
|
||||
try:
|
||||
acquirer_id = int(acquirer_id)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
if request.env.user._is_public():
|
||||
save_token = False # we avoid to create a token for the public user
|
||||
|
||||
success_url = kwargs.get(
|
||||
"success_url",
|
||||
"%s?%s" % (folio_sudo.access_url, access_token if access_token else ""),
|
||||
)
|
||||
vals = {
|
||||
"acquirer_id": acquirer_id,
|
||||
"return_url": success_url,
|
||||
}
|
||||
|
||||
if save_token:
|
||||
vals["type"] = "form_save"
|
||||
transaction = folio_sudo._create_payment_transaction(vals)
|
||||
PaymentProcessing.add_payment_transaction(transaction)
|
||||
if not transaction:
|
||||
return False
|
||||
tx_ids_list = set(request.session.get("__payment_tx_ids__", [])) | set(
|
||||
transaction.ids
|
||||
)
|
||||
request.session["__payment_tx_ids__"] = list(tx_ids_list)
|
||||
return transaction.render_folio_button(
|
||||
folio_sudo,
|
||||
submit_txt=_("Pay & Confirm"),
|
||||
render_values={
|
||||
"type": "form_save" if save_token else "form",
|
||||
"alias_usage": _(
|
||||
"If we store your payment information on our server, "
|
||||
"subscription payments will be made automatically."
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
@http.route(
|
||||
["/my/folios", "/my/folios/page/<int:page>"],
|
||||
type="http",
|
||||
auth="public",
|
||||
website=True,
|
||||
)
|
||||
def portal_my_folios(
|
||||
self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, **kw
|
||||
):
|
||||
partner = request.env.user.partner_id
|
||||
values = self._prepare_portal_layout_values()
|
||||
PmsFolio = request.env["pms.folio"]
|
||||
values["folios"] = PmsFolio.search(
|
||||
[
|
||||
("partner_id", "child_of", partner.id),
|
||||
]
|
||||
)
|
||||
domain = [
|
||||
("partner_id", "child_of", partner.id),
|
||||
]
|
||||
searchbar_sortings = {
|
||||
"date": {"label": _("Order Date"), "folio": "date_order desc"},
|
||||
"name": {"label": _("Reference"), "folio": "name"},
|
||||
"stage": {"label": _("Stage"), "folio": "state"},
|
||||
}
|
||||
if not sortby:
|
||||
sortby = "date"
|
||||
sort_order = searchbar_sortings[sortby]["folio"]
|
||||
|
||||
if date_begin and date_end:
|
||||
domain += [
|
||||
("create_date", ">", date_begin),
|
||||
("create_date", "<=", date_end),
|
||||
]
|
||||
folio_count = PmsFolio.search_count(domain)
|
||||
pager = portal_pager(
|
||||
url="/my/folios",
|
||||
url_args={"date_begin": date_begin, "date_end": date_end, "sortby": sortby},
|
||||
total=folio_count,
|
||||
page=page,
|
||||
step=self._items_per_page,
|
||||
)
|
||||
folios = PmsFolio.search(
|
||||
domain, order=sort_order, limit=self._items_per_page, offset=pager["offset"]
|
||||
)
|
||||
request.session["my_folios_history"] = folios.ids[:100]
|
||||
values.update(
|
||||
{
|
||||
"date": date_begin,
|
||||
"folios": folios.sudo(),
|
||||
"page_name": "folios",
|
||||
"pager": pager,
|
||||
"default_url": "/my/folios",
|
||||
"searchbar_sortings": searchbar_sortings,
|
||||
"sortby": sortby,
|
||||
}
|
||||
)
|
||||
return request.render("pms.portal_my_folio", values)
|
||||
|
||||
@http.route(["/my/folios/<int:folio_id>"], type="http", auth="public", website=True)
|
||||
def portal_my_folio_detail(
|
||||
self, folio_id, access_token=None, report_type=None, download=False, **kw
|
||||
):
|
||||
try:
|
||||
folio_sudo = self._document_check_access(
|
||||
"pms.folio",
|
||||
folio_id,
|
||||
access_token=access_token,
|
||||
)
|
||||
except (AccessError, MissingError):
|
||||
return request.redirect("/my")
|
||||
if report_type in ("html", "pdf", "text"):
|
||||
return self._show_report(
|
||||
model=folio_sudo,
|
||||
report_type=report_type,
|
||||
report_ref="pms.action_report_folio",
|
||||
download=download,
|
||||
)
|
||||
values = self._folio_get_page_view_values(folio_sudo, access_token, **kw)
|
||||
return request.render("pms.folio_portal_template", values)
|
||||
|
||||
@http.route(
|
||||
["/my/folios/<int:folio_id>/precheckin"],
|
||||
type="http",
|
||||
auth="public",
|
||||
website=True,
|
||||
)
|
||||
def portal_my_folio_precheckin(
|
||||
self, folio_id, access_token=None, report_type=None, download=False, **kw
|
||||
):
|
||||
values = self._prepare_portal_layout_values()
|
||||
try:
|
||||
folio_sudo = self._document_check_access(
|
||||
"pms.folio",
|
||||
folio_id,
|
||||
access_token=access_token,
|
||||
)
|
||||
except (AccessError, MissingError):
|
||||
return request.redirect("/my")
|
||||
values.update(self._folio_get_page_view_values(folio_sudo, access_token, **kw))
|
||||
values.update({"no_breadcrumbs": True, "error": {}})
|
||||
country_ids = request.env["res.country"].search([])
|
||||
state_ids = request.env["res.country.state"].search([])
|
||||
doc_type_ids = request.env["res.partner.id_category"].sudo().search([])
|
||||
values.update(
|
||||
{
|
||||
"country_ids": country_ids,
|
||||
"state_ids": state_ids,
|
||||
"doc_type_ids": doc_type_ids,
|
||||
}
|
||||
)
|
||||
return request.render("pms.portal_my_folio_precheckin", values)
|
||||
|
||||
|
||||
class PortalReservation(CustomerPortal):
|
||||
def _prepare_home_portal_values(self, counters):
|
||||
partner = request.env.user.partner_id
|
||||
values = super()._prepare_home_portal_values(counters)
|
||||
Reservation = request.env["pms.reservation"]
|
||||
if "reservation_count" in counters:
|
||||
values["reservation_count"] = (
|
||||
Reservation.search_count(
|
||||
[
|
||||
("partner_id", "=", partner.id),
|
||||
]
|
||||
)
|
||||
if Reservation.check_access_rights("read", raise_exception=False)
|
||||
else 0
|
||||
)
|
||||
return values
|
||||
|
||||
def _reservation_get_page_view_values(self, reservation, access_token, **kwargs):
|
||||
values = {"reservation": reservation, "token": access_token}
|
||||
return self._get_page_view_values(
|
||||
reservation,
|
||||
access_token,
|
||||
values,
|
||||
"my_reservations_history",
|
||||
False,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
@http.route(
|
||||
["/my/reservations", "/my/reservations/page/<int:page>"],
|
||||
type="http",
|
||||
auth="public",
|
||||
website=True,
|
||||
)
|
||||
def portal_my_reservations(self, page=1, date_begin=None, date_end=None):
|
||||
partner = request.env.user.partner_id
|
||||
values = self._prepare_portal_layout_values()
|
||||
Reservation = request.env["pms.reservation"]
|
||||
values["reservations"] = Reservation.search(
|
||||
[
|
||||
("partner_id", "child_of", partner.id),
|
||||
]
|
||||
)
|
||||
domain = [
|
||||
("partner_id", "child_of", partner.id),
|
||||
]
|
||||
if date_begin and date_end:
|
||||
domain += [
|
||||
("create_date", ">", date_begin),
|
||||
("create_date", "<=", date_end),
|
||||
]
|
||||
reservation_count = Reservation.search_count(domain)
|
||||
pager = portal_pager(
|
||||
url="/my/reservations",
|
||||
url_args={"date_begin": date_begin, "date_end": date_end},
|
||||
total=reservation_count,
|
||||
page=page,
|
||||
step=self._items_per_page,
|
||||
)
|
||||
reservations = Reservation.search(
|
||||
domain, limit=self._items_per_page, offset=pager["offset"]
|
||||
)
|
||||
folios_dict = {}
|
||||
for reservation in reservations:
|
||||
folio = reservation.folio_id
|
||||
folios_dict[folio] = ""
|
||||
|
||||
request.session["my_reservations_history"] = reservations.ids[:100]
|
||||
values.update(
|
||||
{
|
||||
"date": date_begin,
|
||||
"reservations": reservations.sudo(),
|
||||
"page_name": "reservations",
|
||||
"pager": pager,
|
||||
"default_url": "/my/reservations",
|
||||
"folios_dict": folios_dict,
|
||||
"partner": partner,
|
||||
}
|
||||
)
|
||||
return request.render("pms.portal_my_reservation", values)
|
||||
|
||||
@http.route(
|
||||
["/my/reservations/<int:reservation_id>"],
|
||||
type="http",
|
||||
auth="public",
|
||||
website=True,
|
||||
)
|
||||
def portal_my_reservation_detail(self, reservation_id, access_token=None, **kw):
|
||||
try:
|
||||
reservation_sudo = self._document_check_access(
|
||||
"pms.reservation",
|
||||
reservation_id,
|
||||
access_token=access_token,
|
||||
)
|
||||
except (AccessError, MissingError):
|
||||
return request.redirect("/my")
|
||||
values = self._reservation_get_page_view_values(
|
||||
reservation_sudo, access_token, **kw
|
||||
)
|
||||
return request.render("pms.portal_my_reservation_detail", values)
|
||||
|
||||
@http.route(
|
||||
["/my/reservations/<int:reservation_id>/precheckin"],
|
||||
type="http",
|
||||
auth="public",
|
||||
website=True,
|
||||
)
|
||||
def portal_my_reservation_precheckin(self, reservation_id, access_token=None, **kw):
|
||||
try:
|
||||
reservation_sudo = self._document_check_access(
|
||||
"pms.reservation",
|
||||
reservation_id,
|
||||
access_token=access_token,
|
||||
)
|
||||
except (AccessError, MissingError):
|
||||
return request.redirect("/my")
|
||||
values = self._reservation_get_page_view_values(
|
||||
reservation_sudo, access_token, **kw
|
||||
)
|
||||
values.update({"no_breadcrumbs": True, "error": {}})
|
||||
country_ids = request.env["res.country"].search([])
|
||||
state_ids = request.env["res.country.state"].search([])
|
||||
doc_type_ids = request.env["res.partner.id_category"].sudo().search([])
|
||||
values.update(
|
||||
{
|
||||
"country_ids": country_ids,
|
||||
"state_ids": state_ids,
|
||||
"doc_type_ids": doc_type_ids,
|
||||
}
|
||||
)
|
||||
return request.render("pms.portal_my_reservation_precheckin", values)
|
||||
|
||||
|
||||
class PortalPrecheckin(CustomerPortal):
|
||||
def _precheckin_get_page_view_values(self, checkin_partner, access_token, **kwargs):
|
||||
values = {"checkin_partner": checkin_partner, "token": access_token}
|
||||
return self._get_page_view_values(
|
||||
checkin_partner,
|
||||
access_token,
|
||||
values,
|
||||
"my_precheckins_history",
|
||||
False,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
@http.route(
|
||||
["/my/precheckin/<int:checkin_partner_id>"],
|
||||
type="http",
|
||||
auth="public",
|
||||
website=True,
|
||||
)
|
||||
def portal_my_precheckin_detail(self, checkin_partner_id, access_token=None, **kw):
|
||||
try:
|
||||
checkin_sudo = self._document_check_access(
|
||||
"pms.checkin.partner",
|
||||
checkin_partner_id,
|
||||
access_token=access_token,
|
||||
)
|
||||
except (AccessError, MissingError):
|
||||
return request.redirect("/my")
|
||||
values = self._precheckin_get_page_view_values(checkin_sudo, access_token, **kw)
|
||||
country_ids = request.env["res.country"].search([])
|
||||
state_ids = request.env["res.country.state"].search([])
|
||||
doc_type_ids = request.env["res.partner.id_category"].sudo().search([])
|
||||
values.update(
|
||||
{
|
||||
"doc_type_ids": doc_type_ids,
|
||||
"country_ids": country_ids,
|
||||
"state_ids": state_ids,
|
||||
"no_breadcrumbs": True,
|
||||
"error": {},
|
||||
}
|
||||
)
|
||||
return request.render("pms.portal_my_precheckin_detail", values)
|
||||
|
||||
@http.route(
|
||||
["/my/precheckin"], type="http", auth="public", website=True, csrf=False
|
||||
)
|
||||
def portal_precheckin_submit(self, **kw):
|
||||
values = dict()
|
||||
checkin_partner = request.env["pms.checkin.partner"].browse(int(kw.get("id")))
|
||||
values.update(
|
||||
{
|
||||
"checkin_partner": checkin_partner,
|
||||
"error": {},
|
||||
"error_message": {},
|
||||
}
|
||||
)
|
||||
country_ids = request.env["res.country"].search([])
|
||||
state_ids = request.env["res.country.state"].search([])
|
||||
doc_type_ids = request.env["res.partner.id_category"].sudo().search([])
|
||||
if kw:
|
||||
error, error_message = self.form_validate(kw, None)
|
||||
values.update(
|
||||
{
|
||||
"no_breadcrumbs": True,
|
||||
"error": error,
|
||||
"error_message": error_message,
|
||||
"country_ids": country_ids,
|
||||
"state_ids": state_ids,
|
||||
"doc_type_ids": doc_type_ids,
|
||||
}
|
||||
)
|
||||
if error:
|
||||
return request.render("pms.portal_my_precheckin_detail", values)
|
||||
else:
|
||||
try:
|
||||
values = kw
|
||||
if values.get("document_type"):
|
||||
doc_type = (
|
||||
request.env["res.partner.id_category"]
|
||||
.sudo()
|
||||
.search([("name", "=", values.get("document_type"))])
|
||||
)
|
||||
values.update(
|
||||
{
|
||||
"document_type": doc_type.id,
|
||||
}
|
||||
)
|
||||
request.env["pms.checkin.partner"].sudo()._save_data_from_portal(
|
||||
values
|
||||
)
|
||||
doc_type_ids = (
|
||||
request.env["res.partner.id_category"].sudo().search([])
|
||||
)
|
||||
values.update(
|
||||
{
|
||||
"doc_type_ids": doc_type_ids,
|
||||
}
|
||||
)
|
||||
country_ids = request.env["res.country"].search([])
|
||||
state_ids = request.env["res.country.state"].search([])
|
||||
values.update(
|
||||
{
|
||||
"country_ids": country_ids,
|
||||
"state_ids": state_ids,
|
||||
}
|
||||
)
|
||||
values.update(
|
||||
{
|
||||
"success": True,
|
||||
"checkin_partner": checkin_partner,
|
||||
"no_breadcrumbs": True,
|
||||
"error": {},
|
||||
}
|
||||
)
|
||||
return request.render("pms.portal_my_precheckin_detail", values)
|
||||
except (AccessError, MissingError):
|
||||
return request.redirect("/my")
|
||||
|
||||
@http.route(
|
||||
["/my/precheckin/folio_reservation"],
|
||||
type="http",
|
||||
auth="public",
|
||||
website=True,
|
||||
csrf=False,
|
||||
)
|
||||
def portal_precheckin_folio_submit(self, **kw):
|
||||
errors = {}
|
||||
e_messages = {}
|
||||
counter = 1
|
||||
has_error = False
|
||||
checkin_partners = False
|
||||
if kw.get("folio_id"):
|
||||
folio = request.env["pms.folio"].sudo().browse(int(kw.get("folio_id")))
|
||||
checkin_partners = folio.checkin_partner_ids
|
||||
elif kw.get("reservation_id"):
|
||||
reservation = (
|
||||
request.env["pms.reservation"]
|
||||
.sudo()
|
||||
.browse(int(kw.get("reservation_id")))
|
||||
)
|
||||
checkin_partners = reservation.checkin_partner_ids
|
||||
for checkin in checkin_partners:
|
||||
values = {
|
||||
"id": kw.get("id-" + str(counter)),
|
||||
"firstname": kw.get("firstname-" + str(counter)),
|
||||
"lastname": kw.get("lastname-" + str(counter)),
|
||||
"lastname2": kw.get("lastname2-" + str(counter)),
|
||||
"gender": kw.get("gender-" + str(counter)),
|
||||
"birthdate_date": kw.get("birthdate_date-" + str(counter))
|
||||
if kw.get("birthdate_date-" + str(counter))
|
||||
else False,
|
||||
"document_type": kw.get("document_type-" + str(counter)),
|
||||
"document_number": kw.get("document_number-" + str(counter)),
|
||||
"document_expedition_date": kw.get(
|
||||
"document_expedition_date-" + str(counter)
|
||||
)
|
||||
if kw.get("document_expedition_date-" + str(counter))
|
||||
else False,
|
||||
"mobile": kw.get("mobile-" + str(counter)),
|
||||
"email": kw.get("email-" + str(counter)),
|
||||
"nationality_id": kw.get("nationality_id-" + str(counter)),
|
||||
"state": kw.get("state-" + str(counter)),
|
||||
}
|
||||
|
||||
if values.get("document_type"):
|
||||
doc_type_code = values.get("document_type")
|
||||
doc_type = (
|
||||
request.env["res.partner.id_category"]
|
||||
.sudo()
|
||||
.search([("name", "=", doc_type_code)])
|
||||
)
|
||||
values.update(
|
||||
{
|
||||
"document_type": doc_type.id,
|
||||
}
|
||||
)
|
||||
error, error_message = self.form_validate(kw, counter)
|
||||
errors.update(error)
|
||||
e_messages.update(error_message)
|
||||
if error_message:
|
||||
has_error = True
|
||||
else:
|
||||
checkin.sudo()._save_data_from_portal(values)
|
||||
counter = counter + 1
|
||||
values = {"no_breadcrumbs": True}
|
||||
doc_type_ids = request.env["res.partner.id_category"].sudo().search([])
|
||||
country_ids = request.env["res.country"].search([])
|
||||
state_ids = request.env["res.country.state"].search([])
|
||||
values.update(
|
||||
{
|
||||
"doc_type_ids": doc_type_ids,
|
||||
"country_ids": country_ids,
|
||||
"state_ids": state_ids,
|
||||
}
|
||||
)
|
||||
if has_error:
|
||||
filtered_dict_error = {k: v for k, v in errors.items() if v}
|
||||
filtered_dict_error_messages = {k: v for k, v in e_messages.items() if v}
|
||||
values.update(
|
||||
{
|
||||
"error": filtered_dict_error,
|
||||
"error_message": filtered_dict_error_messages,
|
||||
}
|
||||
)
|
||||
else:
|
||||
values.update({"success": True, "error": {}})
|
||||
if kw.get("folio_id"):
|
||||
folio = request.env["pms.folio"].sudo().browse(int(kw.get("folio_id")))
|
||||
values.update(
|
||||
{
|
||||
"folio": folio,
|
||||
}
|
||||
)
|
||||
return request.render("pms.portal_my_folio_precheckin", values)
|
||||
elif kw.get("reservation_id"):
|
||||
reservation = request.env["pms.reservation"].browse(
|
||||
int(kw.get("reservation_id"))
|
||||
)
|
||||
values.update(
|
||||
{
|
||||
"reservation": reservation,
|
||||
}
|
||||
)
|
||||
return request.render("pms.portal_my_reservation_precheckin", values)
|
||||
|
||||
def form_validate(self, data, counter):
|
||||
error, error_message = self.form_document_validate(data, counter)
|
||||
keys = data.keys()
|
||||
mobile = "mobile" if "mobile" in keys else "mobile-" + str(counter)
|
||||
if data[mobile]:
|
||||
if not re.match(
|
||||
r"^(\d{3}[\-\s]?\d{2}[\-\s]?\d{2}[\-\s]?\d{2}[\-\s]?|"
|
||||
r"\d{3}[\-\s]?\d{3}[\-\s]?\d{3})$",
|
||||
data[mobile],
|
||||
):
|
||||
error[mobile] = "error"
|
||||
error_message[mobile] = "Invalid phone"
|
||||
birthdate_date = (
|
||||
"birthdate_date"
|
||||
if "birthdate_date" in keys
|
||||
else "birthdate_date-" + str(counter)
|
||||
)
|
||||
if data[birthdate_date] and data[birthdate_date] > str(fields.Datetime.today()):
|
||||
error[birthdate_date] = "error"
|
||||
error_message[birthdate_date] = "Birthdate must be less than today"
|
||||
email = "email" if "email" in keys else "email-" + str(counter)
|
||||
if data[email] and not tools.single_email_re.match(data[email]):
|
||||
error[email] = "error"
|
||||
error_message[email] = "Email format is wrong"
|
||||
firstname = "firstname" if "firstname" in keys else "firstname-" + str(counter)
|
||||
lastname = "lastname" if "lastname" in keys else "lastname-" + str(counter)
|
||||
lastname2 = "lastname2" if "lastname2" in keys else "lastname2-" + str(counter)
|
||||
if not data[firstname] and not data[lastname] and not data[lastname2]:
|
||||
error[firstname] = "error"
|
||||
error_message[firstname] = "Firstname or any lastname are not included"
|
||||
return error, error_message
|
||||
|
||||
def form_document_validate(self, data, counter):
|
||||
error = dict()
|
||||
error_message = {}
|
||||
keys = data.keys()
|
||||
document_number = (
|
||||
"document_number"
|
||||
if "document_number" in keys
|
||||
else "document_number-" + str(counter)
|
||||
)
|
||||
document_type = (
|
||||
"document_type"
|
||||
if "document_type" in keys
|
||||
else "document_type-" + str(counter)
|
||||
)
|
||||
document_expedition_date = (
|
||||
"document_expedition_date"
|
||||
if "document_expedition_date" in keys
|
||||
else "document_expedition_date-" + str(counter)
|
||||
)
|
||||
if data[document_expedition_date] and not data[document_number]:
|
||||
error[document_expedition_date] = "error"
|
||||
error_message[
|
||||
document_expedition_date
|
||||
] = "Document Number not entered and Document Type is not selected"
|
||||
if data[document_number]:
|
||||
if not data[document_type]:
|
||||
error[document_type] = "error"
|
||||
error_message[document_type] = "Document Type is not selected"
|
||||
if data[document_type] == "D":
|
||||
if len(data[document_number]) == 9 or len(data[document_number]) == 10:
|
||||
if not re.match(r"^\d{8}[ -]?[a-zA-Z]$", data[document_number]):
|
||||
error[document_number] = "error"
|
||||
error_message[document_number] = "The DNI format is wrong"
|
||||
letters = {
|
||||
0: "T",
|
||||
1: "R",
|
||||
2: "W",
|
||||
3: "A",
|
||||
4: "G",
|
||||
5: "M",
|
||||
6: "Y",
|
||||
7: "F",
|
||||
8: "P",
|
||||
9: "D",
|
||||
10: "X",
|
||||
11: "B",
|
||||
12: "N",
|
||||
13: "J",
|
||||
14: "Z",
|
||||
15: "S",
|
||||
16: "Q",
|
||||
17: "V",
|
||||
18: "H",
|
||||
19: "L",
|
||||
20: "C",
|
||||
21: "K",
|
||||
22: "E",
|
||||
}
|
||||
dni_number = data[document_number][0:8]
|
||||
dni_letter = data[document_number][
|
||||
len(data[document_number]) - 1 : len(data[document_number])
|
||||
]
|
||||
if letters.get(int(dni_number) % 23) != dni_letter.upper():
|
||||
error[document_number] = "error"
|
||||
error_message[document_number] = "DNI format is invalid"
|
||||
else:
|
||||
error[document_number] = "error"
|
||||
error_message[document_number] = "DNI is invalid"
|
||||
if data[document_type] == "C" and not re.match(
|
||||
r"^\d{8}[ -]?[a-zA-Z]$", data[document_number]
|
||||
):
|
||||
error[document_number] = "error"
|
||||
error_message[document_number] = "The Driving License format is wrong"
|
||||
if data[document_type] == "N" and not re.match(
|
||||
r"^[X|Y]{1}[ -]?\d{7,8}[ -]?[a-zA-Z]$", data[document_number]
|
||||
):
|
||||
error[document_number] = "error"
|
||||
error_message[
|
||||
document_number
|
||||
] = "The Spanish Residence Permit format is wrong"
|
||||
if data[document_type] == "X" and not re.match(
|
||||
r"^[X|Y]{1}[ -]?\d{7,8}[ -]?[a-zA-Z]$", data[document_number]
|
||||
):
|
||||
error[document_number] = "error"
|
||||
error_message[
|
||||
document_number
|
||||
] = "The European Residence Permit format is wrong"
|
||||
elif data[document_type]:
|
||||
error[document_number] = "error"
|
||||
error_message[document_number] = "Document Number not entered"
|
||||
return error, error_message
|
||||
|
||||
@http.route(
|
||||
["/my/precheckin/send_invitation"],
|
||||
auth="public",
|
||||
type="json",
|
||||
website=True,
|
||||
csrf=False,
|
||||
)
|
||||
def portal_precheckin_folio_send_invitation(self, **kw):
|
||||
if kw.get("folio_id"):
|
||||
folio = request.env["pms.folio"].browse(int(kw.get("folio_id")))
|
||||
kw.update({"folio": folio})
|
||||
checkin_partner = (
|
||||
request.env["pms.checkin.partner"]
|
||||
.sudo()
|
||||
.browse(int(kw["checkin_partner_id"]))
|
||||
)
|
||||
firstname = kw["firstname"]
|
||||
email = kw["email"]
|
||||
if firstname and email:
|
||||
checkin_partner.write({"firstname": firstname, "email": email})
|
||||
checkin_partner.send_portal_invitation_email(firstname, email)
|
||||
@@ -1,105 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<!-- Set reservation like No Show if the client does not show up -->
|
||||
<record model="ir.cron" id="noshow_reservations">
|
||||
<field name="name">Automatic No Show Reservation</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<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 09:00:00')"
|
||||
/>
|
||||
<field name="code">model.auto_arrival_delayed()</field>
|
||||
</record>
|
||||
<!-- Set reservation like No Checout if checkout is not confirmed-->
|
||||
<record model="ir.cron" id="nocheckout_reservations">
|
||||
<field name="name">Automatic No Checkout Reservations</field>
|
||||
<field name="interval_number">5</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False" />
|
||||
<field name="state">code</field>
|
||||
<field name="model_id" ref="model_pms_reservation" />
|
||||
<field name="nextcall" eval="DateTime.now()" />
|
||||
<field name="code">model.auto_departure_delayed()</field>
|
||||
</record>
|
||||
<!-- 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>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<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="code">model.autocheckout()</field>
|
||||
</record>
|
||||
<record model="ir.cron" id="priority_reservations">
|
||||
<field name="name">Recompute priority on reservations</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<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:30:00')"
|
||||
/>
|
||||
<field name="code">model.update_daily_priority_reservation()</field>
|
||||
</record>
|
||||
<!-- Scheduler for send confirmed email -->
|
||||
<record model="ir.cron" id="send_confirmation_email_folio">
|
||||
<field name="name">Send Confirmation Email</field>
|
||||
<field name="interval_number">5</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="active" eval="False" />
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False" />
|
||||
<field name="state">code</field>
|
||||
<field name="model_id" ref="model_pms_folio" />
|
||||
<field name="nextcall" eval="DateTime.now() + timedelta(days=1)" />
|
||||
<field name="code">model.send_confirmation_mail()</field>
|
||||
</record>
|
||||
<record model="ir.cron" id="send_modification_email_folio">
|
||||
<field name="name">Send Modification Email</field>
|
||||
<field name="interval_number">5</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="active" eval="False" />
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False" />
|
||||
<field name="state">code</field>
|
||||
<field name="model_id" ref="model_pms_folio" />
|
||||
<field name="nextcall" eval="DateTime.now()" />
|
||||
<field name="code">model.send_modification_mail()</field>
|
||||
</record>
|
||||
<record model="ir.cron" id="send_cancelation_email_folio">
|
||||
<field name="name">Send Cancellation Email</field>
|
||||
<field name="interval_number">5</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="active" eval="False" />
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False" />
|
||||
<field name="state">code</field>
|
||||
<field name="model_id" ref="model_pms_folio" />
|
||||
<field name="nextcall" eval="DateTime.now()" />
|
||||
<field name="code">model.send_cancelation_mail()</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,52 +0,0 @@
|
||||
<?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"
|
||||
/>
|
||||
<menuitem
|
||||
id="menu_reservations"
|
||||
name="Reservations"
|
||||
parent="pms_management_menu"
|
||||
sequence="5"
|
||||
/>
|
||||
<menuitem
|
||||
id="pms_sales_menu"
|
||||
name="Sales"
|
||||
sequence="15"
|
||||
parent="pms_management_menu"
|
||||
/>
|
||||
<menuitem
|
||||
id="pms_contacts_menu"
|
||||
name="Contacts"
|
||||
sequence="20"
|
||||
parent="pms_management_menu"
|
||||
groups="pms.group_pms_user"
|
||||
/>
|
||||
<menuitem
|
||||
id="revenue_management_menu"
|
||||
name="Revenue Management"
|
||||
sequence="25"
|
||||
parent="pms_management_menu"
|
||||
/>
|
||||
<menuitem
|
||||
id="pms_rooms_menu"
|
||||
name="Rooms"
|
||||
sequence="35"
|
||||
parent="pms_management_menu"
|
||||
/>
|
||||
<menuitem
|
||||
id="pms_services_menu"
|
||||
name="Services"
|
||||
sequence="45"
|
||||
parent="pms_management_menu"
|
||||
/>
|
||||
<menuitem
|
||||
id="pms_configuration_menu"
|
||||
name="Configuration"
|
||||
sequence="55"
|
||||
parent="pms_management_menu"
|
||||
/>
|
||||
</odoo>
|
||||
@@ -1,160 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="cancelled_reservation_email" model="mail.template">
|
||||
<field name="name">Cancelled Reservation</field>
|
||||
<field name="model_id" ref="pms.model_pms_reservation" />
|
||||
<field
|
||||
name="subject"
|
||||
>Your reservation in ${object.pms_property_id.name} has been cancelled</field>
|
||||
<field
|
||||
name="email_from"
|
||||
>${object.pms_property_id.partner_id.email | safe}</field>
|
||||
<field
|
||||
name="email_to"
|
||||
>${(object.email and '"%s" <%s>' % (object.name, object.email) or object.partner_id.email_formatted or '') | safe}</field>
|
||||
<field name="body_html" type="html">
|
||||
<table
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="padding-top: 16px; background-color: #F1F1F1; font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;"
|
||||
><tr><td align="center">
|
||||
<table
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
width="590"
|
||||
style="padding: 16px; background-color: white; color: #454748; border-collapse:separate;"
|
||||
>
|
||||
<tbody>
|
||||
<!-- HEADER -->
|
||||
<!-- PROPERTY DESCRIPTION -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 0px 0px 0px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td align="right">
|
||||
<div class="col-sm-4">
|
||||
% if object.pms_property_id.partner_id.street
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street}</p>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.street2
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street2}</p>
|
||||
% endif
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.zip}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.city}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.country_id.name}</p>
|
||||
</div>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div>
|
||||
Hello ${object.partner_id.name or ''},<br
|
||||
/>
|
||||
Your reservation at ${object.pms_property_id.name} has been successfully canceled.
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- DETAILS -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<!-- CONTACT -->
|
||||
<div>
|
||||
<div
|
||||
>If you have questions please contact with us:</div>
|
||||
<ul>
|
||||
<li
|
||||
>${object.pms_property_id.name}</li>
|
||||
% if object.pms_property_id.partner_id.email
|
||||
<li>Mail: <a
|
||||
href="mailto:${object.pms_property_id.partner_id.email}"
|
||||
style="text-decoration:none;color:#875A7B;"
|
||||
>${object.pms_property_id.partner_id.email}</a></li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.phone
|
||||
<li
|
||||
>Phone: ${object.pms_property_id.partner_id.phone}</li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.mobile
|
||||
<li
|
||||
>Mobile: ${object.pms_property_id.partner_id.mobile}</li>
|
||||
% endif
|
||||
</ul>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td></tr>
|
||||
<!-- FOOTER -->
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.pms_property_id.privacy_policy
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="font-size: 10px;">
|
||||
${object.pms_property_id.privacy_policy}
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.company_id
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="text-align: center; font-size: 10px;">
|
||||
Sent by <a
|
||||
target="_blank"
|
||||
href="${object.company_id.website}"
|
||||
style="color: #875A7B;"
|
||||
>${object.company_id.name}</a>
|
||||
<br />
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
</table>
|
||||
</field>
|
||||
<field name="lang">${object.partner_id.lang}</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,307 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="confirmed_reservation_email" model="mail.template">
|
||||
<field name="name">Confirmed Reservation</field>
|
||||
<field name="model_id" ref="pms.model_pms_reservation" />
|
||||
<field
|
||||
name="subject"
|
||||
>${object.company_id.name} has confirmed your reservation in ${object.pms_property_id.name}</field>
|
||||
<field
|
||||
name="email_from"
|
||||
>${object.pms_property_id.partner_id.email | safe}</field>
|
||||
<field
|
||||
name="email_to"
|
||||
>${(object.email and '"%s" <%s>' % (object.name, object.email) or object.partner_id.email_formatted or '') | safe}</field>
|
||||
<field name="body_html" type="html">
|
||||
<table
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="padding-top: 16px; background-color: #F1F1F1; font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;"
|
||||
><tr><td align="center">
|
||||
<table
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
width="590"
|
||||
style="padding: 16px; background-color: white; color: #454748; border-collapse:separate;"
|
||||
>
|
||||
<head>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"
|
||||
integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
</head>
|
||||
<tbody>
|
||||
<!-- PROPERTY DESCRIPTION -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 0px 0px 0px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td align="right">
|
||||
<div class="col-sm-4">
|
||||
% if object.pms_property_id.partner_id.street
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street}</p>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.street2
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street2}</p>
|
||||
% endif
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.zip}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.city}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.country_id.name}</p>
|
||||
</div>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div>
|
||||
Hello ${object.partner_id.name or ''},<br
|
||||
/>
|
||||
We are happy to confirm your reservation in ${object.pms_property_id.name}
|
||||
</div>
|
||||
<div>
|
||||
See you soon,<br />
|
||||
<span style="color: #454748;">
|
||||
<br />
|
||||
${object.company_id.name}
|
||||
</span>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- DETAILS -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div
|
||||
align="left"
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
><strong>Reservation Details</strong></div>
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<table style="width:50%;">
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
class="far fa-calendar-alt fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px; font-size: 14px;"
|
||||
>
|
||||
<div><strong
|
||||
>From</strong> ${object.checkin} <strong
|
||||
>At</strong> ${object.arrival_hour}</div>
|
||||
<div><strong
|
||||
>To</strong> ${object.checkout} <strong
|
||||
>At</strong> ${object.departure_hour}</div>
|
||||
<div
|
||||
style="font-size:12px;color:#9e9e9e"
|
||||
><i><strong
|
||||
>TZ</strong> ${object.pms_property_id.tz}</i></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
>
|
||||
<br />
|
||||
<div
|
||||
class="fas fa-bed fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td style="vertical-align:top;">
|
||||
<br />
|
||||
<div><strong
|
||||
>Room: </strong> ${object.room_type_id.name}</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
>
|
||||
<br />
|
||||
<div
|
||||
class="fas fa-coins fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px; font-size: 14px;"
|
||||
>
|
||||
<br />
|
||||
<div><strong
|
||||
>Price: </strong> ${object.price_room_services_set} ${object.pms_property_id.country_id.currency_id.symbol}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<div>
|
||||
% if object.pms_property_id.mail_information
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div
|
||||
align="left"
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
><strong
|
||||
>Additional Information</strong></div>
|
||||
${object.pms_property_id.mail_information|safe}
|
||||
% endif
|
||||
</div>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td
|
||||
align="center"
|
||||
style="padding: 20px 0 0px 0; "
|
||||
>
|
||||
<div>
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
Do your check-in now and save time.
|
||||
<br />
|
||||
Access our<strong
|
||||
> quick registration system</strong>. In a few steps you will be able to register your data in an agile, simple and secure way,<strong
|
||||
> avoiding queues at reception</strong>.
|
||||
If you register your data in our system, <strong
|
||||
> your passage through reception will be much faster</strong>, being able to enjoy the comfort of your room right away.
|
||||
<table
|
||||
border="0"
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a
|
||||
href="/my/folios/${object.folio_id.id}/precheckin?access_token=${object.folio_id.access_token}"
|
||||
target="_blank"
|
||||
style="text-decoration: none; color: #FFFFFF; font-size: 2em; padding: 10px 20px 10px 20px;"
|
||||
>
|
||||
<div
|
||||
style="padding: 0.5em; background-color: #45C2B1; border-color: #45C2B1; border-width: 2px;border-style:solid; border-bottom-style: solid;border-left-style: solid;border-right-style: solid;border-top-style: solid;-webkit-border-radius: 10; -moz-border-radius: 10; border-radius: 10px;font-size: 12px;"
|
||||
>Check-in
|
||||
</div>
|
||||
<center><img
|
||||
src="https://www.aldahotels.es/firma/email/llegada/check-in.png"
|
||||
alt="Hacer check-in"
|
||||
width="80px"
|
||||
height="80px"
|
||||
href="${object.url}"
|
||||
/></center></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<!-- CONTACT -->
|
||||
<div>
|
||||
<span
|
||||
style="font-weight:300;margin:10px 0px"
|
||||
>Questions about the reservation?</span>
|
||||
<div>Please contact with us:</div>
|
||||
<ul>
|
||||
<li
|
||||
>${object.pms_property_id.name}</li>
|
||||
% if object.pms_property_id.partner_id.email
|
||||
<li>Mail: <a
|
||||
href="mailto:${object.pms_property_id.partner_id.email}"
|
||||
style="text-decoration:none;color:#875A7B;"
|
||||
>${object.pms_property_id.partner_id.email}</a></li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.phone
|
||||
<li
|
||||
>Phone: ${object.pms_property_id.partner_id.phone}</li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.mobile
|
||||
<li
|
||||
>Mobile: ${object.pms_property_id.partner_id.mobile}</li>
|
||||
% endif
|
||||
</ul>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td></tr>
|
||||
<!-- FOOTER -->
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.pms_property_id.privacy_policy
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="font-size: 10px;">
|
||||
${object.pms_property_id.privacy_policy|safe}
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.company_id
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="text-align: center; font-size: 10px;">
|
||||
Sent by <a
|
||||
target="_blank"
|
||||
href="${object.company_id.website}"
|
||||
style="color: #875A7B;"
|
||||
>${object.company_id.name}</a>
|
||||
<br />
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
</table>
|
||||
</field>
|
||||
<field name="lang">${object.partner_id.lang}</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,174 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- Basic pms -->
|
||||
<record id="main_pms_availability_plan" model="pms.availability.plan">
|
||||
<field name="name">Availability 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="street">Rua Street Demo, s/n</field>
|
||||
<field name="city">Commitsun city</field>
|
||||
<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>
|
||||
<field name="folio_sequence_id" ref="pms.seq_pms_folio" />
|
||||
<field name="checkin_sequence_id" ref="pms.seq_pms_checkin" />
|
||||
<field name="reservation_sequence_id" ref="pms.seq_pms_reservation" />
|
||||
</record>
|
||||
<!-- pms.users -->
|
||||
<record id="base.user_root" model="res.users">
|
||||
<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="groups_id" eval="[(4,ref('pms.group_pms_manager'))]" />
|
||||
</record>
|
||||
<record id="base.user_admin" model="res.users">
|
||||
<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="groups_id" eval="[(4,ref('pms.group_pms_manager'))]" />
|
||||
</record>
|
||||
<!-- pms.sale.channel-->
|
||||
<record id="main_pms_sale_channel_0" model="pms.sale.channel">
|
||||
<field name="name">Door</field>
|
||||
<field name="channel_type">direct</field>
|
||||
</record>
|
||||
<record id="main_pms_sale_channel_1" model="pms.sale.channel">
|
||||
<field name="name">Phone</field>
|
||||
<field name="channel_type">direct</field>
|
||||
</record>
|
||||
<record id="main_pms_sale_channel_2" model="pms.sale.channel">
|
||||
<field name="name">Mail</field>
|
||||
<field name="channel_type">direct</field>
|
||||
</record>
|
||||
<record id="main_pms_sale_channel_3" model="pms.sale.channel">
|
||||
<field name="name">Agency</field>
|
||||
<field name="channel_type">indirect</field>
|
||||
</record>
|
||||
<!--res.partner_category_id-->
|
||||
<record id="document_type_passport" model="res.partner.id_category">
|
||||
<field name="name">Passport</field>
|
||||
<field name="code">P</field>
|
||||
<!-- <field name="has_unique_numbers">True</field>-->
|
||||
</record>
|
||||
<record id="document_type_driving_license" model="res.partner.id_category">
|
||||
<field name="name">Driving License</field>
|
||||
<field name="code">C</field>
|
||||
<field name="validation_code">
|
||||
letters = {
|
||||
0: "T",
|
||||
1: "R",
|
||||
2: "W",
|
||||
3: "A",
|
||||
4: "G",
|
||||
5: "M",
|
||||
6: "Y",
|
||||
7: "F",
|
||||
8: "P",
|
||||
9: "D",
|
||||
10: "X",
|
||||
11: "B",
|
||||
12: "N",
|
||||
13: "J",
|
||||
14: "Z",
|
||||
15: "S",
|
||||
16: "Q",
|
||||
17: "V",
|
||||
18: "H",
|
||||
19: "L",
|
||||
20: "C",
|
||||
21: "K",
|
||||
22: "E",
|
||||
}
|
||||
dni_number = id_number.name[0:8]
|
||||
dni_letter = id_number.name[
|
||||
len(id_number.name) - 1 : len(id_number.name)
|
||||
]
|
||||
if dni_number.isdigit() and not dni_letter.isdigit():
|
||||
if letters.get(int(dni_number) % 23) != dni_letter.upper():
|
||||
failed = True
|
||||
else:
|
||||
failed = True
|
||||
</field>
|
||||
<!-- <field name="has_unique_numbers">True</field>-->
|
||||
</record>
|
||||
<record
|
||||
id="document_type_identification_document"
|
||||
model="res.partner.id_category"
|
||||
>
|
||||
<field name="name">Identification Document</field>
|
||||
<field name="code">I</field>
|
||||
<!-- <field name="has_unique_numbers">True</field>-->
|
||||
</record>
|
||||
<record id="document_type_spanish_residence" model="res.partner.id_category">
|
||||
<field name="name">Spanish Residence permit</field>
|
||||
<field name="code">N</field>
|
||||
<field name="validation_code">
|
||||
permit_first_letter=id_number.name[0:1]
|
||||
permit_last_letter = id_number.name[
|
||||
len(id_number.name) - 1 : len(id_number.name)
|
||||
]
|
||||
if (permit_first_letter.upper() in ['X','Y']) and id_number.name[1:8].isdigit() and not permit_last_letter.isdigit():
|
||||
failed = False
|
||||
else:
|
||||
failed = True
|
||||
</field>
|
||||
<!-- <field name="has_unique_numbers">True</field>-->
|
||||
</record>
|
||||
<record id="document_type_european_residence" model="res.partner.id_category">
|
||||
<field name="name">European Residence permit</field>
|
||||
<field name="code">X</field>
|
||||
<field name="validation_code">
|
||||
permit_first_letter=id_number.name[0:1]
|
||||
permit_last_letter = id_number.name[
|
||||
len(id_number.name) - 1 : len(id_number.name)
|
||||
]
|
||||
if (permit_first_letter.upper() in ['X','Y']) and id_number.name[1:8].isdigit() and not permit_last_letter.isdigit():
|
||||
failed = False
|
||||
else:
|
||||
failed = True
|
||||
</field>
|
||||
</record>
|
||||
<!-- pms.automated_mails-->
|
||||
<record id="pms_auto_mail_confirm" model="pms.automated.mails">
|
||||
<field name="name">Confirmed Reservation</field>
|
||||
<field name="active">False</field>
|
||||
<field name="template_id" ref="pms.confirmed_reservation_email" />
|
||||
<field name="action">creation</field>
|
||||
<field
|
||||
name="pms_property_ids"
|
||||
eval="[(6, False, [ref('main_pms_property')])]"
|
||||
/>
|
||||
<field name="moment">in_act</field>
|
||||
</record>
|
||||
<record id="pms_auto_mail_write" model="pms.automated.mails">
|
||||
<field name="name">Modified Reservation</field>
|
||||
<field name="active">False</field>
|
||||
<field name="template_id" ref="pms.modified_reservation_email" />
|
||||
<field name="action">write</field>
|
||||
<field
|
||||
name="pms_property_ids"
|
||||
eval="[(6, False, [ref('main_pms_property')])]"
|
||||
/>
|
||||
<field name="moment">in_act</field>
|
||||
</record>
|
||||
<record id="pms_auto_mail_cancel" model="pms.automated.mails">
|
||||
<field name="name">Cancelled Reservation</field>
|
||||
<field name="active">False</field>
|
||||
<field name="template_id" ref="pms.cancelled_reservation_email" />
|
||||
<field name="action">cancel</field>
|
||||
<field
|
||||
name="pms_property_ids"
|
||||
eval="[(6, False, [ref('main_pms_property')])]"
|
||||
/>
|
||||
<field name="moment">in_act</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,262 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="modified_reservation_email" model="mail.template">
|
||||
<field name="name">Modified Reservation</field>
|
||||
<field name="model_id" ref="pms.model_pms_reservation" />
|
||||
<field
|
||||
name="subject"
|
||||
>Your reservation in ${object.pms_property_id.name} has been modified</field>
|
||||
<field
|
||||
name="email_from"
|
||||
>${object.pms_property_id.partner_id.email | safe}</field>
|
||||
<field
|
||||
name="email_to"
|
||||
>${(object.email and '"%s" <%s>' % (object.name, object.email) or object.partner_id.email_formatted or '') | safe}</field>
|
||||
<field name="body_html" type="html">
|
||||
<table
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="padding-top: 16px; background-color: #F1F1F1; font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;"
|
||||
><tr><td align="center">
|
||||
<table
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
width="590"
|
||||
style="padding: 16px; background-color: white; color: #454748; border-collapse:separate;"
|
||||
>
|
||||
<head>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"
|
||||
integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
</head>
|
||||
<tbody>
|
||||
<!-- HEADER -->
|
||||
<!-- PROPERTY DESCRIPTION -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 0px 0px 0px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td align="right">
|
||||
<div class="col-sm-4">
|
||||
% if object.pms_property_id.partner_id.street
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street}</p>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.street2
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street2}</p>
|
||||
% endif
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.zip}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.city}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.country_id.name}</p>
|
||||
</div>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div>
|
||||
Hello ${object.partner_id.name or ''},<br
|
||||
/>
|
||||
Your reservation in ${object.pms_property_id.name} has been modified
|
||||
</div>
|
||||
<div>
|
||||
See you soon,<br />
|
||||
<span style="color: #454748;">
|
||||
<br />
|
||||
${object.company_id.name}
|
||||
</span>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- DETAILS -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div
|
||||
align="left"
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
><strong>Reservation Details</strong></div>
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<table style="width:50%;">
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
class="far fa-calendar-alt fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px; font-size: 14px;"
|
||||
>
|
||||
<div><strong
|
||||
>From</strong> ${object.checkin} <strong
|
||||
>At</strong> ${object.arrival_hour}</div>
|
||||
<div><strong
|
||||
>To</strong> ${object.checkout} <strong
|
||||
>At</strong> ${object.departure_hour}</div>
|
||||
<div
|
||||
style="font-size:12px;color:#9e9e9e"
|
||||
><i><strong
|
||||
>TZ</strong> ${object.pms_property_id.tz}</i></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
>
|
||||
<br />
|
||||
<div
|
||||
class="fas fa-bed fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td style="vertical-align:top;">
|
||||
<br />
|
||||
<div><strong
|
||||
>Room: </strong> ${object.room_type_id.name}</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
>
|
||||
<br />
|
||||
<div
|
||||
class="fas fa-coins fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px; font-size: 14px;"
|
||||
>
|
||||
<br />
|
||||
<div><strong
|
||||
>Price: </strong> ${object.price_total} ${object.pms_property_id.country_id.currency_id.symbol}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<div>
|
||||
% if object.pms_property_id.mail_information
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div
|
||||
align="left"
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
><strong
|
||||
>Additional Information</strong></div>
|
||||
<p
|
||||
>${object.pms_property_id.mail_information|safe}</p>
|
||||
% endif
|
||||
</div>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<!-- CONTACT -->
|
||||
<div>
|
||||
<span
|
||||
style="font-weight:300;margin:10px 0px"
|
||||
>Questions about the reservation?</span>
|
||||
<div>Please contact with us:</div>
|
||||
<ul>
|
||||
<li
|
||||
>${object.pms_property_id.name}</li>
|
||||
% if object.pms_property_id.partner_id.email
|
||||
<li>Mail: <a
|
||||
href="mailto:${object.pms_property_id.partner_id.email}"
|
||||
style="text-decoration:none;color:#875A7B;"
|
||||
>${object.pms_property_id.partner_id.email}</a></li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.phone
|
||||
<li
|
||||
>Phone: ${object.pms_property_id.partner_id.phone}</li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.mobile
|
||||
<li
|
||||
>Mobile: ${object.pms_property_id.partner_id.mobile}</li>
|
||||
% endif
|
||||
</ul>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td></tr>
|
||||
<!-- FOOTER -->
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.pms_property_id.privacy_policy
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="font-size: 10px;">
|
||||
${object.pms_property_id.privacy_policy|safe}
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.company_id
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="text-align: center; font-size: 10px;">
|
||||
Sent by <a
|
||||
target="_blank"
|
||||
href="${object.company_id.website}"
|
||||
style="color: #875A7B;"
|
||||
>${object.company_id.name}</a>
|
||||
<br />
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
</table>
|
||||
</field>
|
||||
<field name="lang">${object.partner_id.lang}</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,57 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="precheckin_invitation_email" model="mail.template">
|
||||
<field name="name">Precheckin Invitation</field>
|
||||
<field name="model_id" ref="pms.model_pms_checkin_partner" />
|
||||
<field
|
||||
name="subject"
|
||||
>Hi ${object.firstname}, do your check-in now in ${object.pms_property_id.name}</field>
|
||||
<field
|
||||
name="email_from"
|
||||
>${object.pms_property_id.partner_id.email | safe}</field>
|
||||
<field
|
||||
name="email_to"
|
||||
>${(object.email and '"%s" <%s>' % (object.name, object.email) or object.partner_id.email_formatted or '') | safe}</field>
|
||||
<field name="body_html" type="html">
|
||||
<div>
|
||||
Do your check-in now and save time.
|
||||
<br />
|
||||
Access our<strong
|
||||
> quick registration system</strong>. In a few steps you will be able to register your data in an agile, simple and secure way,<strong
|
||||
> avoiding queues at reception</strong>.
|
||||
If you register your data in our system, <strong
|
||||
> your passage through reception will be much faster</strong>, being able to enjoy the comfort of your room right away.
|
||||
<table align="center">
|
||||
<tr>
|
||||
<td align="center" style="padding: 20px 0 0px 0; ">
|
||||
<table border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a
|
||||
href="/my/precheckin/${object.id}?access_token=${object.access_token}"
|
||||
target="_blank"
|
||||
style="text-decoration: none; color: #FFFFFF; font-size: 2em; padding: 10px 20px 10px 20px;"
|
||||
>
|
||||
<div
|
||||
style="padding: 0.5em; background-color: #45C2B1; border-color: #45C2B1; border-width: 2px;border-style:solid; border-bottom-style: solid;border-left-style: solid;border-right-style: solid;border-top-style: solid;-webkit-border-radius: 10; -moz-border-radius: 10; border-radius: 10px;font-size: 12px;"
|
||||
>Check-in
|
||||
</div>
|
||||
<center><img
|
||||
src="https://www.aldahotels.es/firma/email/llegada/check-in.png"
|
||||
alt="Hacer check-in"
|
||||
width="80px"
|
||||
height="80px"
|
||||
href="${object.url}"
|
||||
/></center></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record model="ir.sequence" id="seq_pms_folio">
|
||||
<field name="name">PMS Folio</field>
|
||||
<field name="code">pms.folio</field>
|
||||
<field name="prefix">F%(y)s</field>
|
||||
<field name="padding">5</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.sequence" id="seq_pms_reservation">
|
||||
<field name="name">PMS Reservation</field>
|
||||
<field name="code">pms.reservation</field>
|
||||
<field name="prefix">R%(y)s</field>
|
||||
<field name="padding">6</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.sequence" id="seq_pms_checkin">
|
||||
<field name="name">PMS Checkin</field>
|
||||
<field name="code">pms.checkin.partner</field>
|
||||
<field name="prefix">%(y)s</field>
|
||||
<field name="padding">6</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="traveller_report_paperformat" model="report.paperformat">
|
||||
<field name="name">Traveller Report PaperFormat</field>
|
||||
<field name="default" eval="True" />
|
||||
<field name="format">custom</field>
|
||||
<field name="page_height">200</field>
|
||||
<field name="page_width">75</field>
|
||||
<field name="orientation">Portrait</field>
|
||||
<field name="margin_top">1</field>
|
||||
<field name="margin_bottom">3</field>
|
||||
<field name="margin_left">0</field>
|
||||
<field name="margin_right">0</field>
|
||||
<field name="header_line" eval="False" />
|
||||
<field name="header_spacing">1</field>
|
||||
<field name="dpi">201</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,841 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- 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="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_0'),
|
||||
'checkin': (DateTime.today() + timedelta(days=14)),
|
||||
'checkout': (DateTime.today() + timedelta(days=16)),
|
||||
'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="user_id" ref="base.user_admin" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_3'),
|
||||
'checkin': (DateTime.today() + timedelta(days=14)),
|
||||
'checkout': (DateTime.today() + timedelta(days=15)),
|
||||
'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 arrival at Folio creation -->
|
||||
<record id="pms_folio_2" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_10" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=14)),
|
||||
'checkout': (DateTime.today() + timedelta(days=16)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=14)),
|
||||
'checkout': (DateTime.today() + timedelta(days=16)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=14)),
|
||||
'checkout': (DateTime.today() + timedelta(days=16)),
|
||||
'adults': 1,
|
||||
'state': 'cancel',
|
||||
})]"
|
||||
/>
|
||||
</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="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_4'),
|
||||
'checkin': (DateTime.today() + timedelta(days=15)),
|
||||
'checkout': (DateTime.today() + timedelta(days=16)),
|
||||
'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="user_id" ref="base.user_admin" />
|
||||
<field name="reservation_type">out</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=16)),
|
||||
'checkout': (DateTime.today() + timedelta(days=17)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'reservation_type': 'out',
|
||||
'closure_reason_id': ref('pms_room_closure_reason_0'),
|
||||
'out_service_description': 'Change of lighting',
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!-- reservation of 1 double room for 1 day-->
|
||||
<record id="pms_folio_5" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_15" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=15)),
|
||||
'checkout': (DateTime.today() + timedelta(days=16)),
|
||||
'adults': 1,
|
||||
'children':1,
|
||||
'state': 'confirm',
|
||||
'board_service_room_id': ref('pms_board_service_room_1'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!-- reservation of 1 triple room for for 1 person and 1 day-->
|
||||
<record id="pms_folio_6" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_4" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_2" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_3'),
|
||||
'checkin': (DateTime.today() + timedelta(days=15)),
|
||||
'checkout': (DateTime.today() + timedelta(days=16)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'board_service_room_id': ref('pms_board_service_room_1'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!-- reservation of all rooms for 1 day on behalf of a company -->
|
||||
<record id="pms_folio_7" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_10" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_0'),
|
||||
'checkin': (DateTime.today() + timedelta(days=17)),
|
||||
'checkout': (DateTime.today() + timedelta(days=18)),
|
||||
'adults': 2,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=17)),
|
||||
'checkout': (DateTime.today() + timedelta(days=18)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=17)),
|
||||
'checkout': (DateTime.today() + timedelta(days=18)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=17)),
|
||||
'checkout': (DateTime.today() + timedelta(days=18)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=17)),
|
||||
'checkout': (DateTime.today() + timedelta(days=18)),
|
||||
'adults': 2,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=17)),
|
||||
'checkout': (DateTime.today() + timedelta(days=18)),
|
||||
'adults': 2,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_3'),
|
||||
'checkin': (DateTime.today() + timedelta(days=17)),
|
||||
'checkout': (DateTime.today() + timedelta(days=18)),
|
||||
'adults': 3,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_4'),
|
||||
'checkin': (DateTime.today() + timedelta(days=17)),
|
||||
'checkout': (DateTime.today() + timedelta(days=18)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!-- out of service single-101 room -->
|
||||
<record id="pms_folio_8" model="pms.folio">
|
||||
<field name="partner_id" ref="main_pms_property" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="reservation_type">out</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'preferred_room_id': ref('pms_room_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=19)),
|
||||
'checkout': (DateTime.today() + timedelta(days=20)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'reservation_type': 'out',
|
||||
'closure_reason_id': ref('pms_room_closure_reason_0'),
|
||||
'out_service_description': 'Door arrangement',
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--2 reservetions in diferent rooms and diferent days-->
|
||||
<record id="pms_folio_9" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_33" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=19)),
|
||||
'checkout': (DateTime.today() + timedelta(days=20)),
|
||||
'adults': 2,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=20)),
|
||||
'checkout': (DateTime.today() + timedelta(days=21)),
|
||||
'adults': 2,
|
||||
'state': 'confirm',
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--reservation of the conference room for 3 days-->
|
||||
<record id="pms_folio_10" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_main2" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_4'),
|
||||
'checkin': (DateTime.today() + timedelta(days=19)),
|
||||
'checkout': (DateTime.today() + timedelta(days=21)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--reservation of 2 single rooms and 1 triple room-->
|
||||
<record id="pms_folio_11" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_10" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=19)),
|
||||
'checkout': (DateTime.today() + timedelta(days=20)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=19)),
|
||||
'checkout': (DateTime.today() + timedelta(days=20)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_3'),
|
||||
'checkin': (DateTime.today() + timedelta(days=19)),
|
||||
'checkout': (DateTime.today() + timedelta(days=20)),
|
||||
'adults': 3,
|
||||
'state': 'confirm',
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of economic room-->
|
||||
<record id="pms_folio_12" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_1" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'preferred_room_id': ref('pms_room_0'),
|
||||
'checkin': (DateTime.today() + timedelta(days=19)),
|
||||
'checkout': (DateTime.today() + timedelta(days=20)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of the conference room with VIP privacy closure reason-->
|
||||
<record id="pms_folio_13" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_12" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="reservation_type">normal</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_1" />
|
||||
<field name="state">cancel</field>
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'preferred_room_id': ref('pms_room_7'),
|
||||
'checkin': (DateTime.today() + timedelta(days=21)),
|
||||
'checkout': (DateTime.today() + timedelta(days=22)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'closure_reason_id': ref('pms_room_closure_reason_1'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of triple room with 2 adults and 1 children-->
|
||||
<record id="pms_folio_14" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_12" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_3'),
|
||||
'checkin': (DateTime.today() + timedelta(days=16)),
|
||||
'checkout': (DateTime.today() + timedelta(days=17)),
|
||||
'adults': 2,
|
||||
'children':1,
|
||||
'board_service_room_id': ref('pms_board_service_room_3'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of the conference room whit cancelled-->
|
||||
<!-- TODO: The reservation is marked from State: Cancelled to Pending arrival at Folio creation -->
|
||||
<record id="pms_folio_15" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_18" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="reservation_type">normal</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref ('pms_room_type_4'),
|
||||
'checkin': (DateTime.today() + timedelta(days=22)),
|
||||
'checkout': (DateTime.today() + timedelta(days=23)),
|
||||
'adults': 1,
|
||||
'state': 'cancel',
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of double room without default hours-->
|
||||
<record id="pms_folio_16" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_18" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="reservation_type">normal</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_2" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=21)),
|
||||
'checkout': (DateTime.today() + timedelta(days=22)),
|
||||
'adults': 1,
|
||||
'children': 1,
|
||||
'state': 'confirm',
|
||||
'arrival_hour': '12:00',
|
||||
'departure_hour': '12:30',
|
||||
'board_service_room_id': ref('pms_board_service_room_1'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of triple room whit draft state-->
|
||||
<!-- TODO: The reservation is marked from State: Pre-reservation to Pending arrival at Folio creation -->
|
||||
<record id="pms_folio_17" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_32" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="reservation_type">normal</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_2" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'preferred_room_id': ref('pms_room_6'),
|
||||
'checkin': (DateTime.today() + timedelta(days=20)),
|
||||
'checkout': (DateTime.today() + timedelta(days=21)),
|
||||
'adults': 3,
|
||||
'state': 'draft',
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of 2 double rooms and 1 triple room whith board service-->
|
||||
<record id="pms_folio_18" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_30" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=23)),
|
||||
'checkout': (DateTime.today() + timedelta(days=24)),
|
||||
'adults': 1,
|
||||
'children': 1,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=23)),
|
||||
'checkout': (DateTime.today() + timedelta(days=24)),
|
||||
'adults': 1,
|
||||
'children': 1,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_3'),
|
||||
'checkin': (DateTime.today() + timedelta(days=23)),
|
||||
'checkout': (DateTime.today() + timedelta(days=24)),
|
||||
'adults': 2,
|
||||
'children': 1,
|
||||
'state': 'confirm',
|
||||
'board_service_room_id': ref('pms_board_service_room_2'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of economic room and 3 single rooms whith differents board services-->
|
||||
<record id="pms_folio_19" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_18" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_0'),
|
||||
'checkin': (DateTime.today() + timedelta(days=23)),
|
||||
'checkout': (DateTime.today() + timedelta(days=24)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=23)),
|
||||
'checkout': (DateTime.today() + timedelta(days=24)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'board_service_room_id': ref('pms_board_service_room_1'),
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=23)),
|
||||
'checkout': (DateTime.today() + timedelta(days=24)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'board_service_room_id': ref('pms_board_service_room_3'),
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=23)),
|
||||
'checkout': (DateTime.today() + timedelta(days=24)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'board_service_room_id': ref('pms_board_service_room_4'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of 2 single rooms whith differents arrival and departure hours-->
|
||||
<record id="pms_folio_20" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_25" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_2" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=24)),
|
||||
'checkout': (DateTime.today() + timedelta(days=25)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'arrival_hour': '17:00',
|
||||
'departure_hour': '12:15',
|
||||
'board_service_room_id': ref('pms_board_service_room_10'),
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=24)),
|
||||
'checkout': (DateTime.today() + timedelta(days=25)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'arrival_hour': '16:00',
|
||||
'departure_hour': '11:15',
|
||||
'board_service_room_id': ref('pms_board_service_room_10'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of 2 double rooms whith differents arrival and departure hours and one room whith board service-->
|
||||
<record id="pms_folio_21" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_32" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=24)),
|
||||
'checkout': (DateTime.today() + timedelta(days=25)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'arrival_hour': '17:00',
|
||||
'departure_hour': '12:15',
|
||||
'board_service_room_id': ref('pms_board_service_room_1'),
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=24)),
|
||||
'checkout': (DateTime.today() + timedelta(days=25)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'arrival_hour': '16:00',
|
||||
'departure_hour': '11:15',
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of conference room whith lunch and dinner services-->
|
||||
<record id="pms_folio_22" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_10" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'preferred_room_id': ref('pms_room_7'),
|
||||
'checkin': (DateTime.today() + timedelta(days=24)),
|
||||
'checkout': (DateTime.today() + timedelta(days=25)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'arrival_hour': '09:00',
|
||||
'departure_hour': '12:00',
|
||||
'board_service_room_id': ref('pms_board_service_room_4'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of economic room for a week-->
|
||||
<record id="pms_folio_23" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_4" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_2" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'preferred_room_id': ref('pms_room_0'),
|
||||
'checkin': (DateTime.today() + timedelta(days=25)),
|
||||
'checkout': (DateTime.today() + timedelta(days=32)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'board_service_room_id': ref('pms_board_service_room_2'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of 1 single room for a week-->
|
||||
<record id="pms_folio_24" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_27" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'preferred_room_id': ref('pms_room_1'),
|
||||
'checkin': (DateTime.today() + timedelta(days=25)),
|
||||
'checkout': (DateTime.today() + timedelta(days=32)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'board_service_room_id': ref('pms_board_service_room_9'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of 1 single room for a week whith board service-->
|
||||
<record id="pms_folio_25" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_12" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'preferred_room_id': ref('pms_room_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=25)),
|
||||
'checkout': (DateTime.today() + timedelta(days=32)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'board_service_room_id': ref('pms_board_service_room_4'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of 2 double rooms for a week whith diferent checkouts-->
|
||||
<record id="pms_folio_26" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_27" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=25)),
|
||||
'checkout': (DateTime.today() + timedelta(days=31)),
|
||||
'adults': 2,
|
||||
'state': 'confirm',
|
||||
'board_service_room_id': ref('pms_board_service_room_6'),
|
||||
}),
|
||||
(0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_2'),
|
||||
'checkin': (DateTime.today() + timedelta(days=25)),
|
||||
'checkout': (DateTime.today() + timedelta(days=32)),
|
||||
'adults': 2,
|
||||
'state': 'confirm',
|
||||
'board_service_room_id': ref('pms_board_service_room_7'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of the conference room with VIP privacy closure reason and board service-->
|
||||
<record id="pms_folio_27" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_3" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'preferred_room_id': ref('pms_room_7'),
|
||||
'checkin': (DateTime.today() + timedelta(days=25)),
|
||||
'checkout': (DateTime.today() + timedelta(days=26)),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'closure_reason_id': ref('pms_room_closure_reason_1'),
|
||||
'board_service_room_id': ref('pms_board_service_room_4'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of 1 triple room for 1 adult and 2 children whith board service-->
|
||||
<record id="pms_folio_28" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_17" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_0" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_3'),
|
||||
'checkin': (DateTime.today() + timedelta(days=25)),
|
||||
'checkout': (DateTime.today() + timedelta(days=27)),
|
||||
'adults': 1,
|
||||
'children': 2,
|
||||
'board_service_room_id': ref('pms_board_service_room_2'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!--Reservation of 1 triple room for 1 adult and 2 children whith specific arrival and departure hours and whith board service-->
|
||||
<record id="pms_folio_29" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_25" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="channel_type_id" ref="pms.main_pms_sale_channel_2" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_3'),
|
||||
'checkin': (DateTime.today() + timedelta(days=27)),
|
||||
'checkout': (DateTime.today() + timedelta(days=28)),
|
||||
'adults': 1,
|
||||
'children': 2,
|
||||
'arrival_hour': '09:00',
|
||||
'departure_hour': '11:00',
|
||||
'board_service_room_id': ref('pms_board_service_room_2'),
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!-- reservation of 1 triple room for 1 day-->
|
||||
<record id="pms_folio_30" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_15" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_3'),
|
||||
'preferred_room_id': ref('pms_room_6'),
|
||||
'checkin': (DateTime.today() + timedelta(days=29)),
|
||||
'checkout': (DateTime.today() + timedelta(days=30)),
|
||||
'adults': 1,
|
||||
'children':1,
|
||||
'state': 'confirm',
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<!-- Cancelled Folio-->
|
||||
<record id="pms_folio_31" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_15" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_3'),
|
||||
'preferred_room_id': ref('pms_room_6'),
|
||||
'checkin': (DateTime.today() + timedelta(days=-5)),
|
||||
'checkout': (DateTime.today() + timedelta(days=-3)),
|
||||
'adults': 1,
|
||||
'children':1,
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<function model="pms.folio" name="action_cancel">
|
||||
<value eval="[ref('pms_folio_31')]" />
|
||||
</function>
|
||||
<record id="pms_folio_32" model="pms.folio">
|
||||
<field name="partner_id" ref="base.res_partner_address_15" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="agency_id" ref="pms.demo_agency_1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': ref('product.list0'),
|
||||
'room_type_id': ref('pms_room_type_3'),
|
||||
'preferred_room_id': ref('pms_room_6'),
|
||||
'checkin': (DateTime.today() + timedelta(days=-10)),
|
||||
'checkout': (DateTime.today() + timedelta(days=-7)),
|
||||
'adults': 1,
|
||||
'children':1,
|
||||
})]"
|
||||
/>
|
||||
</record>
|
||||
<function model="pms.folio" name="action_cancel">
|
||||
<value eval="[ref('pms_folio_31')]" />
|
||||
</function>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,511 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- Company -->
|
||||
<record id="pms_company1" model="res.company">
|
||||
<field name="name">Alda Company</field>
|
||||
<field name="currency_id" ref="base.EUR" />
|
||||
<field
|
||||
name="favicon"
|
||||
model="res.company"
|
||||
eval="obj()._get_default_favicon(original=True)"
|
||||
/>
|
||||
</record>
|
||||
<!--Availability Plan -->
|
||||
<record id="demo_pms_availability" model="pms.availability.plan">
|
||||
<field name="name">Availability Plan Demo</field>
|
||||
</record>
|
||||
<!-- Sequence -->
|
||||
<record model="ir.sequence" id="seq_pms_folio2">
|
||||
<field name="name">PMS Folio 2</field>
|
||||
<field name="code">pms.folio</field>
|
||||
<field name="prefix">F/%(y)s</field>
|
||||
<field name="suffix">%(sec)s</field>
|
||||
<field name="padding">4</field>
|
||||
<field name="company_id" ref="pms_company1" />
|
||||
</record>
|
||||
|
||||
<record model="ir.sequence" id="seq_pms_reservation2">
|
||||
<field name="name">PMS Reservation 2</field>
|
||||
<field name="code">pms.reservation</field>
|
||||
<field name="prefix">R/%(y)s</field>
|
||||
<field name="suffix">%(sec)s</field>
|
||||
<field name="padding">4</field>
|
||||
<field name="company_id" ref="pms_company1" />
|
||||
</record>
|
||||
|
||||
<record model="ir.sequence" id="seq_pms_checkin2">
|
||||
<field name="name">PMS Checkin 2</field>
|
||||
<field name="code">pms.checkin.partner</field>
|
||||
<field name="prefix">C/%(y)s</field>
|
||||
<field name="suffix">%(sec)s</field>
|
||||
<field name="padding">4</field>
|
||||
<field name="company_id" ref="pms_company1" />
|
||||
</record>
|
||||
|
||||
<!--Properties-->
|
||||
<record id="demo_pms_property" model="pms.property">
|
||||
<field name="name">San Carlos</field>
|
||||
<field name="company_id" ref="base.main_company" />
|
||||
<field name="default_pricelist_id" ref="product.list0" />
|
||||
<field name="folio_sequence_id" ref="pms.seq_pms_folio" />
|
||||
<field name="checkin_sequence_id" ref="pms.seq_pms_checkin" />
|
||||
<field name="reservation_sequence_id" ref="pms.seq_pms_reservation" />
|
||||
</record>
|
||||
<record id="demo_pms_property2" model="pms.property">
|
||||
<field name="name">Algalia</field>
|
||||
<field name="company_id" ref="base.main_company" />
|
||||
<field name="default_pricelist_id" ref="product.list0" />
|
||||
<field name="folio_sequence_id" ref="pms.seq_pms_folio" />
|
||||
<field name="checkin_sequence_id" ref="pms.seq_pms_checkin" />
|
||||
<field name="reservation_sequence_id" ref="pms.seq_pms_reservation" />
|
||||
</record>
|
||||
<record id="demo_pms_property3" model="pms.property">
|
||||
<field name="name">Pilgrim Leon</field>
|
||||
<field name="company_id" ref="pms_company1" />
|
||||
<field name="default_pricelist_id" ref="product.list0" />
|
||||
<field name="folio_sequence_id" ref="pms.seq_pms_folio2" />
|
||||
<field name="checkin_sequence_id" ref="pms.seq_pms_checkin2" />
|
||||
<field name="reservation_sequence_id" ref="pms.seq_pms_reservation2" />
|
||||
</record>
|
||||
<!-- users -->
|
||||
<record id="base.user_root" model="res.users">
|
||||
<field name="company_ids" eval="[(4, ref('pms.pms_company1'))]" />
|
||||
<field
|
||||
name="pms_property_ids"
|
||||
eval="[
|
||||
(4, ref('demo_pms_property')),
|
||||
(4, ref('demo_pms_property2')),
|
||||
(4, ref('demo_pms_property3')),
|
||||
]"
|
||||
/>
|
||||
</record>
|
||||
<record id="base.user_admin" model="res.users">
|
||||
<field name="company_ids" eval="[(4, ref('pms.pms_company1'))]" />
|
||||
<field
|
||||
name="pms_property_ids"
|
||||
eval="[
|
||||
(4, ref('demo_pms_property')),
|
||||
(4, ref('demo_pms_property2')),
|
||||
(4, ref('demo_pms_property3')),
|
||||
]"
|
||||
/>
|
||||
</record>
|
||||
<record id="base.user_demo" model="res.users">
|
||||
<field name="groups_id" eval="[(4,ref('pms.group_pms_user'))]" />
|
||||
<field name="company_id" ref="base.main_company" />
|
||||
<field
|
||||
name="company_ids"
|
||||
eval="[
|
||||
(4, ref('base.main_company')),
|
||||
(4, ref('pms.pms_company1')),
|
||||
]"
|
||||
/>
|
||||
<field name="pms_property_id" ref="main_pms_property" />
|
||||
<field
|
||||
name="pms_property_ids"
|
||||
eval="[
|
||||
(4, ref('main_pms_property')),
|
||||
(4, ref('demo_pms_property')),
|
||||
(4, ref('demo_pms_property2')),
|
||||
(4, ref('demo_pms_property3')),
|
||||
]"
|
||||
/>
|
||||
</record>
|
||||
<!-- pms.ubication -->
|
||||
<record id="pms_ubication_0" model="pms.ubication">
|
||||
<field name="name">Ground Floor</field>
|
||||
</record>
|
||||
<record id="pms_ubication_1" model="pms.ubication">
|
||||
<field name="name">First Floor</field>
|
||||
</record>
|
||||
<record id="pms_ubication_2" model="pms.ubication">
|
||||
<field name="name">Second Floor</field>
|
||||
</record>
|
||||
<!-- pms.amenity.type -->
|
||||
<record id="pms_amenity_type_0" model="pms.amenity.type">
|
||||
<field name="name">Toiletries</field>
|
||||
</record>
|
||||
<record id="pms_amenity_type_1" model="pms.amenity.type">
|
||||
<field name="name">Connectivity</field>
|
||||
</record>
|
||||
<record id="pms_amenity_type_2" model="pms.amenity.type">
|
||||
<field name="name">Kitchen facilities</field>
|
||||
</record>
|
||||
<!-- pms.amenity -->
|
||||
<record id="pms_amenity_0" model="pms.amenity">
|
||||
<field name="name">Shampoo and Soap</field>
|
||||
<field name="pms_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="pms_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="pms_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="pms_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="pms_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="pms_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="pms_amenity_type_id" ref="pms_amenity_type_2" />
|
||||
</record>
|
||||
<!-- pms.room.type.class -->
|
||||
<record id="pms_room_type_class_0" model="pms.room.type.class">
|
||||
<field name="name">Room</field>
|
||||
<field name="default_code">RO</field>
|
||||
</record>
|
||||
<record id="pms_room_type_class_1" model="pms.room.type.class">
|
||||
<field name="name">Conference</field>
|
||||
<field name="default_code">CO</field>
|
||||
</record>
|
||||
<!-- pms.room.type -->
|
||||
<record id="pms_room_type_0" model="pms.room.type">
|
||||
<field name="name">Economic</field>
|
||||
<field name="default_code">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'))]" />
|
||||
</record>
|
||||
<record id="pms_room_type_1" model="pms.room.type">
|
||||
<field name="name">Single</field>
|
||||
<field name="default_code">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'))]"
|
||||
/>
|
||||
</record>
|
||||
<record id="pms_room_type_2" model="pms.room.type">
|
||||
<field name="name">Double</field>
|
||||
<field name="default_code">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'))]"
|
||||
/>
|
||||
</record>
|
||||
<record id="pms_room_type_3" model="pms.room.type">
|
||||
<field name="name">Triple</field>
|
||||
<field name="default_code">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'))]"
|
||||
/>
|
||||
</record>
|
||||
<record id="pms_room_type_4" model="pms.room.type">
|
||||
<field name="name">Conference Room</field>
|
||||
<field name="default_code">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'))]"
|
||||
/>
|
||||
</record>
|
||||
<!-- 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="ubication_id" ref="pms_ubication_1" />
|
||||
<field name="capacity">2</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</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="ubication_id" ref="pms_ubication_1" />
|
||||
<field name="capacity">1</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</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="ubication_id" ref="pms_ubication_1" />
|
||||
<field name="capacity">1</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</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="ubication_id" ref="pms_ubication_1" />
|
||||
<field name="capacity">1</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</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="ubication_id" ref="pms_ubication_2" />
|
||||
<field name="capacity">2</field>
|
||||
<field name="extra_beds_allowed">1</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</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="ubication_id" ref="pms_ubication_2" />
|
||||
<field name="capacity">2</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</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="ubication_id" ref="pms_ubication_2" />
|
||||
<field name="capacity">3</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</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="ubication_id" ref="pms_ubication_0" />
|
||||
<field name="capacity">10</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<!-- 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>
|
||||
<field name="type">service</field>
|
||||
<field name="purchase_ok">False</field>
|
||||
<field name="per_day">True</field>
|
||||
<field name="per_person">True</field>
|
||||
<field name="consumed_on">after</field>
|
||||
</record>
|
||||
<record id="pms_service_1" model="product.product">
|
||||
<field name="name">Extra Bed</field>
|
||||
<field name="list_price">15.0</field>
|
||||
<field name="type">service</field>
|
||||
<field name="purchase_ok">False</field>
|
||||
<field name="per_day">True</field>
|
||||
<field name="per_person">False</field>
|
||||
<field name="daily_limit">1</field>
|
||||
<field name="is_extra_bed">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>
|
||||
<field name="type">service</field>
|
||||
<field name="purchase_ok">False</field>
|
||||
<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>
|
||||
<field name="type">service</field>
|
||||
<field name="purchase_ok">False</field>
|
||||
<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>
|
||||
<field name="type">service</field>
|
||||
<field name="purchase_ok">False</field>
|
||||
<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>
|
||||
<field name="type">service</field>
|
||||
<field name="purchase_ok">False</field>
|
||||
<field name="per_day">True</field>
|
||||
<field name="per_person">True</field>
|
||||
</record>
|
||||
<!-- pms.board.service -->
|
||||
<record id="pms_board_service_0" model="pms.board.service">
|
||||
<field name="name">BreakFast</field>
|
||||
<field name="default_code">BB</field>
|
||||
<field
|
||||
name="board_service_line_ids"
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'product_id': ref('pms_service_0'),
|
||||
'amount': 3})]"
|
||||
/>
|
||||
</record>
|
||||
<record id="pms_board_service_1" model="pms.board.service">
|
||||
<field name="name">Half Board</field>
|
||||
<field name="default_code">HB</field>
|
||||
<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})
|
||||
]"
|
||||
/>
|
||||
</record>
|
||||
<record id="pms_board_service_2" model="pms.board.service">
|
||||
<field name="name">FullBoard</field>
|
||||
<field name="default_code">FB</field>
|
||||
<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})
|
||||
]"
|
||||
/>
|
||||
</record>
|
||||
<!-- 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>
|
||||
<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>
|
||||
<record id="pms_board_service_room_2" 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_0" />
|
||||
</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" />
|
||||
</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>
|
||||
<!-- Room 2 Double -->
|
||||
<record id="pms_board_service_room_5" 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_2" />
|
||||
</record>
|
||||
<record id="pms_board_service_room_6" 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_2" />
|
||||
</record>
|
||||
<record id="pms_board_service_room_7" 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_2" />
|
||||
</record>
|
||||
<!-- Room 2 Single -->
|
||||
<record id="pms_board_service_room_8" 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_1" />
|
||||
</record>
|
||||
<record id="pms_board_service_room_9" 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_1" />
|
||||
</record>
|
||||
<record id="pms_board_service_room_10" 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_1" />
|
||||
</record>
|
||||
|
||||
|
||||
<!-- 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>
|
||||
</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>
|
||||
</record>
|
||||
<!-- pms.room.type -->
|
||||
<record id="demo_pms_room_type_0" model="pms.room.type">
|
||||
<field name="pms_property_ids" eval="[(4, ref('pms.demo_pms_property'))]" />
|
||||
<field name="name">Prop. Demo Suite</field>
|
||||
<field name="default_code">SUI</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'))]" />
|
||||
</record>
|
||||
<record id="demo_pms_room_type_1" model="pms.room.type">
|
||||
<field name="pms_property_ids" eval="[(4, ref('pms.demo_pms_property'))]" />
|
||||
<field name="name">Prop. Demo Views</field>
|
||||
<field name="default_code">VIE</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'))]"
|
||||
/>
|
||||
</record>
|
||||
<!-- Agencies -->
|
||||
<record id="demo_agency_0" model="res.partner">
|
||||
<field name="is_agency">True</field>
|
||||
<field name="sale_channel_id" ref="pms.main_pms_sale_channel_3" />
|
||||
<field name="name">Agency 000</field>
|
||||
<field name="street">1st St</field>
|
||||
<field name="city">Fremont</field>
|
||||
<field name="phone">(870)-333-0515</field>
|
||||
<field name="country_id" ref="base.us" />
|
||||
<field name="email">agency000@example.com</field>
|
||||
<field name="website">http://www.agency000travel.com</field>
|
||||
<field
|
||||
name="image_1920"
|
||||
type="base64"
|
||||
file="pms/static/description/agency_logo.png"
|
||||
/>
|
||||
</record>
|
||||
<record id="demo_agency_1" model="res.partner">
|
||||
<field name="is_agency">True</field>
|
||||
<field name="sale_channel_id" ref="pms.main_pms_sale_channel_3" />
|
||||
<field name="name">Agency 111</field>
|
||||
<field name="street">2st St</field>
|
||||
<field name="city">Stockton</field>
|
||||
<field name="phone">(872)-941-0441</field>
|
||||
<field name="country_id" ref="base.us" />
|
||||
<field name="email">agency111@example.com</field>
|
||||
<field name="website">http://www.agency1travel.com</field>
|
||||
<field
|
||||
name="image_1920"
|
||||
type="base64"
|
||||
file="pms/static/description/agency_logo1.png"
|
||||
/>
|
||||
</record>
|
||||
<!-- Add partner mobile -->
|
||||
<record id="base.res_partner_12" model="res.partner">
|
||||
<field name="mobile">645773288</field>
|
||||
</record>
|
||||
<record id="base.res_partner_address_15" model="res.partner">
|
||||
<field name="mobile">666777888</field>
|
||||
</record>
|
||||
<record id="base.res_partner_address_28" model="res.partner">
|
||||
<field name="mobile">611567888</field>
|
||||
</record>
|
||||
<record id="base.res_partner_address_16" model="res.partner">
|
||||
<field name="mobile">610067000</field>
|
||||
</record>
|
||||
<record id="base.res_partner_address_10" model="res.partner">
|
||||
<field name="mobile">689017000</field>
|
||||
</record>
|
||||
<record id="base.res_partner_4" model="res.partner">
|
||||
<field name="mobile">633773338</field>
|
||||
</record>
|
||||
<record id="base.res_partner_address_27" model="res.partner">
|
||||
<field name="mobile">678112438</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,491 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- Economic -->
|
||||
<record id="pms_reservation_0" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_27" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_0" />
|
||||
<field name="adults">1</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(8)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(9)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_2" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_1" model="pms.reservation">
|
||||
<field name="partner_id" ref="main_pms_property" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="reservation_type">out</field>
|
||||
<field name="room_type_id" ref="pms_room_type_0" />
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(-3)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(-1)" />
|
||||
<field name="closure_reason_id" ref="pms_room_closure_reason_1" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_2" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_28" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_0" />
|
||||
<field name="adults">2</field>
|
||||
<field name="state">onboard</field>
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_address_28'),
|
||||
'state': 'onboard'
|
||||
}),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_12'),
|
||||
'state': 'onboard'
|
||||
}),
|
||||
]"
|
||||
/>
|
||||
<field name="checkin" eval="DateTime.today()" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(1)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_1" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_3" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_13" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_0" />
|
||||
<field name="adults">1</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(1)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(4)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_4" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_16" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_0" />
|
||||
<field name="adults">2</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(4)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(5)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_5" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_33" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_0" />
|
||||
<field name="adults">1</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(5)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(7)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<!-- Single -->
|
||||
<record id="pms_reservation_6" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_27" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_1" />
|
||||
<field name="adults">1</field>
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_address_27'),
|
||||
'state': 'onboard'
|
||||
}),
|
||||
]"
|
||||
/>
|
||||
<field name="checkin" eval="DateTime.today()" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(3)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_2" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_7" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_10" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_1" />
|
||||
<field name="adults">1</field>
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_address_10'),
|
||||
}),
|
||||
]"
|
||||
/>
|
||||
<field name="checkin" eval="DateTime.today()" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(3)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_0" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_8" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_13" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_1" />
|
||||
<field name="adults">1</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(7)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(8)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_1" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_9" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_15" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_1" />
|
||||
<field name="adults">1</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(9)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(13)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_10" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_10" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_1" />
|
||||
<field name="adults">1</field>
|
||||
<field name="children">1</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(13)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(14)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_11" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_10" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_1" />
|
||||
<field name="adults">1</field>
|
||||
<field name="checkin" eval="DateTime.today()" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(4)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_2" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_12" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_10" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_1" />
|
||||
<field name="adults">1</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(6)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(10)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<!-- Double-->
|
||||
<record id="pms_reservation_13" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_12" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="adults">2</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(11)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(13)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_0" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_14" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_33" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="adults">2</field>
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {'partner_id': ref('base.res_partner_12')}),
|
||||
(0, 0, {'partner_id': ref('base.res_partner_18')}),
|
||||
]"
|
||||
/>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(6)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(8)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_15" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_10" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="adults">1</field>
|
||||
<field name="children">1</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(10)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(11)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_3" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_16" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_13" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="adults">2</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(4)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(6)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_17" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_15" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="adults">2</field>
|
||||
<field name="checkin" eval="DateTime.today()" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(4)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_2" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_18" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_12" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="adults">2</field>
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {'partner_id': ref('base.res_partner_18')}),
|
||||
(0, 0, {'partner_id': ref('base.res_partner_12')}),
|
||||
]"
|
||||
/>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(11)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(13)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_19" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_32" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="adults">2</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(6)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(8)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_1" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_20" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_15" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="adults">1</field>
|
||||
<field name="children">1</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(10)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(11)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_21" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_3" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="adults">2</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(4)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(6)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_0" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_22" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_12" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="adults">2</field>
|
||||
<field name="checkin" eval="DateTime.today()" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(4)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<!-- Triple -->
|
||||
<record id="pms_reservation_23" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_4" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_3" />
|
||||
<field name="adults">3</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(11)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(13)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_2" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_24" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_12" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_3" />
|
||||
<field name="adults">3</field>
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {'partner_id': ref('base.res_partner_10')}),
|
||||
(0, 0, {'partner_id': ref('base.res_partner_address_10')}),
|
||||
(0, 0, {'partner_id': ref('base.res_partner_address_18')}),
|
||||
]"
|
||||
/>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(6)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(8)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_25" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_28" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_3" />
|
||||
<field name="adults">1</field>
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {'partner_id': ref('base.res_partner_3')}),
|
||||
]"
|
||||
/>
|
||||
<field name="children">2</field>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(10)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(11)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_3" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_26" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_16" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_3" />
|
||||
<field name="adults">3</field>
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {'partner_id': ref('base.res_partner_3')}),
|
||||
(0, 0, {'partner_id': ref('base.res_partner_address_14')}),
|
||||
(0, 0, {'partner_id': ref('base.res_partner_address_33')}),
|
||||
]"
|
||||
/>
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(4)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(6)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_27" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_12" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_3" />
|
||||
<field name="adults">2</field>
|
||||
<field name="children">1</field>
|
||||
<field name="state">onboard</field>
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_12'),
|
||||
'state': 'onboard'
|
||||
}),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_2'),
|
||||
'state': 'onboard'
|
||||
}),
|
||||
]"
|
||||
/>
|
||||
<field name="checkin" eval="DateTime.today()" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(4)" />
|
||||
<field name="board_service_room_id" ref="pms_board_service_room_2" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<!-- Open talk away -->
|
||||
<record id="pms_reservation_28" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_27" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_4" />
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(10)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(12)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_29" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_32" />
|
||||
<field name="user_id" ref="base.user_demo" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_4" />
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(1)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(4)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<record id="pms_reservation_30" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_33" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_4" />
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(6)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(8)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<!-- Past Reservation -->
|
||||
<record id="pms_reservation_31" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_33" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_4" />
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(-10)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(-5)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field name="allowed_checkout">True</field>
|
||||
<field name="checkin_partner_pending_count">0</field>
|
||||
<field name="folio_payment_state">paid</field>
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_12'),
|
||||
'state': 'done'
|
||||
}),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_2'),
|
||||
'state': 'done'
|
||||
}),
|
||||
]"
|
||||
/>
|
||||
<field name="state">done</field>
|
||||
</record>
|
||||
<!-- Cancelled Reservation -->
|
||||
<record id="pms_reservation_32" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_address_32" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(50)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(53)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_3'),
|
||||
}),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_4'),
|
||||
}),
|
||||
]"
|
||||
/>
|
||||
</record>
|
||||
<function model="pms.reservation" name="action_cancel">
|
||||
<value eval="[ref('pms_reservation_32')]" />
|
||||
</function>
|
||||
<record id="pms_reservation_33" model="pms.reservation">
|
||||
<field name="partner_id" ref="base.res_partner_12" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="room_type_id" ref="pms_room_type_2" />
|
||||
<field name="checkin" eval="DateTime.today() + timedelta(-20)" />
|
||||
<field name="checkout" eval="DateTime.today() + timedelta(-12)" />
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
eval="[(5, 0),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_3'),
|
||||
}),
|
||||
(0, 0, {
|
||||
'partner_id': ref('base.res_partner_4'),
|
||||
}),
|
||||
]"
|
||||
/>
|
||||
</record>
|
||||
<function model="pms.reservation" name="action_cancel">
|
||||
<value eval="[ref('pms_reservation_32')]" />
|
||||
</function>
|
||||
</data>
|
||||
</odoo>
|
||||
8492
pms/i18n/es.po
8492
pms/i18n/es.po
File diff suppressed because it is too large
Load Diff
10260
pms/i18n/pms.pot
10260
pms/i18n/pms.pot
File diff suppressed because it is too large
Load Diff
@@ -1,16 +0,0 @@
|
||||
from odoo import SUPERUSER_ID
|
||||
from odoo.api import Environment
|
||||
|
||||
|
||||
def pre_init_hook(cr):
|
||||
with Environment.manage():
|
||||
env = Environment(cr, SUPERUSER_ID, {})
|
||||
ResConfig = env["res.config.settings"]
|
||||
default_values = ResConfig.default_get(list(ResConfig.fields_get()))
|
||||
default_values.update(
|
||||
{"group_product_pricelist": True, "group_sale_pricelist": True}
|
||||
)
|
||||
ResConfig.sudo().create(default_values).execute()
|
||||
env["ir.config_parameter"].sudo().set_param(
|
||||
"product.product_pricelist_setting", "advanced"
|
||||
)
|
||||
@@ -1,50 +0,0 @@
|
||||
# Copyright 2018 Alexandre Díaz
|
||||
# Copyright 2018 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import ir_http
|
||||
from . import ir_config_parameter
|
||||
|
||||
# from . import payment_return
|
||||
from . import pms_board_service_room_type
|
||||
from . import pms_property
|
||||
from . import res_users
|
||||
from . import pms_ubication
|
||||
from . import pms_folio
|
||||
from . import pms_reservation
|
||||
from . import pms_room
|
||||
from . import pms_amenity
|
||||
from . import pms_amenity_type
|
||||
from . import pms_room_type
|
||||
from . import pms_service
|
||||
from . import account_move
|
||||
from . import product_template
|
||||
from . import product_product
|
||||
from . import res_company
|
||||
from . import account_payment
|
||||
from . import pms_availability_plan
|
||||
from . import pms_availability_plan_rule
|
||||
from . import pms_reservation_line
|
||||
from . import pms_checkin_partner
|
||||
from . import product_pricelist
|
||||
from . import product_pricelist_item
|
||||
from . import res_partner
|
||||
from . import pms_sale_channel
|
||||
|
||||
from . import mail_compose_message
|
||||
from . import pms_room_type_class
|
||||
from . import pms_room_closure_reason
|
||||
from . import pms_service_line
|
||||
from . import pms_board_service
|
||||
from . import pms_board_service_room_type_line
|
||||
from . import pms_board_service_line
|
||||
from . import account_move_line
|
||||
from . import pms_cancelation_rule
|
||||
from . import folio_sale_line
|
||||
from . import account_bank_statement_line
|
||||
from . import account_bank_statement
|
||||
from . import account_journal
|
||||
from . import pms_availability
|
||||
from . import res_partner_id_number
|
||||
from . import pms_automated_mails
|
||||
from . import payment_transaction
|
||||
@@ -1,16 +0,0 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AccountBankStatement(models.Model):
|
||||
_inherit = "account.bank.statement"
|
||||
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Properties with access to the element",
|
||||
copy=False,
|
||||
comodel_name="pms.property",
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
string="Company",
|
||||
help="The company for Account Bank Statement",
|
||||
)
|
||||
@@ -1,46 +0,0 @@
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AccountBankStatementLine(models.Model):
|
||||
_inherit = "account.bank.statement.line"
|
||||
|
||||
folio_ids = fields.Many2many(
|
||||
string="Folios",
|
||||
comodel_name="pms.folio",
|
||||
ondelete="cascade",
|
||||
relation="account_bank_statement_folio_rel",
|
||||
column1="account_journal_id",
|
||||
column2="folio_id",
|
||||
)
|
||||
reservation_ids = fields.Many2many(
|
||||
string="Reservations",
|
||||
help="Reservations in which the Account Bank Statement Lines are included",
|
||||
comodel_name="pms.reservation",
|
||||
ondelete="cascade",
|
||||
relation="account_bank_statement_reservation_rel",
|
||||
column1="account_bank_statement_id",
|
||||
column2="reservation_id",
|
||||
)
|
||||
service_ids = fields.Many2many(
|
||||
string="Services",
|
||||
help="Services in which the Account Bank Statement Lines are included",
|
||||
comodel_name="pms.service",
|
||||
ondelete="cascade",
|
||||
relation="account_bank_statement_service_rel",
|
||||
column1="account_bank_statement_id",
|
||||
column2="service_id",
|
||||
)
|
||||
|
||||
@api.model
|
||||
def _prepare_move_line_default_vals(self, counterpart_account_id=None):
|
||||
line_vals_list = super(
|
||||
AccountBankStatementLine, self
|
||||
)._prepare_move_line_default_vals(counterpart_account_id)
|
||||
if self.folio_ids:
|
||||
for line in line_vals_list:
|
||||
line.update(
|
||||
{
|
||||
"folio_ids": [(6, 0, self.folio_ids.ids)],
|
||||
}
|
||||
)
|
||||
return line_vals_list
|
||||
@@ -1,25 +0,0 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AccountJournal(models.Model):
|
||||
_inherit = "account.journal"
|
||||
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
ondelete="restrict",
|
||||
relation="account_journal_pms_property_rel",
|
||||
column1="account_journal_id",
|
||||
column2="pms_property_id",
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
string="Company",
|
||||
help="The company for Account Jouarnal",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
allowed_pms_payments = fields.Boolean(
|
||||
string="For manual payments",
|
||||
help="Use to pay for reservations",
|
||||
)
|
||||
@@ -1,126 +0,0 @@
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||
import json
|
||||
|
||||
from odoo import _, fields, models
|
||||
from odoo.tools import float_is_zero
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_inherit = "account.move"
|
||||
|
||||
# Field Declarations
|
||||
folio_ids = fields.Many2many(
|
||||
string="Folios",
|
||||
help="Folios where the account move are included",
|
||||
comodel_name="pms.folio",
|
||||
compute="_compute_folio_origin",
|
||||
relation="account_move_folio_ids_rel",
|
||||
column1="account_move_id",
|
||||
column2="folio_ids_id",
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Property with access to the element",
|
||||
comodel_name="pms.property",
|
||||
)
|
||||
outstanding_folios_debits_widget = fields.Text(
|
||||
compute="_compute_get_outstanding_folios_JSON"
|
||||
)
|
||||
has_folios_outstanding = fields.Boolean(
|
||||
compute="_compute_get_outstanding_folios_JSON"
|
||||
)
|
||||
|
||||
def _compute_folio_origin(self):
|
||||
for inv in self:
|
||||
inv.folio_ids = False
|
||||
folios = inv.mapped("invoice_line_ids.folio_ids")
|
||||
if folios:
|
||||
inv.folio_ids = [(6, 0, folios.ids)]
|
||||
|
||||
def _compute_get_outstanding_folios_JSON(self):
|
||||
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
|
||||
)
|
||||
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")
|
||||
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)
|
||||
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:
|
||||
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)
|
||||
if float_is_zero(
|
||||
amount_to_show, precision_rounding=self.currency_id.rounding
|
||||
):
|
||||
continue
|
||||
if 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
|
||||
self.outstanding_folios_debits_widget = json.dumps(info)
|
||||
self.has_folio_outstanding = True
|
||||
|
||||
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)],
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
# 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
|
||||
|
||||
|
||||
class AccountMoveLine(models.Model):
|
||||
_inherit = "account.move.line"
|
||||
|
||||
# Fields declaration
|
||||
# TODO: REVIEW why not a Many2one?
|
||||
folio_line_ids = fields.Many2many(
|
||||
string="Folio Lines",
|
||||
help="The folio lines in the account move lines",
|
||||
copy=False,
|
||||
comodel_name="folio.sale.line",
|
||||
relation="folio_sale_line_invoice_rel",
|
||||
column1="invoice_line_id",
|
||||
column2="sale_line_id",
|
||||
)
|
||||
folio_ids = fields.Many2many(
|
||||
string="Folios",
|
||||
comodel_name="pms.folio",
|
||||
relation="payment_folio_rel",
|
||||
column1="move_id",
|
||||
column2="folio_id",
|
||||
)
|
||||
name_changed_by_user = fields.Boolean(
|
||||
string="Custom label",
|
||||
readonly=False,
|
||||
default=False,
|
||||
store=True,
|
||||
compute="_compute_name_changed_by_user",
|
||||
)
|
||||
|
||||
@api.depends("name")
|
||||
def _compute_name_changed_by_user(self):
|
||||
for record in self:
|
||||
# if not record._context.get("auto_name"):
|
||||
if not self._context.get("auto_name"):
|
||||
record.name_changed_by_user = True
|
||||
else:
|
||||
record.name_changed_by_user = False
|
||||
|
||||
name = fields.Char(
|
||||
compute="_compute_name",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
|
||||
@api.depends("quantity")
|
||||
def _compute_name(self):
|
||||
for record in self:
|
||||
record.name = self.env["folio.sale.line"].generate_folio_sale_name(
|
||||
record.folio_line_ids.reservation_id,
|
||||
record.product_id,
|
||||
record.folio_line_ids.service_id,
|
||||
record.folio_line_ids.reservation_line_ids,
|
||||
record.folio_line_ids.service_line_ids,
|
||||
qty=record.quantity,
|
||||
)
|
||||
# TODO: check why this code doesn't work
|
||||
# if not record.name_changed_by_user:
|
||||
# record.with_context(auto_name=True).name = self
|
||||
# .env["folio.sale.line"].generate_folio_sale_name(
|
||||
# record.folio_line_ids.service_id,
|
||||
# record.folio_line_ids.reservation_line_ids,
|
||||
# record.product_id,
|
||||
# qty=record.quantity)
|
||||
# record.with_context(auto_name=True)
|
||||
# ._compute_name_changed_by_user()
|
||||
|
||||
def _copy_data_extend_business_fields(self, values):
|
||||
super(AccountMoveLine, self)._copy_data_extend_business_fields(values)
|
||||
values["folio_line_ids"] = [(6, None, self.folio_line_ids.ids)]
|
||||
@@ -1,104 +0,0 @@
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AccountPayment(models.Model):
|
||||
_inherit = "account.payment"
|
||||
|
||||
# Fields declaration
|
||||
folio_ids = fields.Many2many(
|
||||
string="Folios",
|
||||
comodel_name="pms.folio",
|
||||
ondelete="cascade",
|
||||
relation="account_payment_folio_rel",
|
||||
column1="payment_id",
|
||||
column2="folio_id",
|
||||
)
|
||||
|
||||
def _prepare_move_line_default_vals(self, write_off_line_vals=None):
|
||||
line_vals_list = super(AccountPayment, self)._prepare_move_line_default_vals(
|
||||
write_off_line_vals
|
||||
)
|
||||
if self.folio_ids:
|
||||
for line in line_vals_list:
|
||||
line.update(
|
||||
{
|
||||
"folio_ids": [(6, 0, self.folio_ids.ids)],
|
||||
}
|
||||
)
|
||||
return line_vals_list
|
||||
|
||||
# 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",
|
||||
# }
|
||||
# self.update(vals)
|
||||
# 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,
|
||||
# )
|
||||
# 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 += _("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)
|
||||
|
||||
# def delete(self):
|
||||
# msg = False
|
||||
# if self.folio_id:
|
||||
# msg = _("Deleted payment: %s %s ") % (self.amount, self.currency_id.symbol)
|
||||
# self.cancel()
|
||||
# self.move_name = ""
|
||||
# self.unlink()
|
||||
# if 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)
|
||||
|
||||
# def modify_payment(self):
|
||||
# self.ensure_one()
|
||||
# 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,
|
||||
# }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,22 +0,0 @@
|
||||
from odoo import _, api, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class IrConfigParameter(models.Model):
|
||||
_inherit = "ir.config_parameter"
|
||||
|
||||
def unlink(self):
|
||||
for record in self:
|
||||
if (
|
||||
record.key == "product.product_pricelist_setting"
|
||||
and record.value == "advanced"
|
||||
):
|
||||
raise ValidationError(_("Cannot delete this parameter"))
|
||||
return super().unlink()
|
||||
|
||||
@api.constrains("key", "value")
|
||||
def check_value(self):
|
||||
if self.key == "product.product_pricelist_setting" and self.value != "advanced":
|
||||
raise ValidationError(
|
||||
_("The parameter Advanced price rules cannot be modified")
|
||||
)
|
||||
@@ -1,50 +0,0 @@
|
||||
# Copyright 2019 Pablo Quesada
|
||||
# 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
|
||||
|
||||
|
||||
class IrHttp(models.AbstractModel):
|
||||
_inherit = "ir.http"
|
||||
|
||||
def session_info(self):
|
||||
res = super().session_info()
|
||||
user = request.env.user
|
||||
res.update(
|
||||
{
|
||||
# current_pms_property should be default_property
|
||||
"user_pms_properties": {
|
||||
"current_pms_property": (
|
||||
user.pms_property_id.id,
|
||||
user.pms_property_id.name,
|
||||
),
|
||||
# TODO: filter all properties based on
|
||||
# the current set of active companies
|
||||
"allowed_pms_properties": [
|
||||
(property.id, property.name)
|
||||
for property in user.pms_property_ids
|
||||
],
|
||||
},
|
||||
"display_switch_pms_property_menu": len(user.pms_property_ids) > 1,
|
||||
}
|
||||
)
|
||||
# TODO: This user context update should be placed in other function ¿?
|
||||
res["user_context"].update(
|
||||
{
|
||||
"allowed_pms_property_ids": [
|
||||
(property.id) for property in user.pms_property_ids
|
||||
]
|
||||
}
|
||||
)
|
||||
# TODO: update current_company based on current_pms_property
|
||||
# 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
|
||||
# else:
|
||||
# raise MissingError(
|
||||
# _("Wrong property and company access settings for this user. "
|
||||
# "Please review property and company for user %s") % user.name)
|
||||
|
||||
return res
|
||||
@@ -1,45 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class MailComposeMessage(models.TransientModel):
|
||||
_inherit = "mail.compose.message"
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
res = super(MailComposeMessage, self).default_get(fields)
|
||||
template = self.env["mail.template"].browse(self._context.get("template_id"))
|
||||
res.update(
|
||||
{
|
||||
"composition_mode": "comment",
|
||||
"attachment_ids": False,
|
||||
"template_id": template.id,
|
||||
}
|
||||
)
|
||||
return res
|
||||
|
||||
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")
|
||||
# ):
|
||||
# # TODO: WorkFlow Mails
|
||||
# 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
|
||||
# ]
|
||||
# if any(cmds):
|
||||
# folio.reservation_ids = cmds
|
||||
res = super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)
|
||||
if self._context.get("record_id"):
|
||||
folio = self.env["pms.folio"].search(
|
||||
[("id", "=", self._context.get("record_id"))]
|
||||
)
|
||||
reservations = folio.reservation_ids
|
||||
for reservation in reservations:
|
||||
reservation.is_mail_send = True
|
||||
return res
|
||||
@@ -1,45 +0,0 @@
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from openerp import fields, models
|
||||
|
||||
|
||||
class PaymentReturn(models.Model):
|
||||
_inherit = "payment.return"
|
||||
|
||||
# Fields declaration
|
||||
folio_id = fields.Many2one(
|
||||
string="Folio", help="Folio in payment return", comodel_name="pms.folio"
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Property with access to the element",
|
||||
store=True,
|
||||
readonly=True,
|
||||
comodel_name="pms.property",
|
||||
related="folio_id.pms_property_id",
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
string="Company",
|
||||
help="The company for Payment Return",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
|
||||
def action_confirm(self):
|
||||
pay = super(PaymentReturn, self).action_confirm()
|
||||
if pay:
|
||||
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")
|
||||
)
|
||||
# for folio in folios_line:
|
||||
# if self.id not in folio.return_ids.ids:
|
||||
# folio.update({"return_ids": [(4, self.id)]})
|
||||
# msg = _("Return of %s registered") % (line.amount)
|
||||
# folio.message_post(subject=_("Payment Return"), body=msg)
|
||||
folios += folios_line
|
||||
folios.compute_amount()
|
||||
@@ -1,43 +0,0 @@
|
||||
from odoo import _, fields, models
|
||||
|
||||
|
||||
class PaymentTransaction(models.Model):
|
||||
_inherit = "payment.transaction"
|
||||
|
||||
folio_ids = fields.Many2many(
|
||||
string="Folios",
|
||||
comodel_name="pms.folio",
|
||||
ondelete="cascade",
|
||||
relation="payment_transaction_folio_rel",
|
||||
column1="payment_transaction_id",
|
||||
column2="folio_id",
|
||||
)
|
||||
|
||||
def _create_payment(self, add_payment_vals=False):
|
||||
self.ensure_one()
|
||||
if not add_payment_vals:
|
||||
add_payment_vals = {}
|
||||
if self.folio_ids:
|
||||
add_payment_vals["folio_ids"] = [(6, 0, self.folio_ids.ids)]
|
||||
return super(PaymentTransaction, self)._create_payment(add_payment_vals)
|
||||
|
||||
def render_folio_button(self, folio, submit_txt=None, render_values=None):
|
||||
self.reference = folio.name
|
||||
values = {
|
||||
"partner_id": folio.partner_id.id,
|
||||
"type": self.type,
|
||||
}
|
||||
if render_values:
|
||||
values.update(render_values)
|
||||
return (
|
||||
self.acquirer_id.with_context(
|
||||
submit_class="btn btn-primary", submit_txt=submit_txt or _("Pay Now")
|
||||
)
|
||||
.sudo()
|
||||
.render(
|
||||
self.reference,
|
||||
folio.pending_amount,
|
||||
folio.currency_id.id,
|
||||
values=values,
|
||||
)
|
||||
)
|
||||
@@ -1,46 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class PmsRoomAmenity(models.Model):
|
||||
_name = "pms.amenity"
|
||||
_description = "Room amenity"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
active = fields.Boolean(
|
||||
string="Active",
|
||||
help="Determines if amenity is active",
|
||||
default=True,
|
||||
)
|
||||
name = fields.Char(
|
||||
string="Amenity Name",
|
||||
help="Amenity Name",
|
||||
required=True,
|
||||
translate=True,
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
ondelete="restrict",
|
||||
relation="pms_amenity_pms_property_rel",
|
||||
column1="amenity_id",
|
||||
column2="pms_property_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_amenity_type_id = fields.Many2one(
|
||||
string="Amenity Category",
|
||||
help="Segment the amenities by categories (multimedia, comfort, etc ...)",
|
||||
comodel_name="pms.amenity.type",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
default_code = fields.Char(
|
||||
string="Internal Reference", help="Internal unique identifier of the amenity"
|
||||
)
|
||||
is_add_code_room_name = fields.Boolean(
|
||||
string="Add in room name",
|
||||
help="True if the Internal Reference should appear in the display name of the rooms",
|
||||
)
|
||||
@@ -1,40 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class PmsRoomAmenityType(models.Model):
|
||||
_name = "pms.amenity.type"
|
||||
_description = "Amenity Type"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
active = fields.Boolean(
|
||||
string="Active",
|
||||
help="Determines if amenity type is active",
|
||||
default=True,
|
||||
)
|
||||
name = fields.Char(
|
||||
string="Amenity Type Name",
|
||||
help="Amenity Type Name",
|
||||
required=True,
|
||||
translate=True,
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
ondelete="restrict",
|
||||
relation="pms_amenity_type_pms_property_rel",
|
||||
column1="amenity_type_id",
|
||||
column2="pms_property_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_amenity_ids = fields.One2many(
|
||||
string="Amenities In This Category",
|
||||
help="Amenities included in this type",
|
||||
comodel_name="pms.amenity",
|
||||
inverse_name="pms_amenity_type_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
@@ -1,367 +0,0 @@
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class PmsAutomatedMails(models.Model):
|
||||
_name = "pms.automated.mails"
|
||||
_description = "Automatic Mails"
|
||||
|
||||
name = fields.Char(string="Name", help="Name of the automated mail.", required=True)
|
||||
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Property",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
)
|
||||
|
||||
automated_actions_id = fields.Many2one(
|
||||
string="Automated Actions",
|
||||
help="automated action that is created when creating automated emails ",
|
||||
comodel_name="base.automation",
|
||||
)
|
||||
|
||||
time = fields.Integer(string="Time", help="Amount of time")
|
||||
|
||||
time_type = fields.Selection(
|
||||
string="Time Range",
|
||||
help="Type of date range",
|
||||
selection=[
|
||||
("minutes", "Minutes"),
|
||||
("hour", "Hour"),
|
||||
("day", "Days"),
|
||||
("month", "Months"),
|
||||
],
|
||||
default="day",
|
||||
)
|
||||
template_id = fields.Many2one(
|
||||
string="Template",
|
||||
help="The template that will be sent by email",
|
||||
comodel_name="mail.template",
|
||||
required=True,
|
||||
)
|
||||
|
||||
action = fields.Selection(
|
||||
string="Action",
|
||||
help="The action that will cause the email to be sent ",
|
||||
selection=[
|
||||
("creation", "Reservation creation"),
|
||||
("write", "Reservation modification"),
|
||||
("cancel", "Reservation cancellation"),
|
||||
("checkin", "Checkin"),
|
||||
("checkout", "Checkout"),
|
||||
("payment", "Payment"),
|
||||
("invoice", "Invoice"),
|
||||
],
|
||||
default="creation",
|
||||
required=True,
|
||||
)
|
||||
|
||||
moment = fields.Selection(
|
||||
string="Moment",
|
||||
help="Moment in relation to the action in which the email will be sent",
|
||||
selection=[
|
||||
("before", "Before"),
|
||||
("after", "After"),
|
||||
("in_act", "In the act"),
|
||||
],
|
||||
default="before",
|
||||
)
|
||||
|
||||
active = fields.Boolean(
|
||||
string="Active", help="Indicates if the automated mail is active", default=True
|
||||
)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
name = vals.get("name")
|
||||
action = vals.get("action")
|
||||
time = vals.get("time")
|
||||
date_range_type = vals.get("time_type")
|
||||
template_id = vals.get("template_id")
|
||||
active = vals.get("active")
|
||||
moment = vals.get("moment")
|
||||
properties = vals.get("pms_property_ids")
|
||||
is_create = True
|
||||
if action in ("creation", "write", "cancel", "invoice") and moment == "before":
|
||||
raise UserError(_("The moment for this action cannot be 'Before'"))
|
||||
dict_val = self._prepare_automated_actions_id(
|
||||
action, time, moment, properties, is_create
|
||||
)
|
||||
action_server_vals = {
|
||||
"name": name,
|
||||
"state": "email",
|
||||
"usage": "ir_cron",
|
||||
"model_id": dict_val["model_id"],
|
||||
}
|
||||
action_server = self.env["ir.actions.server"].create(action_server_vals)
|
||||
automated_actions_vals = {
|
||||
"active": active,
|
||||
"action_server_id": action_server.id,
|
||||
"trigger": dict_val["trigger"],
|
||||
"filter_domain": dict_val["filter_domain"],
|
||||
"filter_pre_domain": dict_val["filter_pre_domain"],
|
||||
"trg_date_range": dict_val["time"],
|
||||
"trg_date_range_type": date_range_type,
|
||||
"template_id": template_id,
|
||||
}
|
||||
model_field = dict_val["model_field"]
|
||||
if model_field:
|
||||
automated_actions_vals.update(
|
||||
{
|
||||
"trg_date_id": dict_val["model_field"].id,
|
||||
}
|
||||
)
|
||||
trigger_field = dict_val["trigger_fields"]
|
||||
if trigger_field:
|
||||
automated_actions_vals.update(
|
||||
{
|
||||
"trigger_field_ids": dict_val["trigger_fields"].ids,
|
||||
}
|
||||
)
|
||||
automated_action = self.env["base.automation"].create(automated_actions_vals)
|
||||
vals.update({"automated_actions_id": automated_action.id})
|
||||
return super(PmsAutomatedMails, self).create(vals)
|
||||
|
||||
def write(self, vals):
|
||||
result = super(PmsAutomatedMails, self).write(vals)
|
||||
is_create = False
|
||||
if (
|
||||
self.action in ("creation", "write", "cancel", "invoice")
|
||||
and self.moment == "before"
|
||||
):
|
||||
raise UserError(_("The moment for this action cannot be 'Before'"))
|
||||
dict_val = self._prepare_automated_actions_id(
|
||||
self.action, self.time, self.moment, self.pms_property_ids, is_create
|
||||
)
|
||||
automated_actions_id = self.automated_actions_id
|
||||
action_server = automated_actions_id.action_server_id
|
||||
action_server_vals = {
|
||||
"name": self.name,
|
||||
"state": "email",
|
||||
"usage": "ir_cron",
|
||||
"model_id": dict_val["model_id"],
|
||||
}
|
||||
action_server.write(action_server_vals)
|
||||
automated_actions_vals = {
|
||||
"active": self.active,
|
||||
"action_server_id": action_server.id,
|
||||
"trigger": dict_val["trigger"],
|
||||
"filter_domain": dict_val["filter_domain"],
|
||||
"filter_pre_domain": dict_val["filter_pre_domain"],
|
||||
"trg_date_range": dict_val["time"],
|
||||
"trg_date_range_type": self.time_type,
|
||||
"template_id": self.template_id,
|
||||
}
|
||||
model_field = dict_val["model_field"]
|
||||
if model_field:
|
||||
automated_actions_vals.update(
|
||||
{
|
||||
"trg_date_id": dict_val["model_field"].id,
|
||||
}
|
||||
)
|
||||
trigger_field = dict_val["trigger_fields"]
|
||||
if trigger_field:
|
||||
automated_actions_vals.update(
|
||||
{
|
||||
"trigger_field_ids": dict_val["trigger_fields"].ids,
|
||||
}
|
||||
)
|
||||
automated_actions_id.write(automated_actions_vals)
|
||||
vals.update({"automated_actions_id": automated_actions_id.id})
|
||||
return result
|
||||
|
||||
def unlink(self):
|
||||
automated_actions_id = self.automated_actions_id
|
||||
action_server = automated_actions_id.action_server_id
|
||||
automated_actions_id.unlink()
|
||||
action_server.unlink()
|
||||
return super(PmsAutomatedMails, self).unlink()
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_creation_action(self, moment, time):
|
||||
model_field = False
|
||||
model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
|
||||
if moment == "in_act":
|
||||
trigger = "on_create"
|
||||
time = 0
|
||||
else:
|
||||
trigger = "on_time"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "create_date")]
|
||||
)
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"trigger": trigger,
|
||||
"model_field": model_field,
|
||||
"time": time,
|
||||
}
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_write_or_cancel_action(self, moment, time):
|
||||
model_field = False
|
||||
model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
|
||||
if moment == "in_act":
|
||||
trigger = "on_write"
|
||||
time = 0
|
||||
else:
|
||||
trigger = "on_time"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "write_date")]
|
||||
)
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"trigger": trigger,
|
||||
"model_field": model_field,
|
||||
"time": time,
|
||||
}
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_checkin_action(self, moment, time):
|
||||
model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
|
||||
trigger = "on_time"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "checkin")]
|
||||
)
|
||||
if moment == "before":
|
||||
time = time * (-1)
|
||||
if moment == "in_act":
|
||||
trigger = "on_write"
|
||||
time = 0
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"trigger": trigger,
|
||||
"model_field": model_field,
|
||||
"time": time,
|
||||
}
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_checkout_action(self, moment, time):
|
||||
model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
|
||||
trigger = "on_time"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "checkout")]
|
||||
)
|
||||
if moment == "before":
|
||||
time = time * (-1)
|
||||
if moment == "in_act":
|
||||
trigger = "on_write"
|
||||
time = 0
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"trigger": trigger,
|
||||
"model_field": model_field,
|
||||
"time": time,
|
||||
}
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_payment_action(self, moment, time):
|
||||
model_field = False
|
||||
model_id = (
|
||||
self.env["ir.model"]
|
||||
.search([("model", "=", "account.payment"), ("transient", "=", False)])
|
||||
.id
|
||||
)
|
||||
if moment == "in_act":
|
||||
trigger = "on_create"
|
||||
time = 0
|
||||
else:
|
||||
trigger = "on_time"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "account.payment"), ("name", "=", "date")]
|
||||
)
|
||||
if moment == "before":
|
||||
time = time * (-1)
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"trigger": trigger,
|
||||
"model_field": model_field,
|
||||
"time": time,
|
||||
}
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_invoice_action(self, moment, time):
|
||||
trigger = False
|
||||
model_id = self.env["ir.model"].search([("model", "=", "account.move")]).id
|
||||
if moment == "in_act":
|
||||
trigger = "on_create"
|
||||
time = 0
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"time": time,
|
||||
"trigger": trigger,
|
||||
"model_field": False,
|
||||
}
|
||||
return result
|
||||
|
||||
def _prepare_automated_actions_id(
|
||||
self, action, time, moment, properties, is_create
|
||||
):
|
||||
filter_domain = []
|
||||
filter_pre_domain = []
|
||||
trigger_fields = False
|
||||
dict_val = {}
|
||||
if action == "creation":
|
||||
dict_val = self._get_auto_action_fields_in_creation_action(moment, time)
|
||||
elif action == "write" or action == "cancel":
|
||||
dict_val = self._get_auto_action_fields_in_write_or_cancel_action(
|
||||
moment, time
|
||||
)
|
||||
if action == "cancel":
|
||||
filter_domain = [
|
||||
("state", "=", "cancelled"),
|
||||
]
|
||||
elif action == "checkin":
|
||||
dict_val = self._get_auto_action_fields_in_checkin_action(moment, time)
|
||||
if moment == "in_act":
|
||||
trigger_fields = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "state")]
|
||||
)
|
||||
filter_pre_domain = [("state", "=", "confirm")]
|
||||
filter_domain = [
|
||||
("state", "=", "onboard"),
|
||||
]
|
||||
elif action == "checkout":
|
||||
dict_val = self._get_auto_action_fields_in_checkout_action(moment, time)
|
||||
if moment == "in_act":
|
||||
trigger_fields = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "state")]
|
||||
)
|
||||
filter_pre_domain = [("state", "=", "onboard")]
|
||||
filter_domain = [
|
||||
("state", "=", "out"),
|
||||
]
|
||||
elif action == "payment":
|
||||
dict_val = self._get_auto_action_fields_in_payment_action(moment, time)
|
||||
elif action == "invoice":
|
||||
dict_val = self._get_auto_action_fields_in_invoice_action(moment, time)
|
||||
filter_domain = [
|
||||
("folio_ids", "!=", False),
|
||||
]
|
||||
pms_property_ids = self._get_pms_property_ids(properties, is_create)
|
||||
if pms_property_ids:
|
||||
filter_domain.append(("pms_property_id", "in", pms_property_ids))
|
||||
result = {
|
||||
"trigger": dict_val["trigger"],
|
||||
"model_field": dict_val["model_field"],
|
||||
"trigger_fields": trigger_fields,
|
||||
"filter_pre_domain": filter_pre_domain,
|
||||
"filter_domain": filter_domain,
|
||||
"time": dict_val["time"],
|
||||
"model_id": dict_val["model_id"],
|
||||
}
|
||||
return result
|
||||
|
||||
def _get_pms_property_ids(self, properties, is_create):
|
||||
pms_property_ids = []
|
||||
if is_create:
|
||||
pms_property_ids = properties[0][2]
|
||||
else:
|
||||
for pms_property in properties:
|
||||
pms_property_ids.append(pms_property.id)
|
||||
return pms_property_ids
|
||||
@@ -1,277 +0,0 @@
|
||||
# Copyright 2021 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import datetime
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class PmsAvailability(models.Model):
|
||||
_name = "pms.availability"
|
||||
_description = "Room type availability per day"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
room_type_id = fields.Many2one(
|
||||
string="Room Type",
|
||||
help="Room type for which availability is indicated",
|
||||
readonly=True,
|
||||
required=True,
|
||||
comodel_name="pms.room.type",
|
||||
ondelete="cascade",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
date = fields.Date(
|
||||
string="Date",
|
||||
help="Date for which availability applies",
|
||||
readonly=True,
|
||||
required=True,
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Property to which the availability is directed",
|
||||
readonly=True,
|
||||
required=True,
|
||||
comodel_name="pms.property",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
reservation_line_ids = fields.One2many(
|
||||
string="Reservation Lines",
|
||||
help="They are the lines of the reservation into a reservation,"
|
||||
"they corresponds to the nights",
|
||||
readonly=True,
|
||||
comodel_name="pms.reservation.line",
|
||||
inverse_name="avail_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
avail_rule_ids = fields.One2many(
|
||||
string="Avail record rules",
|
||||
comodel_name="pms.availability.plan.rule",
|
||||
inverse_name="avail_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
real_avail = fields.Integer(
|
||||
string="Real Avail",
|
||||
help="",
|
||||
store=True,
|
||||
readonly=True,
|
||||
compute="_compute_real_avail",
|
||||
)
|
||||
parent_avail_id = fields.Many2one(
|
||||
string="Parent Avail",
|
||||
help="Parent availability for this availability",
|
||||
comodel_name="pms.availability",
|
||||
ondelete="restrict",
|
||||
compute="_compute_parent_avail_id",
|
||||
store=True,
|
||||
check_pms_properties=True,
|
||||
)
|
||||
child_avail_ids = fields.One2many(
|
||||
string="Child Avails",
|
||||
help="Child availabilities for this availability",
|
||||
comodel_name="pms.availability",
|
||||
inverse_name="parent_avail_id",
|
||||
compute="_compute_child_avail_ids",
|
||||
store=True,
|
||||
check_pms_properties=True,
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
"room_type_registry_unique",
|
||||
"unique(room_type_id, date, pms_property_id)",
|
||||
"Only can exists one availability in the same \
|
||||
day for the same room type!",
|
||||
)
|
||||
]
|
||||
|
||||
@api.depends(
|
||||
"reservation_line_ids",
|
||||
"reservation_line_ids.occupies_availability",
|
||||
"room_type_id.total_rooms_count",
|
||||
"parent_avail_id",
|
||||
"parent_avail_id.reservation_line_ids",
|
||||
"parent_avail_id.reservation_line_ids.occupies_availability",
|
||||
"child_avail_ids",
|
||||
"child_avail_ids.reservation_line_ids",
|
||||
"child_avail_ids.reservation_line_ids.occupies_availability",
|
||||
)
|
||||
def _compute_real_avail(self):
|
||||
for record in self:
|
||||
Rooms = self.env["pms.room"]
|
||||
total_rooms = Rooms.search_count(
|
||||
[
|
||||
("room_type_id", "=", record.room_type_id.id),
|
||||
("pms_property_id", "=", record.pms_property_id.id),
|
||||
]
|
||||
)
|
||||
room_ids = record.room_type_id.mapped("room_ids.id")
|
||||
count_rooms_not_avail = len(
|
||||
record.get_rooms_not_avail(
|
||||
checkin=record.date,
|
||||
checkout=record.date + datetime.timedelta(1),
|
||||
room_ids=room_ids,
|
||||
pms_property_id=record.pms_property_id.id,
|
||||
)
|
||||
)
|
||||
record.real_avail = total_rooms - count_rooms_not_avail
|
||||
|
||||
@api.depends("reservation_line_ids", "reservation_line_ids.room_id")
|
||||
def _compute_parent_avail_id(self):
|
||||
for record in self:
|
||||
parent_rooms = record.room_type_id.mapped("room_ids.parent_id.id")
|
||||
if parent_rooms:
|
||||
for room_id in parent_rooms:
|
||||
room = self.env["pms.room"].browse(room_id)
|
||||
parent_avail = self.env["pms.availability"].search(
|
||||
[
|
||||
("date", "=", record.date),
|
||||
("room_type_id", "=", room.room_type_id.id),
|
||||
("pms_property_id", "=", record.pms_property_id.id),
|
||||
]
|
||||
)
|
||||
if parent_avail:
|
||||
record.parent_avail_id = parent_avail
|
||||
else:
|
||||
record.parent_avail_id = self.env["pms.availability"].create(
|
||||
{
|
||||
"date": record.date,
|
||||
"room_type_id": room.room_type_id.id,
|
||||
"pms_property_id": record.pms_property_id.id,
|
||||
}
|
||||
)
|
||||
else:
|
||||
record.parent_avail_id = False
|
||||
|
||||
@api.depends("reservation_line_ids", "reservation_line_ids.room_id")
|
||||
def _compute_child_avail_ids(self):
|
||||
for record in self:
|
||||
child_rooms = record.room_type_id.mapped("room_ids.child_ids.id")
|
||||
if child_rooms:
|
||||
for room_id in child_rooms:
|
||||
room = self.env["pms.room"].browse(room_id)
|
||||
child_avail = self.env["pms.availability"].search(
|
||||
[
|
||||
("date", "=", record.date),
|
||||
("room_type_id", "=", room.room_type_id.id),
|
||||
("pms_property_id", "=", record.pms_property_id.id),
|
||||
]
|
||||
)
|
||||
if child_avail:
|
||||
record.child_avail_ids = [(4, child_avail.id)]
|
||||
else:
|
||||
record.child_avail_ids = [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"date": record.date,
|
||||
"room_type_id": room.room_type_id.id,
|
||||
"pms_property_id": record.pms_property_id.id,
|
||||
},
|
||||
)
|
||||
]
|
||||
else:
|
||||
record.child_avail_ids = False
|
||||
|
||||
@api.model
|
||||
def get_rooms_not_avail(
|
||||
self, checkin, checkout, room_ids, pms_property_id, current_lines=False
|
||||
):
|
||||
RoomLines = self.env["pms.reservation.line"]
|
||||
rooms = self.env["pms.room"].browse(room_ids)
|
||||
occupied_room_ids = []
|
||||
for room in rooms.filtered("parent_id"):
|
||||
if self.get_occupied_parent_rooms(
|
||||
room=room.parent_id,
|
||||
checkin=checkin,
|
||||
checkout=checkout,
|
||||
pms_property_id=room.pms_property_id.id,
|
||||
):
|
||||
occupied_room_ids.append(room.id)
|
||||
for room in rooms.filtered("child_ids"):
|
||||
if self.get_occupied_child_rooms(
|
||||
rooms=room.child_ids,
|
||||
checkin=checkin,
|
||||
checkout=checkout,
|
||||
pms_property_id=room.pms_property_id.id,
|
||||
):
|
||||
occupied_room_ids.append(room.id)
|
||||
occupied_room_ids.extend(
|
||||
RoomLines.search(
|
||||
[
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout - datetime.timedelta(1)),
|
||||
("room_id", "in", room_ids),
|
||||
("pms_property_id", "=", pms_property_id),
|
||||
("occupies_availability", "=", True),
|
||||
("id", "not in", current_lines if current_lines else []),
|
||||
]
|
||||
).mapped("room_id.id")
|
||||
)
|
||||
return occupied_room_ids
|
||||
|
||||
@api.model
|
||||
def get_occupied_parent_rooms(self, room, checkin, checkout, pms_property_id):
|
||||
RoomLines = self.env["pms.reservation.line"]
|
||||
if (
|
||||
RoomLines.search_count(
|
||||
[
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout - datetime.timedelta(1)),
|
||||
("room_id", "=", room.id),
|
||||
("pms_property_id", "=", pms_property_id),
|
||||
("occupies_availability", "=", True),
|
||||
]
|
||||
)
|
||||
> 0
|
||||
):
|
||||
return True
|
||||
if room.parent_id:
|
||||
return self.get_occupied_parent_rooms(
|
||||
room=room.parent_room_id,
|
||||
checkin=checkin,
|
||||
checkout=checkout,
|
||||
)
|
||||
return False
|
||||
|
||||
@api.model
|
||||
def get_occupied_child_rooms(self, rooms, checkin, checkout, pms_property_id):
|
||||
RoomLines = self.env["pms.reservation.line"]
|
||||
if (
|
||||
RoomLines.search_count(
|
||||
[
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout - datetime.timedelta(1)),
|
||||
("room_id", "in", rooms.ids),
|
||||
("pms_property_id", "=", pms_property_id),
|
||||
("occupies_availability", "=", True),
|
||||
]
|
||||
)
|
||||
> 0
|
||||
):
|
||||
return True
|
||||
for room in rooms.filtered("child_ids"):
|
||||
if self.get_occupied_child_rooms(
|
||||
rooms=room.child_ids,
|
||||
checkin=checkin,
|
||||
checkout=checkout,
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
@api.constrains(
|
||||
"room_type_id",
|
||||
"pms_property_id",
|
||||
)
|
||||
def _check_property_integrity(self):
|
||||
for rec in self:
|
||||
if rec.pms_property_id and rec.room_type_id:
|
||||
if (
|
||||
rec.room_type_id.pms_property_ids.ids
|
||||
and rec.pms_property_id.id
|
||||
not in rec.room_type_id.pms_property_ids.ids
|
||||
):
|
||||
raise ValidationError(
|
||||
_("Property not allowed on availability day compute")
|
||||
)
|
||||
@@ -1,145 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import datetime
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
|
||||
|
||||
class PmsAvailabilityPlan(models.Model):
|
||||
"""The room type availability is used as a daily availability plan for room types
|
||||
and therefore is related only with one property."""
|
||||
|
||||
_name = "pms.availability.plan"
|
||||
_description = "Reservation availability plan"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
@api.model
|
||||
def _get_default_pms_property(self):
|
||||
return self.env.user.get_active_property_ids()[0] or None
|
||||
|
||||
name = fields.Char(
|
||||
string="Availability Plan Name", help="Name of availability plan", required=True
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
ondelete="restrict",
|
||||
relation="pms_availability_plan_pms_property_rel",
|
||||
column1="availability_plan_id",
|
||||
column2="pms_property_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_pricelist_ids = fields.One2many(
|
||||
string="Pricelists",
|
||||
help="Pricelists of the availability plan ",
|
||||
comodel_name="product.pricelist",
|
||||
inverse_name="availability_plan_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
|
||||
rule_ids = fields.One2many(
|
||||
string="Availability Rules",
|
||||
help="Rules in a availability plan",
|
||||
comodel_name="pms.availability.plan.rule",
|
||||
inverse_name="availability_plan_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
|
||||
active = fields.Boolean(
|
||||
string="Active",
|
||||
help="If unchecked, it will allow you to hide the "
|
||||
"Availability plan without removing it.",
|
||||
default=True,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def any_rule_applies(cls, checkin, checkout, item):
|
||||
if isinstance(checkin, str):
|
||||
checkin = datetime.datetime.strptime(
|
||||
checkin, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
if isinstance(checkout, str):
|
||||
checkout = datetime.datetime.strptime(
|
||||
checkout, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
reservation_len = (checkout - checkin).days
|
||||
return any(
|
||||
[
|
||||
(0 < item.max_stay < reservation_len),
|
||||
(0 < item.min_stay > reservation_len),
|
||||
(0 < item.max_stay_arrival < reservation_len and checkin == item.date),
|
||||
(0 < item.min_stay_arrival > reservation_len and checkin == item.date),
|
||||
item.closed,
|
||||
(item.closed_arrival and checkin == item.date),
|
||||
(item.closed_departure and checkout == item.date),
|
||||
(item.quota == 0 or item.max_avail == 0),
|
||||
]
|
||||
)
|
||||
|
||||
@api.model
|
||||
def update_quota(self, pricelist_id, room_type_id, date, impacts_quota_id=False):
|
||||
if pricelist_id and room_type_id and date:
|
||||
rule = self.env["pms.availability.plan.rule"].search(
|
||||
[
|
||||
("availability_plan_id.pms_pricelist_ids", "=", pricelist_id.id),
|
||||
("room_type_id", "=", room_type_id.id),
|
||||
("date", "=", date),
|
||||
]
|
||||
)
|
||||
# applies a rule
|
||||
if rule:
|
||||
rule.ensure_one()
|
||||
if rule and rule.quota != -1 and rule.quota > 0:
|
||||
|
||||
# the line has no rule item applied before
|
||||
if not impacts_quota_id:
|
||||
rule.quota -= 1
|
||||
return rule.id
|
||||
|
||||
# the line has a rule item applied before
|
||||
elif impacts_quota_id != rule.id:
|
||||
|
||||
# decrement quota on current rule item
|
||||
rule.quota -= 1
|
||||
|
||||
# check old rule item
|
||||
old_rule = self.env["pms.availability.plan.rule"].search(
|
||||
[("id", "=", impacts_quota_id)]
|
||||
)
|
||||
|
||||
# restore quota in old rule item
|
||||
if old_rule:
|
||||
old_rule.quota += 1
|
||||
|
||||
return rule.id
|
||||
|
||||
# in any case, check old rule item
|
||||
if impacts_quota_id:
|
||||
old_rule = self.env["pms.availability.plan.rule"].search(
|
||||
[("id", "=", impacts_quota_id)]
|
||||
)
|
||||
# and restore quota in old rule item
|
||||
if old_rule:
|
||||
old_rule.quota += 1
|
||||
|
||||
return False
|
||||
|
||||
# Action methods
|
||||
def open_massive_changes_wizard(self):
|
||||
|
||||
if self.ensure_one():
|
||||
return {
|
||||
"view_type": "form",
|
||||
"view_mode": "form",
|
||||
"name": "Massive changes on Availability Plan: " + self.name,
|
||||
"res_model": "pms.massive.changes.wizard",
|
||||
"target": "new",
|
||||
"type": "ir.actions.act_window",
|
||||
"context": {
|
||||
"availability_plan_id": self.id,
|
||||
},
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class PmsAvailabilityPlanRule(models.Model):
|
||||
_name = "pms.availability.plan.rule"
|
||||
_description = "Reservation rule by day"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
availability_plan_id = fields.Many2one(
|
||||
string="Availability Plan",
|
||||
help="The availability plan that include the Availabilty Rule",
|
||||
index=True,
|
||||
comodel_name="pms.availability.plan",
|
||||
ondelete="cascade",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
room_type_id = fields.Many2one(
|
||||
string="Room Type",
|
||||
help="Room type for which availability rule is applied",
|
||||
required=True,
|
||||
comodel_name="pms.room.type",
|
||||
ondelete="cascade",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
date = fields.Date(
|
||||
string="Date",
|
||||
help="Date for which availability rule applies",
|
||||
)
|
||||
|
||||
min_stay = fields.Integer(
|
||||
string="Min. Stay",
|
||||
help="Minimum stay",
|
||||
default=0,
|
||||
)
|
||||
min_stay_arrival = fields.Integer(
|
||||
string="Min. Stay Arrival",
|
||||
help="Minimum stay if checkin is today",
|
||||
default=0,
|
||||
)
|
||||
max_stay = fields.Integer(
|
||||
string="Max. Stay",
|
||||
help="Maximum stay",
|
||||
default=0,
|
||||
)
|
||||
max_stay_arrival = fields.Integer(
|
||||
string="Max. Stay Arrival",
|
||||
help="Maximum stay if checkin is today",
|
||||
default=0,
|
||||
)
|
||||
closed = fields.Boolean(
|
||||
string="Closed",
|
||||
help="Indicate if property is closed or not",
|
||||
default=False,
|
||||
)
|
||||
closed_departure = fields.Boolean(
|
||||
string="Closed Departure",
|
||||
help="",
|
||||
default=False,
|
||||
)
|
||||
closed_arrival = fields.Boolean(
|
||||
string="Closed Arrival",
|
||||
help="",
|
||||
default=False,
|
||||
)
|
||||
quota = fields.Integer(
|
||||
string="Quota",
|
||||
help="Generic Quota assigned.",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_quota",
|
||||
)
|
||||
max_avail = fields.Integer(
|
||||
string="Max. Availability",
|
||||
help="Maximum simultaneous availability on own Booking Engine",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_max_avail",
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Properties with access to the element",
|
||||
ondelete="restrict",
|
||||
required=True,
|
||||
comodel_name="pms.property",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
avail_id = fields.Many2one(
|
||||
string="Avail record",
|
||||
comodel_name="pms.availability",
|
||||
compute="_compute_avail_id",
|
||||
store=True,
|
||||
readonly=False,
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
real_avail = fields.Integer(
|
||||
string="Real availability",
|
||||
related="avail_id.real_avail",
|
||||
store="True",
|
||||
)
|
||||
plan_avail = fields.Integer(
|
||||
compute="_compute_plan_avail",
|
||||
store="True",
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
"room_type_registry_unique",
|
||||
"unique(availability_plan_id, room_type_id, date, pms_property_id)",
|
||||
"Only can exists one availability rule in the same \
|
||||
day for the same room type!",
|
||||
)
|
||||
]
|
||||
|
||||
@api.depends("room_type_id", "date", "pms_property_id")
|
||||
def _compute_avail_id(self):
|
||||
for record in self:
|
||||
if record.room_type_id and record.pms_property_id and record.date:
|
||||
avail = self.env["pms.availability"].search(
|
||||
[
|
||||
("date", "=", record.date),
|
||||
("room_type_id", "=", record.room_type_id.id),
|
||||
("pms_property_id", "=", record.pms_property_id.id),
|
||||
]
|
||||
)
|
||||
if avail:
|
||||
record.avail_id = avail.id
|
||||
else:
|
||||
record.avail_id = self.env["pms.availability"].create(
|
||||
{
|
||||
"date": record.date,
|
||||
"room_type_id": record.room_type_id.id,
|
||||
"pms_property_id": record.pms_property_id.id,
|
||||
}
|
||||
)
|
||||
else:
|
||||
record.avail_id = False
|
||||
|
||||
@api.depends("quota", "max_avail", "real_avail")
|
||||
def _compute_plan_avail(self):
|
||||
for record in self:
|
||||
real_avail = record.real_avail
|
||||
plan_avail = min(
|
||||
[
|
||||
record.max_avail if record.max_avail >= 0 else real_avail,
|
||||
record.quota if record.quota >= 0 else real_avail,
|
||||
real_avail,
|
||||
]
|
||||
)
|
||||
if not record.plan_avail or record.plan_avail != plan_avail:
|
||||
record.plan_avail = plan_avail
|
||||
|
||||
@api.depends("room_type_id")
|
||||
def _compute_quota(self):
|
||||
for record in self:
|
||||
if not record.quota:
|
||||
record.quota = record.room_type_id.default_quota
|
||||
|
||||
@api.depends("room_type_id")
|
||||
def _compute_max_avail(self):
|
||||
for record in self:
|
||||
if not record.max_avail:
|
||||
record.max_avail = record.room_type_id.default_max_avail
|
||||
|
||||
@api.constrains("min_stay", "min_stay_arrival", "max_stay", "max_stay_arrival")
|
||||
def _check_min_max_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"))
|
||||
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"))
|
||||
elif (
|
||||
record.min_stay != 0
|
||||
and record.max_stay != 0
|
||||
and record.min_stay > record.max_stay
|
||||
):
|
||||
raise ValidationError(_("Max. Stay can't be less than Min. Stay"))
|
||||
elif (
|
||||
record.min_stay_arrival != 0
|
||||
and record.max_stay_arrival != 0
|
||||
and record.min_stay_arrival > record.max_stay_arrival
|
||||
):
|
||||
raise ValidationError(
|
||||
_("Max. Stay Arrival can't be less than Min. Stay Arrival")
|
||||
)
|
||||
@@ -1,133 +0,0 @@
|
||||
# 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 ValidationError
|
||||
|
||||
|
||||
class PmsBoardService(models.Model):
|
||||
_name = "pms.board.service"
|
||||
_description = "Board Services"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
name = fields.Char(
|
||||
string="Board Service Name",
|
||||
help="Board Service Name",
|
||||
required=True,
|
||||
index=True,
|
||||
size=64,
|
||||
translate=True,
|
||||
)
|
||||
default_code = fields.Char(
|
||||
string="Board Service Code",
|
||||
help="Unique Board Service identification code per property",
|
||||
required=True,
|
||||
)
|
||||
board_service_line_ids = fields.One2many(
|
||||
string="Board Service Lines",
|
||||
help="Services included in this Board Service",
|
||||
comodel_name="pms.board.service.line",
|
||||
inverse_name="pms_board_service_id",
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
required=False,
|
||||
ondelete="restrict",
|
||||
comodel_name="pms.property",
|
||||
relation="pms_board_service_pms_property_rel",
|
||||
column1="board_service_id",
|
||||
column2="pms_property_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_board_service_room_type_ids = fields.One2many(
|
||||
string="Board Services Room Type",
|
||||
help="Board Services Room Type corresponding to this Board Service,"
|
||||
"One board service for several room types",
|
||||
comodel_name="pms.board.service.room.type",
|
||||
inverse_name="pms_board_service_id",
|
||||
)
|
||||
amount = fields.Float(
|
||||
string="Amount",
|
||||
help="Price for this Board Service. "
|
||||
"It corresponds to the sum of his board service lines",
|
||||
store=True,
|
||||
digits=("Product Price"),
|
||||
compute="_compute_board_amount",
|
||||
)
|
||||
|
||||
show_detail_report = fields.Boolean(
|
||||
string="Show Detail Report",
|
||||
help="True if you want that board service detail to be shown on the report",
|
||||
)
|
||||
|
||||
@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})
|
||||
|
||||
@api.model
|
||||
def get_unique_by_property_code(self, pms_property_id, default_code=None):
|
||||
"""
|
||||
:param pms_property_id: property ID
|
||||
:param default_code: board service code (optional)
|
||||
:return: - recordset of
|
||||
- all the pms.board.service of the pms_property_id
|
||||
if default_code not defined
|
||||
- one or 0 pms.board.service if default_code defined
|
||||
- ValidationError if more than one default_code found by
|
||||
the same pms_property_id
|
||||
"""
|
||||
# TODO: similiar code as room.type -> unify
|
||||
domain = []
|
||||
if default_code:
|
||||
domain += ["&", ("default_code", "=", default_code)]
|
||||
domain += [
|
||||
"|",
|
||||
("pms_property_ids", "in", pms_property_id),
|
||||
("pms_property_ids", "=", False),
|
||||
]
|
||||
records = self.search(domain)
|
||||
res, res_priority = {}, {}
|
||||
for rec in records:
|
||||
res_priority.setdefault(rec.default_code, -1)
|
||||
priority = rec.pms_property_ids and 1 or 0
|
||||
if priority > res_priority[rec.default_code]:
|
||||
res.setdefault(rec.default_code, rec.id)
|
||||
res[rec.default_code], res_priority[rec.default_code] = rec.id, priority
|
||||
elif priority == res_priority[rec.default_code]:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"Integrity error: There's multiple board services "
|
||||
"with the same code %s and properties"
|
||||
)
|
||||
% rec.default_code
|
||||
)
|
||||
return self.browse(list(res.values()))
|
||||
|
||||
@api.constrains("default_code", "pms_property_ids")
|
||||
def _check_code_property_uniqueness(self):
|
||||
# TODO: similiar code as room.type -> unify
|
||||
msg = _(
|
||||
"Already exists another Board Service with the same code and properties"
|
||||
)
|
||||
for rec in self:
|
||||
if not rec.pms_property_ids:
|
||||
if self.search(
|
||||
[
|
||||
("id", "!=", rec.id),
|
||||
("default_code", "=", rec.default_code),
|
||||
("pms_property_ids", "=", False),
|
||||
]
|
||||
):
|
||||
raise ValidationError(msg)
|
||||
else:
|
||||
for pms_property in rec.pms_property_ids:
|
||||
other = rec.get_unique_by_property_code(
|
||||
pms_property.id, rec.default_code
|
||||
)
|
||||
if other and other != rec:
|
||||
raise ValidationError(msg)
|
||||
@@ -1,82 +0,0 @@
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class PmsBoardServiceLine(models.Model):
|
||||
_name = "pms.board.service.line"
|
||||
_description = "Services on Board Service included"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
pms_board_service_id = fields.Many2one(
|
||||
string="Board Service",
|
||||
help="Board Service in which this line is included",
|
||||
required=True,
|
||||
comodel_name="pms.board.service",
|
||||
ondelete="cascade",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
string="Product",
|
||||
help="Product associated with this board service line",
|
||||
required=True,
|
||||
comodel_name="product.product",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
relation="pms_board_service_line_pms_property_rel",
|
||||
column1="pms_board_service_line_id",
|
||||
column2="pms_property_id",
|
||||
store=True,
|
||||
check_pms_properties=True,
|
||||
)
|
||||
amount = fields.Float(
|
||||
string="Amount",
|
||||
help="Price for this Board Service Line/Product",
|
||||
default=lambda self: self._get_default_price(),
|
||||
digits=("Product Price"),
|
||||
)
|
||||
|
||||
def _get_default_price(self):
|
||||
if self.product_id:
|
||||
return self.product_id.list_price
|
||||
|
||||
@api.onchange("product_id")
|
||||
def onchange_product_id(self):
|
||||
if self.product_id:
|
||||
self.update({"amount": self.product_id.list_price})
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
properties = False
|
||||
if "pms_board_service_id" in vals:
|
||||
board_service = self.env["pms.board.service"].browse(
|
||||
vals["pms_board_service_id"]
|
||||
)
|
||||
properties = board_service.pms_property_ids
|
||||
if properties:
|
||||
vals.update(
|
||||
{
|
||||
"pms_property_ids": properties,
|
||||
}
|
||||
)
|
||||
return super(PmsBoardServiceLine, self).create(vals)
|
||||
|
||||
def write(self, vals):
|
||||
properties = False
|
||||
if "pms_board_service_id" in vals:
|
||||
board_service = self.env["pms.board.service"].browse(
|
||||
vals["pms_board_service_id"]
|
||||
)
|
||||
properties = board_service.pms_property_ids
|
||||
if properties:
|
||||
vals.update(
|
||||
{
|
||||
"pms_property_ids": properties,
|
||||
}
|
||||
)
|
||||
return super(PmsBoardServiceLine, self).write(vals)
|
||||
@@ -1,183 +0,0 @@
|
||||
# Copyright 2017 Dario
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
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"
|
||||
_log_access = False
|
||||
_description = "Board Service included in Room"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
pms_board_service_id = fields.Many2one(
|
||||
string="Board Service",
|
||||
help="Board Service corresponding to this Board Service Room Type",
|
||||
required=True,
|
||||
index=True,
|
||||
comodel_name="pms.board.service",
|
||||
ondelete="cascade",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
required=False,
|
||||
ondelete="restrict",
|
||||
comodel_name="pms.property",
|
||||
relation="pms_board_service_room_type_pms_property_rel",
|
||||
column1="pms_board_service_room_type_id",
|
||||
column2="pms_property_id",
|
||||
check_pms_properties=True,
|
||||
compute="_compute_pms_property_ids",
|
||||
store=True,
|
||||
)
|
||||
pms_room_type_id = fields.Many2one(
|
||||
string="Room Type",
|
||||
help="Room Type for which this Board Service is available",
|
||||
required=True,
|
||||
index=True,
|
||||
comodel_name="pms.room.type",
|
||||
ondelete="cascade",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
board_service_line_ids = fields.One2many(
|
||||
string="Board Service Lines",
|
||||
help="Services included in this Board Service",
|
||||
comodel_name="pms.board.service.room.type.line",
|
||||
inverse_name="pms_board_service_room_type_id",
|
||||
required=True,
|
||||
)
|
||||
amount = fields.Float(
|
||||
string="Amount",
|
||||
help="Price for this Board Service. "
|
||||
"It corresponds to the sum of his board service lines",
|
||||
store=True,
|
||||
digits=("Product Price"),
|
||||
compute="_compute_board_amount",
|
||||
)
|
||||
by_default = fields.Boolean(
|
||||
string="Apply by Default",
|
||||
help="Indicates if this board service is applied by default in the room type",
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"pms_room_type_id",
|
||||
"pms_room_type_id.pms_property_ids",
|
||||
"pms_board_service_id",
|
||||
"pms_board_service_id.pms_property_ids",
|
||||
)
|
||||
def _compute_pms_property_ids(self):
|
||||
for record in self:
|
||||
if (
|
||||
record.pms_room_type_id.pms_property_ids
|
||||
and record.pms_board_service_id.pms_property_ids
|
||||
):
|
||||
record.pms_property_ids = self.env["pms.property"].search(
|
||||
[
|
||||
(
|
||||
"id",
|
||||
"in",
|
||||
list(
|
||||
set(record.pms_room_type_id.pms_property_ids.ids)
|
||||
& set(record.pms_board_service_id.pms_property_ids.ids)
|
||||
),
|
||||
)
|
||||
]
|
||||
)
|
||||
elif (
|
||||
record.pms_room_type_id.pms_property_ids
|
||||
and not record.pms_board_service_id.pms_property_ids
|
||||
):
|
||||
record.pms_property_ids = record.pms_room_type_id.pms_property_ids
|
||||
elif (
|
||||
not record.pms_room_type_id.pms_property_ids
|
||||
and record.pms_board_service_id.pms_property_ids
|
||||
):
|
||||
record.pms_property_ids = record.pms_board_service_id.pms_property_ids
|
||||
else:
|
||||
record.pms_property_ids = False
|
||||
|
||||
@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})
|
||||
|
||||
def name_get(self):
|
||||
res = []
|
||||
for record in self:
|
||||
name = "{} - {}".format(
|
||||
record.pms_board_service_id.name, record.pms_room_type_id.name
|
||||
)
|
||||
res.append((record.id, name))
|
||||
return res
|
||||
|
||||
@api.constrains("by_default")
|
||||
def constrains_duplicated_board_defaul(self):
|
||||
for record in self:
|
||||
default_boards = (
|
||||
record.pms_room_type_id.board_service_room_type_ids.filtered(
|
||||
"by_default"
|
||||
)
|
||||
)
|
||||
# TODO Check properties (with different propertys is allowed)
|
||||
if any(default_boards.filtered(lambda l: l.id != record.id)):
|
||||
raise UserError(_("""Only can set one default board service"""))
|
||||
|
||||
def open_board_lines_form(self):
|
||||
action = (
|
||||
self.env.ref("pms.action_pms_board_service_room_type_view").sudo().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
|
||||
|
||||
def init(self):
|
||||
self._cr.execute(
|
||||
"SELECT indexname FROM pg_indexes WHERE indexname = %s",
|
||||
("pms_board_service_id_pms_room_type_id",),
|
||||
)
|
||||
if not self._cr.fetchone():
|
||||
self._cr.execute(
|
||||
"CREATE INDEX pms_board_service_id_pms_room_type_id \
|
||||
ON pms_board_service_room_type_rel \
|
||||
(pms_board_service_id, pms_room_type_id)"
|
||||
)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# properties = False
|
||||
if "pms_board_service_id" in vals:
|
||||
vals.update(
|
||||
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:
|
||||
vals.update(
|
||||
self.prepare_board_service_reservation_ids(vals["pms_board_service_id"])
|
||||
)
|
||||
return super(PmsBoardServiceRoomType, self).write(vals)
|
||||
|
||||
@api.model
|
||||
def prepare_board_service_reservation_ids(self, board_service_id):
|
||||
"""
|
||||
Prepare line to price products config
|
||||
"""
|
||||
cmds = [(5, 0, 0)]
|
||||
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}
|
||||
@@ -1,73 +0,0 @@
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class PmsBoardServiceRoomTypeLine(models.Model):
|
||||
_name = "pms.board.service.room.type.line"
|
||||
_description = "Services on Board Service included in Room"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
# Fields declaration
|
||||
pms_board_service_room_type_id = fields.Many2one(
|
||||
string="Board Service Room",
|
||||
help="Board Service Room Type in which this line is included",
|
||||
required=True,
|
||||
comodel_name="pms.board.service.room.type",
|
||||
ondelete="cascade",
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
relation="pms_board_service_room_type_line_pms_property_rel",
|
||||
column1="pms_board_service_room_type_id",
|
||||
column2="pms_property_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
string="Product",
|
||||
help="Product associated with this board service room type line",
|
||||
comodel_name="product.product",
|
||||
readonly=True,
|
||||
check_pms_properties=True,
|
||||
)
|
||||
# TODO def default_amount "amount of service"
|
||||
amount = fields.Float(
|
||||
string="Amount",
|
||||
help="Price for this Board Service Room Type Line/Product",
|
||||
default=0.0,
|
||||
digits=("Product Price"),
|
||||
)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
properties = False
|
||||
if "pms_board_service_room_type_id" in vals:
|
||||
board_service = self.env["pms.board.service.room.type"].browse(
|
||||
vals["pms_board_service_room_type_id"]
|
||||
)
|
||||
properties = board_service.pms_property_ids
|
||||
if properties:
|
||||
vals.update(
|
||||
{
|
||||
"pms_property_ids": properties,
|
||||
}
|
||||
)
|
||||
return super(PmsBoardServiceRoomTypeLine, self).create(vals)
|
||||
|
||||
def write(self, vals):
|
||||
properties = False
|
||||
if "pms_board_service_room_type_id" in vals:
|
||||
board_service = self.env["pms.board.service.room.type"].browse(
|
||||
vals["pms_board_service_room_type_id"]
|
||||
)
|
||||
properties = board_service.pms_property_ids
|
||||
if properties:
|
||||
vals.update(
|
||||
{
|
||||
"pms_property_ids": properties,
|
||||
}
|
||||
)
|
||||
return super(PmsBoardServiceRoomTypeLine, self).write(vals)
|
||||
@@ -1,88 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class PmsCancelationRule(models.Model):
|
||||
_name = "pms.cancelation.rule"
|
||||
_description = "Cancelation Rules"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
name = fields.Char(
|
||||
string="Cancelation Rule",
|
||||
required=True,
|
||||
translate=True,
|
||||
)
|
||||
pricelist_ids = fields.One2many(
|
||||
string="Pricelist",
|
||||
help="Pricelist that use this rule",
|
||||
comodel_name="product.pricelist",
|
||||
inverse_name="cancelation_rule_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
required=False,
|
||||
comodel_name="pms.property",
|
||||
relation="pms_cancelation_rule_pms_property_rel",
|
||||
column1="pms_cancelation_rule_id",
|
||||
column2="pms_property_id",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
active = fields.Boolean(
|
||||
string="Active", help="Determines if cancelation rule is active", default=True
|
||||
)
|
||||
days_intime = fields.Integer(
|
||||
string="Days Late",
|
||||
help="Maximum number of days for free cancellation before Checkin",
|
||||
)
|
||||
penalty_late = fields.Integer(
|
||||
string="% Penalty Late",
|
||||
help="Percentage of the total price that partner has "
|
||||
"to pay in case of late arrival",
|
||||
default="100",
|
||||
)
|
||||
apply_on_late = fields.Selection(
|
||||
string="Late apply on",
|
||||
help="Days on which the cancelation rule applies when "
|
||||
"the reason is late arrival. "
|
||||
"Can be first, all days or specify the days.",
|
||||
default="first",
|
||||
selection=[
|
||||
("first", "First Day"),
|
||||
("all", "All Days"),
|
||||
("days", "Specify days"),
|
||||
],
|
||||
)
|
||||
days_late = fields.Integer(
|
||||
string="Late first days",
|
||||
help="Is number of days late in the cancelation rule "
|
||||
"if the value of the apply_on_late field is specify days.",
|
||||
default="2",
|
||||
)
|
||||
penalty_noshow = fields.Integer(
|
||||
string="% Penalty No Show",
|
||||
help="Percentage of the total price that partner has to pay in case of no show",
|
||||
default="100",
|
||||
)
|
||||
apply_on_noshow = fields.Selection(
|
||||
string="No Show apply on",
|
||||
help="Days on which the cancelation rule applies when"
|
||||
" the reason is no show. Can be first, all days or specify the days.",
|
||||
selection=[
|
||||
("first", "First Day"),
|
||||
("all", "All Days"),
|
||||
("days", "Specify days"),
|
||||
],
|
||||
default="all",
|
||||
)
|
||||
days_noshow = fields.Integer(
|
||||
string="NoShow first days",
|
||||
help="Is number of days no show in the cancelation rule "
|
||||
"if the value of the apply_on_show field is specify days.",
|
||||
default="2",
|
||||
)
|
||||
@@ -1,792 +0,0 @@
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# Copyright 2018 Alexandre Diaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
|
||||
class PmsCheckinPartner(models.Model):
|
||||
_name = "pms.checkin.partner"
|
||||
_description = "Partner Checkins"
|
||||
_inherit = ["portal.mixin"]
|
||||
_rec_name = "identifier"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
identifier = fields.Char(
|
||||
string="Identifier",
|
||||
help="Checkin Partner Id",
|
||||
readonly=True,
|
||||
index=True,
|
||||
default=lambda self: _("New"),
|
||||
)
|
||||
partner_id = fields.Many2one(
|
||||
string="Partner",
|
||||
help="Partner associated with checkin partner",
|
||||
readonly=False,
|
||||
store=True,
|
||||
comodel_name="res.partner",
|
||||
domain="[('is_company', '=', False)]",
|
||||
compute="_compute_partner_id",
|
||||
)
|
||||
reservation_id = fields.Many2one(
|
||||
string="Reservation",
|
||||
help="Reservation to which checkin partners belong",
|
||||
comodel_name="pms.reservation",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
folio_id = fields.Many2one(
|
||||
string="Folio",
|
||||
help="Folio to which reservation of checkin partner belongs",
|
||||
store=True,
|
||||
comodel_name="pms.folio",
|
||||
compute="_compute_folio_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Property to which the folio associated belongs",
|
||||
readonly=True,
|
||||
store=True,
|
||||
comodel_name="pms.property",
|
||||
related="folio_id.pms_property_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
name = fields.Char(
|
||||
string="Name", help="Checkin partner name", related="partner_id.name"
|
||||
)
|
||||
email = fields.Char(
|
||||
string="E-mail",
|
||||
help="Checkin Partner Email",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_email",
|
||||
)
|
||||
mobile = fields.Char(
|
||||
string="Mobile",
|
||||
help="Checkin Partner Mobile",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_mobile",
|
||||
)
|
||||
image_128 = fields.Image(
|
||||
string="Image",
|
||||
help="Checkin Partner Image, it corresponds with Partner Image associated",
|
||||
related="partner_id.image_128",
|
||||
)
|
||||
segmentation_ids = fields.Many2many(
|
||||
string="Segmentation",
|
||||
help="Segmentation tags to classify checkin partners",
|
||||
readonly=True,
|
||||
related="reservation_id.segmentation_ids",
|
||||
)
|
||||
checkin = fields.Date(
|
||||
string="Checkin",
|
||||
help="Checkin date",
|
||||
store=True,
|
||||
related="reservation_id.checkin",
|
||||
depends=["reservation_id.checkin"],
|
||||
)
|
||||
checkout = fields.Date(
|
||||
string="Checkout",
|
||||
help="Checkout date",
|
||||
store=True,
|
||||
related="reservation_id.checkout",
|
||||
depends=["reservation_id.checkout"],
|
||||
)
|
||||
arrival = fields.Datetime("Enter", help="Checkin partner arrival date and time")
|
||||
departure = fields.Datetime(
|
||||
string="Exit", help="Checkin partner departure date and time"
|
||||
)
|
||||
state = fields.Selection(
|
||||
string="Status",
|
||||
help="Status of the checkin partner regarding the reservation",
|
||||
readonly=True,
|
||||
store=True,
|
||||
selection=[
|
||||
("draft", "Unkown Guest"),
|
||||
("precheckin", "Pending arrival"),
|
||||
("onboard", "On Board"),
|
||||
("done", "Out"),
|
||||
("cancel", "Cancelled"),
|
||||
],
|
||||
compute="_compute_state",
|
||||
)
|
||||
|
||||
gender = fields.Selection(
|
||||
string="Gender",
|
||||
help="host gender",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_gender",
|
||||
selection=[("male", "Male"), ("female", "Female"), ("other", "Other")],
|
||||
)
|
||||
nationality_id = fields.Many2one(
|
||||
string="Nationality",
|
||||
help="host nationality",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_nationality_id",
|
||||
comodel_name="res.country",
|
||||
)
|
||||
# TODO: Use new partner contact "other or "private" with
|
||||
# personal contact address complete??
|
||||
# to avoid user country_id on companies contacts.
|
||||
# View to res.partner state_id inherit
|
||||
state_id = fields.Many2one(
|
||||
string="Country State",
|
||||
help="host state",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_state_id",
|
||||
comodel_name="res.country.state",
|
||||
)
|
||||
firstname = fields.Char(
|
||||
string="First Name",
|
||||
help="host firstname",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_firstname",
|
||||
)
|
||||
lastname = fields.Char(
|
||||
string="Last Name",
|
||||
help="host lastname",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_lastname",
|
||||
)
|
||||
lastname2 = fields.Char(
|
||||
string="Second Last Name",
|
||||
help="host second lastname",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_lastname2",
|
||||
)
|
||||
birthdate_date = fields.Date(
|
||||
string="Birthdate",
|
||||
help="host birthdate",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_birth_date",
|
||||
)
|
||||
document_number = fields.Char(
|
||||
string="Document Number",
|
||||
help="Host document number",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_document_number",
|
||||
)
|
||||
document_type = fields.Many2one(
|
||||
string="Document Type",
|
||||
help="Select a valid document type",
|
||||
readonly=False,
|
||||
store=True,
|
||||
comodel_name="res.partner.id_category",
|
||||
compute="_compute_document_type",
|
||||
)
|
||||
document_expedition_date = fields.Date(
|
||||
string="Expedition Date",
|
||||
help="Date on which document_type was issued",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_document_expedition_date",
|
||||
)
|
||||
|
||||
document_id = fields.Many2one(
|
||||
string="Document",
|
||||
help="Technical field",
|
||||
readonly=False,
|
||||
store=True,
|
||||
comodel_name="res.partner.id_number",
|
||||
compute="_compute_document_id",
|
||||
ondelete="restrict",
|
||||
)
|
||||
|
||||
partner_incongruences = fields.Char(
|
||||
string="partner_incongruences",
|
||||
help="indicates that some partner fields \
|
||||
on the checkin do not correspond to that of \
|
||||
the associated partner",
|
||||
compute="_compute_partner_incongruences",
|
||||
)
|
||||
|
||||
possible_existing_customer_ids = fields.One2many(
|
||||
string="Possible existing customer",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_possible_existing_customer_ids",
|
||||
comodel_name="res.partner",
|
||||
inverse_name="checkin_partner_possible_customer_id",
|
||||
)
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_document_number(self):
|
||||
for record in self:
|
||||
if not record.document_number:
|
||||
if record.partner_id.id_numbers:
|
||||
record.document_number = record.partner_id.id_numbers[0].name
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_document_type(self):
|
||||
for record in self:
|
||||
if record.partner_id and record.partner_id.id_numbers:
|
||||
if not record.document_type:
|
||||
if record.partner_id.id_numbers:
|
||||
record.document_type = record.partner_id.id_numbers[
|
||||
0
|
||||
].category_id
|
||||
|
||||
@api.depends(
|
||||
"partner_id",
|
||||
)
|
||||
def _compute_document_expedition_date(self):
|
||||
for record in self:
|
||||
if not record.document_expedition_date:
|
||||
record.document_expedition_date = False
|
||||
if record.partner_id and record.partner_id.id_numbers:
|
||||
record.document_expedition_date = record.partner_id.id_numbers[
|
||||
0
|
||||
].valid_from
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_firstname(self):
|
||||
for record in self:
|
||||
if not record.firstname and record.partner_id.firstname:
|
||||
record.firstname = record.partner_id.firstname
|
||||
elif not record.firstname:
|
||||
record.firstname = False
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_lastname(self):
|
||||
for record in self:
|
||||
if not record.lastname and record.partner_id.lastname:
|
||||
record.lastname = record.partner_id.lastname
|
||||
elif not record.lastname:
|
||||
record.lastname = False
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_lastname2(self):
|
||||
for record in self:
|
||||
if not record.lastname2 and record.partner_id.lastname2:
|
||||
record.lastname2 = record.partner_id.lastname2
|
||||
elif not record.lastname2:
|
||||
record.lastname2 = False
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_birth_date(self):
|
||||
for record in self:
|
||||
if not record.birthdate_date and record.partner_id.birthdate_date:
|
||||
record.birthdate_date = record.partner_id.birthdate_date
|
||||
elif not record.birthdate_date:
|
||||
record.birthdate_date = False
|
||||
|
||||
@api.depends(
|
||||
"partner_id",
|
||||
)
|
||||
def _compute_gender(self):
|
||||
for record in self:
|
||||
if not record.gender and record.partner_id.gender:
|
||||
record.gender = record.partner_id.gender
|
||||
elif not record.gender:
|
||||
record.gender = False
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_nationality_id(self):
|
||||
for record in self:
|
||||
if not record.nationality_id and record.partner_id.nationality_id:
|
||||
record.nationality_id = record.partner_id.nationality_id
|
||||
elif not record.nationality_id:
|
||||
record.nationality_id = False
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_state_id(self):
|
||||
for record in self:
|
||||
if not record.state_id and record.partner_id.state_id:
|
||||
record.state_id = record.partner_id.state_id
|
||||
elif not record.state_id:
|
||||
record.state_id = False
|
||||
|
||||
@api.depends("reservation_id", "reservation_id.folio_id")
|
||||
def _compute_folio_id(self):
|
||||
for record in self.filtered("reservation_id"):
|
||||
record.folio_id = record.reservation_id.folio_id
|
||||
|
||||
@api.depends(lambda self: self._checkin_mandatory_fields(depends=True))
|
||||
def _compute_state(self):
|
||||
for record in self:
|
||||
if not record.state:
|
||||
record.state = "draft"
|
||||
if record.reservation_id.state == "cancel":
|
||||
record.state = "cancel"
|
||||
elif record.state in ("draft", "precheckin", "cancel"):
|
||||
if any(
|
||||
not getattr(record, field)
|
||||
for field in record._checkin_mandatory_fields(
|
||||
country=record.nationality_id
|
||||
)
|
||||
):
|
||||
record.state = "draft"
|
||||
else:
|
||||
record.state = "precheckin"
|
||||
|
||||
@api.depends(
|
||||
"partner_id",
|
||||
"partner_id.name",
|
||||
"reservation_id",
|
||||
"reservation_id.preferred_room_id",
|
||||
)
|
||||
def _compute_name(self):
|
||||
for record in self:
|
||||
if not record.name or record.partner_id.name:
|
||||
record.name = record.partner_id.name
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_email(self):
|
||||
for record in self:
|
||||
if not record.email or record.partner_id.email:
|
||||
record.email = record.partner_id.email
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_mobile(self):
|
||||
for record in self:
|
||||
if not record.mobile or record.partner_id.mobile:
|
||||
record.mobile = record.partner_id.mobile
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_document_id(self):
|
||||
for record in self:
|
||||
if record.partner_id:
|
||||
if (
|
||||
not record.document_id
|
||||
and record.document_number
|
||||
and record.document_type
|
||||
):
|
||||
id_number_id = self.env["res.partner.id_number"].search(
|
||||
[
|
||||
("partner_id", "=", record.partner_id.id),
|
||||
("name", "=", record.document_number),
|
||||
("category_id", "=", record.document_type.id),
|
||||
]
|
||||
)
|
||||
if not id_number_id:
|
||||
id_number_id = self.env["res.partner.id_number"].create(
|
||||
{
|
||||
"partner_id": record.partner_id.id,
|
||||
"name": record.document_number,
|
||||
"category_id": record.document_type.id,
|
||||
"valid_from": record.document_expedition_date,
|
||||
}
|
||||
)
|
||||
|
||||
record.document_id = id_number_id
|
||||
else:
|
||||
record.document_id = False
|
||||
|
||||
@api.depends(
|
||||
"document_number",
|
||||
"document_type",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"lastname2",
|
||||
)
|
||||
def _compute_partner_id(self):
|
||||
for record in self:
|
||||
if not record.partner_id:
|
||||
if record.document_number and record.document_type:
|
||||
number = self.env["res.partner.id_number"].search(
|
||||
[
|
||||
("name", "=", record.document_number),
|
||||
("category_id", "=", record.document_type.id),
|
||||
]
|
||||
)
|
||||
partner = self.env["res.partner"].search(
|
||||
[("id", "=", number.partner_id.id)]
|
||||
)
|
||||
if not partner:
|
||||
if record.firstname or record.lastname or record.lastname2:
|
||||
partner_values = {
|
||||
"firstname": record.firstname,
|
||||
"lastname": record.lastname,
|
||||
"lastname2": record.lastname2,
|
||||
"gender": record.gender,
|
||||
"birthdate_date": record.birthdate_date,
|
||||
"nationality_id": record.nationality_id.id,
|
||||
}
|
||||
partner = self.env["res.partner"].create(partner_values)
|
||||
record.partner_id = partner
|
||||
|
||||
@api.depends("email", "mobile")
|
||||
def _compute_possible_existing_customer_ids(self):
|
||||
for record in self:
|
||||
possible_customer = self.env[
|
||||
"pms.folio"
|
||||
]._apply_possible_existing_customer_ids(record.email, record.mobile)
|
||||
if possible_customer:
|
||||
record.possible_existing_customer_ids = possible_customer
|
||||
else:
|
||||
record.possible_existing_customer_ids = False
|
||||
|
||||
@api.depends(
|
||||
"firstname",
|
||||
"lastname",
|
||||
"lastname2",
|
||||
"gender",
|
||||
"birthdate_date",
|
||||
"nationality_id",
|
||||
"email",
|
||||
"mobile",
|
||||
"partner_id",
|
||||
)
|
||||
def _compute_partner_incongruences(self):
|
||||
for record in self:
|
||||
incongruous_fields = False
|
||||
if record.partner_id:
|
||||
for field in record._checkin_partner_fields():
|
||||
if (
|
||||
record.partner_id[field]
|
||||
and record.partner_id[field] != record[field]
|
||||
):
|
||||
if not incongruous_fields:
|
||||
incongruous_fields = record._fields[field].string
|
||||
else:
|
||||
incongruous_fields += ", " + record._fields[field].string
|
||||
if incongruous_fields:
|
||||
record.partner_incongruences = (
|
||||
incongruous_fields + " field/s don't correspond to saved host"
|
||||
)
|
||||
else:
|
||||
record.partner_incongruences = False
|
||||
else:
|
||||
record.partner_incongruences = False
|
||||
|
||||
def _compute_access_url(self):
|
||||
super(PmsCheckinPartner, self)._compute_access_url()
|
||||
for checkin in self:
|
||||
checkin.access_url = "/my/precheckin/%s" % (checkin.id)
|
||||
|
||||
# Constraints and onchanges
|
||||
|
||||
@api.constrains("departure", "arrival")
|
||||
def _check_departure(self):
|
||||
for record in self:
|
||||
if record.departure and record.arrival > record.departure:
|
||||
raise ValidationError(
|
||||
_("Departure date (%s) is prior to arrival on %s")
|
||||
% (record.departure, record.arrival)
|
||||
)
|
||||
|
||||
@api.constrains("partner_id")
|
||||
def _check_partner_id(self):
|
||||
for record in self:
|
||||
if record.partner_id:
|
||||
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 ValidationError(
|
||||
_("This guest is already registered in the room")
|
||||
)
|
||||
|
||||
# REVIEW: Redesign email & mobile control (res.partner? other module in OCA?)
|
||||
# @api.constrains("email")
|
||||
# def check_email_pattern(self):
|
||||
# for record in self:
|
||||
# if record.email:
|
||||
# if not re.search(
|
||||
# r"^[a-zA-Z0-9]([a-zA-z0-9\-\_]*[\.]?[a-zA-Z0-9\-\_]+)*"
|
||||
# r"@([a-zA-z0-9\-]+([\.][a-zA-Z0-9\-\_]+)?\.[a-zA-Z0-9]+)+$",
|
||||
# record.email,
|
||||
# ):
|
||||
# raise ValidationError(_("'%s' is not a valid email", record.email))
|
||||
|
||||
# @api.constrains("mobile")
|
||||
# def check_phone_pattern(self):
|
||||
|
||||
# for record in self:
|
||||
# if record.mobile:
|
||||
|
||||
# if not re.search(
|
||||
# r"^(\d{3}[\-\s]?\d{2}[\-\s]?\d{2}[\-\s]?\d{2}[\-\s]?|"
|
||||
# r"\d{3}[\-\s]?\d{3}[\-\s]?\d{3})$",
|
||||
# str(record.mobile),
|
||||
# ):
|
||||
# raise ValidationError(_("'%s' is not a valid phone", record.mobile))
|
||||
|
||||
@api.constrains("document_number")
|
||||
def check_document_number(self):
|
||||
for record in self:
|
||||
if record.partner_id:
|
||||
for number in record.partner_id.id_numbers:
|
||||
if record.document_type == number.category_id:
|
||||
if record.document_number != number.name:
|
||||
raise ValidationError(_("Document_type has already exists"))
|
||||
|
||||
def _validation_eval_context(self, id_number):
|
||||
self.ensure_one()
|
||||
return {"self": self, "id_number": id_number}
|
||||
|
||||
@api.constrains("document_number", "document_type")
|
||||
def validate_id_number(self):
|
||||
"""Validate the given ID number
|
||||
The method raises an odoo.exceptions.ValidationError if the eval of
|
||||
python validation code fails
|
||||
"""
|
||||
for record in self:
|
||||
if record.document_number and record.document_type:
|
||||
id_number = self.env["res.partner.id_number"].new(
|
||||
{
|
||||
"name": record.document_number,
|
||||
"category_id": record.document_type,
|
||||
}
|
||||
)
|
||||
if (
|
||||
self.env.context.get("id_no_validate")
|
||||
or not record.document_type.validation_code
|
||||
):
|
||||
return
|
||||
eval_context = record._validation_eval_context(id_number)
|
||||
try:
|
||||
safe_eval(
|
||||
record.document_type.validation_code,
|
||||
eval_context,
|
||||
mode="exec",
|
||||
nocopy=True,
|
||||
)
|
||||
except Exception as e:
|
||||
raise UserError(
|
||||
_(
|
||||
"Error when evaluating the id_category validation code:"
|
||||
":\n %s \n(%s)"
|
||||
)
|
||||
% (self.name, e)
|
||||
)
|
||||
if eval_context.get("failed", False):
|
||||
raise ValidationError(
|
||||
_("%s is not a valid %s identifier")
|
||||
% (record.document_number, record.document_type.name)
|
||||
)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# The checkin records are created automatically from adult depends
|
||||
# if you try to create one manually, we update one unassigned checkin
|
||||
reservation_id = vals.get("reservation_id")
|
||||
if reservation_id:
|
||||
reservation = self.env["pms.reservation"].browse(reservation_id)
|
||||
else:
|
||||
raise ValidationError(
|
||||
_("Is mandatory indicate the reservation on the checkin")
|
||||
)
|
||||
draft_checkins = reservation.checkin_partner_ids.filtered(
|
||||
lambda c: c.state == "draft"
|
||||
)
|
||||
if len(reservation.checkin_partner_ids) < reservation.adults:
|
||||
if vals.get("identifier", _("New")) == _("New") or "identifier" not in vals:
|
||||
pms_property_id = (
|
||||
self.env.user.get_active_property_ids()[0]
|
||||
if "pms_property_id" not in vals
|
||||
else vals["pms_property_id"]
|
||||
)
|
||||
pms_property = self.env["pms.property"].browse(pms_property_id)
|
||||
vals["identifier"] = pms_property.checkin_sequence_id._next_do()
|
||||
return super(PmsCheckinPartner, self).create(vals)
|
||||
if len(draft_checkins) > 0:
|
||||
draft_checkins[0].write(vals)
|
||||
return draft_checkins[0]
|
||||
raise ValidationError(
|
||||
_("Is not possible to create the proposed check-in in this reservation")
|
||||
)
|
||||
|
||||
def unlink(self):
|
||||
reservations = self.mapped("reservation_id")
|
||||
res = super().unlink()
|
||||
reservations._compute_checkin_partner_ids()
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def _checkin_mandatory_fields(self, country=False, depends=False):
|
||||
mandatory_fields = [
|
||||
"name",
|
||||
]
|
||||
# api.depends need "reservation_id.state" in the lambda function
|
||||
if depends:
|
||||
mandatory_fields.extend(["reservation_id.state", "name"])
|
||||
|
||||
return mandatory_fields
|
||||
|
||||
@api.model
|
||||
def _checkin_partner_fields(self):
|
||||
checkin_fields = [
|
||||
"firstname",
|
||||
"lastname",
|
||||
"lastname2",
|
||||
"mobile",
|
||||
"email",
|
||||
"gender",
|
||||
"nationality_id",
|
||||
"birthdate_date",
|
||||
]
|
||||
return checkin_fields
|
||||
|
||||
@api.model
|
||||
def import_room_list_json(self, roomlist_json):
|
||||
roomlist_json = json.loads(roomlist_json)
|
||||
for checkin_dict in roomlist_json:
|
||||
identifier = checkin_dict["identifier"]
|
||||
reservation_id = checkin_dict["reservation_id"]
|
||||
checkin = self.env["pms.checkin.partner"].search(
|
||||
[("identifier", "=", identifier)]
|
||||
)
|
||||
reservation = self.env["pms.reservation"].browse(reservation_id)
|
||||
if not checkin:
|
||||
raise ValidationError(
|
||||
_("%s not found in checkins (%s)"), identifier, reservation.name
|
||||
)
|
||||
checkin_vals = {}
|
||||
for key, value in checkin_dict.items():
|
||||
if key in ("reservation_id", "folio_id", "identifier"):
|
||||
continue
|
||||
checkin_vals[key] = value
|
||||
checkin.write(checkin_vals)
|
||||
|
||||
@api.model
|
||||
def calculate_doc_type_expedition_date_from_validity_date(
|
||||
self, doc_type, doc_date, birthdate
|
||||
):
|
||||
today = fields.datetime.today()
|
||||
datetime_doc_date = datetime.strptime(doc_date, DEFAULT_SERVER_DATE_FORMAT)
|
||||
if datetime_doc_date < today:
|
||||
return datetime_doc_date
|
||||
datetime_birthdate = datetime.strptime(birthdate, DEFAULT_SERVER_DATE_FORMAT)
|
||||
age = today.year - datetime_birthdate.year
|
||||
document_type = self.env["res.partner.id_category"].search(
|
||||
[("id", "=", doc_type)]
|
||||
)
|
||||
document_expedition_date = False
|
||||
if document_type.code == "D" or document_type.code == "P":
|
||||
if age < 30:
|
||||
document_expedition_date = datetime_doc_date - relativedelta(years=5)
|
||||
else:
|
||||
document_expedition_date = datetime_doc_date - relativedelta(years=10)
|
||||
if document_type.code == "C":
|
||||
if age < 70:
|
||||
document_expedition_date = datetime_doc_date - relativedelta(years=10)
|
||||
return document_expedition_date
|
||||
|
||||
def action_on_board(self):
|
||||
for record in self:
|
||||
if record.reservation_id.checkin > fields.Date.today():
|
||||
raise ValidationError(_("It is not yet checkin day!"))
|
||||
if record.reservation_id.checkout < fields.Date.today():
|
||||
raise ValidationError(_("Its too late to checkin"))
|
||||
|
||||
if any(
|
||||
not getattr(record, field) for field in self._checkin_mandatory_fields()
|
||||
):
|
||||
raise ValidationError(_("Personal data is missing for check-in"))
|
||||
vals = {
|
||||
"state": "onboard",
|
||||
"arrival": fields.Datetime.now(),
|
||||
}
|
||||
record.update(vals)
|
||||
record.reservation_id.state = "onboard"
|
||||
|
||||
def action_done(self):
|
||||
for record in self.filtered(lambda c: c.state == "onboard"):
|
||||
vals = {
|
||||
"state": "done",
|
||||
"departure": fields.Datetime.now(),
|
||||
}
|
||||
record.update(vals)
|
||||
return True
|
||||
|
||||
def open_partner(self):
|
||||
""" Utility method used to add an "View Customer" button in checkin partner views """
|
||||
self.ensure_one()
|
||||
partner_form_id = self.env.ref("pms.view_partner_data_form").id
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"res_model": "res.partner",
|
||||
"view_mode": "form",
|
||||
"views": [(partner_form_id, "form")],
|
||||
"res_id": self.partner_id.id,
|
||||
"target": "new",
|
||||
"flags": {"form": {"action_buttons": True}},
|
||||
}
|
||||
|
||||
def open_wizard_several_partners(self):
|
||||
ctx = dict(
|
||||
checkin_partner_id=self.id,
|
||||
possible_existing_customer_ids=self.possible_existing_customer_ids.ids,
|
||||
)
|
||||
return {
|
||||
"view_type": "form",
|
||||
"view_mode": "form",
|
||||
"name": "Several Customers",
|
||||
"res_model": "pms.several.partners.wizard",
|
||||
"target": "new",
|
||||
"type": "ir.actions.act_window",
|
||||
"context": ctx,
|
||||
}
|
||||
|
||||
def _save_data_from_portal(self, values):
|
||||
checkin_partner = self.env["pms.checkin.partner"].browse(int(values.get("id")))
|
||||
if values.get("nationality_id"):
|
||||
nationality_id = self.env["res.country"].search(
|
||||
[("id", "=", values.get("nationality_id"))]
|
||||
)
|
||||
values.update({"nationality_id": nationality_id.id})
|
||||
else:
|
||||
values.update({"nationality_id": False})
|
||||
if not values.get("document_type"):
|
||||
values.update({"document_type": False})
|
||||
if values.get("state"):
|
||||
state_id = self.env["res.country.state"].search(
|
||||
[("id", "=", values.get("state"))]
|
||||
)
|
||||
values.update({"state_id": state_id})
|
||||
values.pop("state")
|
||||
if values.get("document_expedition_date"):
|
||||
doc_type = values.get("document_type")
|
||||
doc_date = values.get("document_expedition_date")
|
||||
birthdate = values.get("birthdate_date")
|
||||
document_expedition_date = (
|
||||
self.calculate_doc_type_expedition_date_from_validity_date(
|
||||
doc_type, doc_date, birthdate
|
||||
)
|
||||
)
|
||||
values.update({"document_expedition_date": document_expedition_date})
|
||||
checkin_partner.sudo().write(values)
|
||||
|
||||
def send_portal_invitation_email(self, invitation_firstname=None, email=None):
|
||||
template = self.sudo().env.ref(
|
||||
"pms.precheckin_invitation_email", raise_if_not_found=False
|
||||
)
|
||||
subject = template._render_field(
|
||||
"subject", [6, 0, self.id], compute_lang=True, post_process=True
|
||||
)[self.id]
|
||||
body = template._render_field(
|
||||
"body_html", [6, 0, self.id], compute_lang=True, post_process=True
|
||||
)[self.id]
|
||||
invitation_mail = (
|
||||
self.env["mail.mail"]
|
||||
.sudo()
|
||||
.create(
|
||||
{
|
||||
"subject": subject,
|
||||
"body_html": body,
|
||||
"email_from": self.pms_property_id.partner_id.email,
|
||||
"email_to": email,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
invitation_mail.send()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,492 +0,0 @@
|
||||
# Copyright 2019 Pablo Quesada
|
||||
# Copyright 2019 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import datetime
|
||||
import time
|
||||
|
||||
import pytz
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
|
||||
from odoo.addons.base.models.res_partner import _tz_get
|
||||
|
||||
|
||||
class PmsProperty(models.Model):
|
||||
_name = "pms.property"
|
||||
_description = "Property"
|
||||
_inherits = {"res.partner": "partner_id"}
|
||||
_check_company_auto = True
|
||||
|
||||
partner_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Current property",
|
||||
comodel_name="res.partner",
|
||||
required=True,
|
||||
ondelete="cascade",
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
string="Company",
|
||||
help="The company that owns or operates this property.",
|
||||
comodel_name="res.company",
|
||||
required=True,
|
||||
check_pms_properties=True,
|
||||
)
|
||||
user_ids = fields.Many2many(
|
||||
string="Accepted Users",
|
||||
help="Field related to res.users. Allowed users on the property",
|
||||
comodel_name="res.users",
|
||||
relation="pms_property_users_rel",
|
||||
column1="pms_property_id",
|
||||
column2="user_id",
|
||||
)
|
||||
room_ids = fields.One2many(
|
||||
string="Rooms",
|
||||
help="Rooms that a property has.",
|
||||
comodel_name="pms.room",
|
||||
inverse_name="pms_property_id",
|
||||
)
|
||||
default_pricelist_id = fields.Many2one(
|
||||
string="Product Pricelist",
|
||||
help="The default pricelist used in this property.",
|
||||
comodel_name="product.pricelist",
|
||||
required=True,
|
||||
default=lambda self: self.env.ref("product.list0").id,
|
||||
)
|
||||
default_arrival_hour = fields.Char(
|
||||
string="Arrival Hour", help="HH:mm Format", default="14:00"
|
||||
)
|
||||
default_departure_hour = fields.Char(
|
||||
string="Departure Hour", help="HH:mm Format", default="12:00"
|
||||
)
|
||||
folio_sequence_id = fields.Many2one(
|
||||
string="Folio Sequence",
|
||||
help="The sequence that formed the name of the folio.",
|
||||
check_company=True,
|
||||
copy=False,
|
||||
comodel_name="ir.sequence",
|
||||
)
|
||||
reservation_sequence_id = fields.Many2one(
|
||||
string="Reservation Sequence",
|
||||
help="The sequence that formed the name of the reservation.",
|
||||
check_company=True,
|
||||
copy=False,
|
||||
comodel_name="ir.sequence",
|
||||
)
|
||||
checkin_sequence_id = fields.Many2one(
|
||||
string="Checkin Sequence",
|
||||
help="Field used to create the name of the checkin partner",
|
||||
check_company=True,
|
||||
copy=False,
|
||||
comodel_name="ir.sequence",
|
||||
)
|
||||
|
||||
tz = fields.Selection(
|
||||
string="Timezone",
|
||||
help="This field is used to determine de timezone of the property.",
|
||||
required=True,
|
||||
default=lambda self: self.env.user.tz or "UTC",
|
||||
selection=_tz_get,
|
||||
)
|
||||
|
||||
cardex_warning = fields.Text(
|
||||
string="Warning in Cardex",
|
||||
default="Time to access rooms: 14: 00h. "
|
||||
"Departure time: 12: 00h. If the accommodation "
|
||||
"is not left at that time, the establishment will "
|
||||
"charge a day's stay according to current rate that day",
|
||||
help="Notice under the signature on the traveler's ticket.",
|
||||
)
|
||||
free_room_ids = fields.One2many(
|
||||
string="Rooms available",
|
||||
help="allows you to send different parameters in the context "
|
||||
"(checkin(required), checkout(required), room_type_id, ubication_id, capacity, "
|
||||
"amenity_ids and / or pricelist_id) and return rooms available",
|
||||
comodel_name="pms.room",
|
||||
compute="_compute_free_room_ids",
|
||||
)
|
||||
availability = fields.Integer(
|
||||
string="Number of rooms available",
|
||||
help="allows you to send different parameters in the context "
|
||||
"(checkin(required), checkout(required), room_type_id, ubication_id, capacity,"
|
||||
"amenity_ids and / or pricelist_id) check the availability for the hotel",
|
||||
compute="_compute_availability",
|
||||
)
|
||||
|
||||
mail_information = fields.Html(
|
||||
string="Mail Information", help="Additional information of the mail"
|
||||
)
|
||||
|
||||
privacy_policy = fields.Html(string="Privacy Policy", help="Mail privacy policy ")
|
||||
|
||||
property_confirmed_template = fields.Many2one(
|
||||
string="Confirmation Email",
|
||||
help="Confirmation email template",
|
||||
comodel_name="mail.template",
|
||||
)
|
||||
|
||||
property_modified_template = fields.Many2one(
|
||||
string="Modification Email",
|
||||
help="Modification email template",
|
||||
comodel_name="mail.template",
|
||||
)
|
||||
|
||||
property_canceled_template = fields.Many2one(
|
||||
string="Cancellation Email",
|
||||
help="Cancellation email template",
|
||||
comodel_name="mail.template",
|
||||
)
|
||||
|
||||
is_confirmed_auto_mail = fields.Boolean(string="Auto Send Confirmation Mail")
|
||||
is_modified_auto_mail = fields.Boolean(string="Auto Send Modification Mail")
|
||||
is_canceled_auto_mail = fields.Boolean(string="Auto Send Cancellation Mail")
|
||||
|
||||
@api.depends_context(
|
||||
"checkin",
|
||||
"checkout",
|
||||
"real_avail",
|
||||
"room_type_id",
|
||||
"ubication_id",
|
||||
"capacity",
|
||||
"amenity_ids",
|
||||
"pricelist_id",
|
||||
"class_id",
|
||||
"overnight_rooms",
|
||||
"current_lines",
|
||||
)
|
||||
def _compute_free_room_ids(self):
|
||||
checkin = self._context["checkin"]
|
||||
checkout = self._context["checkout"]
|
||||
|
||||
if isinstance(checkin, str):
|
||||
checkin = datetime.datetime.strptime(
|
||||
checkin, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
if isinstance(checkout, str):
|
||||
checkout = datetime.datetime.strptime(
|
||||
checkout, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
current_lines = self.env.context.get("current_lines", False)
|
||||
if current_lines and not isinstance(current_lines, list):
|
||||
current_lines = [current_lines]
|
||||
|
||||
pricelist_id = self.env.context.get("pricelist_id", False)
|
||||
room_type_id = self.env.context.get("room_type_id", False)
|
||||
class_id = self._context.get("class_id", False)
|
||||
real_avail = self._context.get("real_avail", False)
|
||||
overnight_rooms = self._context.get("overnight_rooms", False)
|
||||
for pms_property in self:
|
||||
free_rooms = pms_property.get_real_free_rooms(
|
||||
checkin, checkout, current_lines
|
||||
)
|
||||
if pricelist_id and not real_avail:
|
||||
# TODO: only closed_departure take account checkout date!
|
||||
domain_rules = [
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout),
|
||||
("pms_property_id", "=", pms_property.id),
|
||||
]
|
||||
if room_type_id:
|
||||
domain_rules.append(("room_type_id", "=", room_type_id))
|
||||
|
||||
pricelist = self.env["product.pricelist"].browse(pricelist_id)
|
||||
if pricelist.availability_plan_id:
|
||||
domain_rules.append(
|
||||
("availability_plan_id", "=", pricelist.availability_plan_id.id)
|
||||
)
|
||||
rule_items = self.env["pms.availability.plan.rule"].search(
|
||||
domain_rules
|
||||
)
|
||||
|
||||
if len(rule_items) > 0:
|
||||
room_types_to_remove = []
|
||||
for item in rule_items:
|
||||
if pricelist.availability_plan_id.any_rule_applies(
|
||||
checkin, checkout, item
|
||||
):
|
||||
room_types_to_remove.append(item.room_type_id.id)
|
||||
free_rooms = free_rooms.filtered(
|
||||
lambda x: x.room_type_id.id not in room_types_to_remove
|
||||
)
|
||||
if class_id:
|
||||
free_rooms = free_rooms.filtered(
|
||||
lambda x: x.room_type_id.class_id.id == class_id
|
||||
)
|
||||
if overnight_rooms:
|
||||
free_rooms = free_rooms.filtered(
|
||||
lambda x: x.room_type_id.overnight_room
|
||||
)
|
||||
if len(free_rooms) > 0:
|
||||
pms_property.free_room_ids = free_rooms.ids
|
||||
else:
|
||||
pms_property.free_room_ids = False
|
||||
|
||||
def get_real_free_rooms(self, checkin, checkout, current_lines=False):
|
||||
self.ensure_one()
|
||||
Avail = self.env["pms.availability"]
|
||||
target_rooms = self.env["pms.room"].search([("pms_property_id", "=", self.id)])
|
||||
|
||||
room_type_id = self.env.context.get("room_type_id", False)
|
||||
if room_type_id:
|
||||
target_rooms = target_rooms.filtered(
|
||||
lambda r: r.room_type_id.id == room_type_id
|
||||
)
|
||||
capacity = self.env.context.get("capacity", False)
|
||||
if capacity:
|
||||
target_rooms = target_rooms.filtered(lambda r: r.capacity >= capacity)
|
||||
|
||||
ubication_id = self.env.context.get("ubication_id", False)
|
||||
if ubication_id:
|
||||
target_rooms = target_rooms.filtered(
|
||||
lambda r: r.ubication_id.id == ubication_id
|
||||
)
|
||||
|
||||
amenity_ids = self.env.context.get("amenity_ids", False)
|
||||
if amenity_ids:
|
||||
if amenity_ids and not isinstance(amenity_ids, list):
|
||||
amenity_ids = [amenity_ids]
|
||||
target_rooms = target_rooms.filtered(
|
||||
lambda r: len(set(amenity_ids) - set(r.room_amenity_ids.ids)) == 0
|
||||
)
|
||||
|
||||
if not current_lines:
|
||||
current_lines = []
|
||||
|
||||
rooms_not_avail_ids = Avail.get_rooms_not_avail(
|
||||
checkin=checkin,
|
||||
checkout=checkout,
|
||||
room_ids=target_rooms.ids,
|
||||
pms_property_id=self.id,
|
||||
current_lines=current_lines,
|
||||
)
|
||||
domain_rooms = [("id", "in", target_rooms.ids)]
|
||||
if rooms_not_avail_ids:
|
||||
domain_rooms.append(
|
||||
("id", "not in", rooms_not_avail_ids),
|
||||
)
|
||||
return self.env["pms.room"].search(domain_rooms)
|
||||
|
||||
@api.depends_context(
|
||||
"checkin",
|
||||
"checkout",
|
||||
"real_avail",
|
||||
"room_type_id",
|
||||
"ubication_id",
|
||||
"capacity",
|
||||
"amenity_ids",
|
||||
"pricelist_id",
|
||||
"class_id",
|
||||
"overnight_rooms",
|
||||
"current_lines",
|
||||
)
|
||||
def _compute_availability(self):
|
||||
for record in self:
|
||||
checkin = self._context["checkin"]
|
||||
checkout = self._context["checkout"]
|
||||
if isinstance(checkin, str):
|
||||
checkin = datetime.datetime.strptime(
|
||||
checkin, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
if isinstance(checkout, str):
|
||||
checkout = datetime.datetime.strptime(
|
||||
checkout, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
room_type_id = self.env.context.get("room_type_id", False)
|
||||
pricelist_id = self.env.context.get("pricelist_id", False)
|
||||
current_lines = self.env.context.get("current_lines", [])
|
||||
class_id = self._context.get("class_id", False)
|
||||
real_avail = self._context.get("real_avail", False)
|
||||
overnight_rooms = self._context.get("overnight_rooms", False)
|
||||
pms_property = record.with_context(
|
||||
checkin=checkin,
|
||||
checkout=checkout,
|
||||
room_type_id=room_type_id,
|
||||
current_lines=current_lines,
|
||||
pricelist_id=pricelist_id,
|
||||
class_id=class_id,
|
||||
real_avail=real_avail,
|
||||
overnight_rooms=overnight_rooms,
|
||||
)
|
||||
count_free_rooms = len(pms_property.free_room_ids)
|
||||
if current_lines and not isinstance(current_lines, list):
|
||||
current_lines = [current_lines]
|
||||
|
||||
domain_rules = [
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout),
|
||||
("pms_property_id", "=", pms_property.id),
|
||||
]
|
||||
if room_type_id:
|
||||
domain_rules.append(("room_type_id", "=", room_type_id))
|
||||
|
||||
pricelist = False
|
||||
if pricelist_id:
|
||||
pricelist = self.env["product.pricelist"].browse(pricelist_id)
|
||||
if pricelist and pricelist.availability_plan_id and not real_avail:
|
||||
domain_rules.append(
|
||||
("availability_plan_id", "=", pricelist.availability_plan_id.id)
|
||||
)
|
||||
rule_groups = self.env["pms.availability.plan.rule"].read_group(
|
||||
domain_rules,
|
||||
["plan_avail:sum"],
|
||||
["date:day"],
|
||||
lazy=False,
|
||||
)
|
||||
if len(rule_groups) > 0:
|
||||
# If in the group per day, some room type has the sale blocked,
|
||||
# we must subtract from that day the availability of that room type
|
||||
for group in rule_groups:
|
||||
items = self.env["pms.availability.plan.rule"].search(
|
||||
group["__domain"]
|
||||
)
|
||||
for item in items:
|
||||
if pricelist.availability_plan_id.any_rule_applies(
|
||||
checkin, checkout, item
|
||||
):
|
||||
group["plan_avail"] -= item.plan_avail
|
||||
count_free_rooms = min(i["plan_avail"] for i in rule_groups)
|
||||
record.availability = count_free_rooms
|
||||
|
||||
@api.model
|
||||
def splitted_availability(
|
||||
self,
|
||||
checkin,
|
||||
checkout,
|
||||
pms_property_id,
|
||||
room_type_id=False,
|
||||
current_lines=False,
|
||||
pricelist=False,
|
||||
):
|
||||
if isinstance(checkin, str):
|
||||
checkin = datetime.datetime.strptime(
|
||||
checkin, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
if isinstance(checkout, str):
|
||||
checkout = datetime.datetime.strptime(
|
||||
checkout, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
for date_iterator in [
|
||||
checkin + datetime.timedelta(days=x)
|
||||
for x in range(0, (checkout - checkin).days)
|
||||
]:
|
||||
pms_property = self.env["pms.property"].browse(pms_property_id)
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=date_iterator,
|
||||
checkout=date_iterator + datetime.timedelta(1),
|
||||
room_type_id=room_type_id,
|
||||
current_lines=current_lines,
|
||||
pricelist_id=pricelist.id,
|
||||
)
|
||||
|
||||
if len(pms_property.free_room_ids) < 1:
|
||||
return False
|
||||
return True
|
||||
|
||||
@api.constrains("default_arrival_hour")
|
||||
def _check_arrival_hour(self):
|
||||
for record in self:
|
||||
try:
|
||||
time.strptime(record.default_arrival_hour, "%H:%M")
|
||||
return True
|
||||
except ValueError:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"Format Arrival Hour (HH:MM) Error: %s",
|
||||
record.default_arrival_hour,
|
||||
)
|
||||
)
|
||||
|
||||
@api.constrains("default_departure_hour")
|
||||
def _check_departure_hour(self):
|
||||
for record in self:
|
||||
try:
|
||||
time.strptime(record.default_departure_hour, "%H:%M")
|
||||
return True
|
||||
except ValueError:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"Format Departure Hour (HH:MM) Error: %s",
|
||||
record.default_departure_hour,
|
||||
)
|
||||
)
|
||||
|
||||
def date_property_timezone(self, dt):
|
||||
self.ensure_one()
|
||||
if self.env.user:
|
||||
tz_property = self.tz
|
||||
dt = pytz.timezone(tz_property).localize(dt)
|
||||
dt = dt.replace(tzinfo=None)
|
||||
dt = pytz.timezone(self.env.user.tz).localize(dt)
|
||||
dt = dt.astimezone(pytz.utc)
|
||||
dt = dt.replace(tzinfo=None)
|
||||
return dt
|
||||
|
||||
def _get_payment_methods(self, automatic_included=False):
|
||||
# We use automatic_included to True to see absolutely
|
||||
# all the journals with associated payments, if it is
|
||||
# false, we will only see those journals that can be used
|
||||
# to pay manually
|
||||
self.ensure_one()
|
||||
payment_methods = self.env["account.journal"].search(
|
||||
[
|
||||
("type", "in", ["cash", "bank"]),
|
||||
"|",
|
||||
("pms_property_ids", "in", self.id),
|
||||
"|",
|
||||
"&",
|
||||
("pms_property_ids", "=", False),
|
||||
("company_id", "=", self.company_id.id),
|
||||
"&",
|
||||
("pms_property_ids", "=", False),
|
||||
("company_id", "=", False),
|
||||
]
|
||||
)
|
||||
if not automatic_included:
|
||||
payment_methods = payment_methods.filtered(lambda p: p.allowed_pms_payments)
|
||||
return payment_methods
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
name = vals.get("name")
|
||||
if "folio_sequence_id" not in vals or not vals.get("folio_sequence_id"):
|
||||
folio_sequence = self.env["ir.sequence"].create(
|
||||
{
|
||||
"name": "PMS Folio " + name,
|
||||
"code": "pms.folio",
|
||||
"prefix": "F/%(y)s",
|
||||
"suffix": "%(sec)s",
|
||||
"padding": 4,
|
||||
"company_id": vals.get("company_id"),
|
||||
}
|
||||
)
|
||||
vals.update({"folio_sequence_id": folio_sequence.id})
|
||||
if "reservation_sequence_id" not in vals or not vals.get(
|
||||
"reservation_sequence_id"
|
||||
):
|
||||
reservation_sequence = self.env["ir.sequence"].create(
|
||||
{
|
||||
"name": "PMS Reservation " + name,
|
||||
"code": "pms.reservation",
|
||||
"prefix": "R/%(y)s",
|
||||
"suffix": "%(sec)s",
|
||||
"padding": 4,
|
||||
"company_id": vals.get("company_id"),
|
||||
}
|
||||
)
|
||||
vals.update({"reservation_sequence_id": reservation_sequence.id})
|
||||
if "checkin_sequence_id" not in vals or not vals.get("checkin_sequence_id"):
|
||||
checkin_sequence = self.env["ir.sequence"].create(
|
||||
{
|
||||
"name": "PMS Checkin " + name,
|
||||
"code": "pms.checkin.partner",
|
||||
"prefix": "C/%(y)s",
|
||||
"suffix": "%(sec)s",
|
||||
"padding": 4,
|
||||
"company_id": vals.get("company_id"),
|
||||
}
|
||||
)
|
||||
vals.update({"checkin_sequence_id": checkin_sequence.id})
|
||||
record = super(PmsProperty, self).create(vals)
|
||||
return record
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,483 +0,0 @@
|
||||
# Copyright 2017-2018 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PmsReservationLine(models.Model):
|
||||
_name = "pms.reservation.line"
|
||||
_description = "Reservations by day"
|
||||
_order = "date"
|
||||
_check_company_auto = True
|
||||
|
||||
reservation_id = fields.Many2one(
|
||||
string="Reservation",
|
||||
help="It is the reservation in a reservation line",
|
||||
required=True,
|
||||
copy=False,
|
||||
comodel_name="pms.reservation",
|
||||
ondelete="cascade",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
room_id = fields.Many2one(
|
||||
string="Room",
|
||||
help="The room of a reservation. ",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_room_id",
|
||||
comodel_name="pms.room",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
|
||||
sale_line_ids = fields.Many2many(
|
||||
string="Sales Lines",
|
||||
readonly=True,
|
||||
copy=False,
|
||||
comodel_name="folio.sale.line",
|
||||
relation="reservation_line_sale_line_rel",
|
||||
column1="reservation_line_id",
|
||||
column2="sale_line_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Property with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
readonly=True,
|
||||
store=True,
|
||||
comodel_name="pms.property",
|
||||
related="reservation_id.pms_property_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
date = fields.Date(
|
||||
string="Date",
|
||||
help="The date of the reservation in reservation line",
|
||||
)
|
||||
state = fields.Selection(
|
||||
string="State",
|
||||
help="State of the reservation line.",
|
||||
related="reservation_id.state",
|
||||
store=True,
|
||||
)
|
||||
price = fields.Float(
|
||||
string="Price",
|
||||
help="The price in a reservation line",
|
||||
store=True,
|
||||
readonly=False,
|
||||
digits=("Product Price"),
|
||||
compute="_compute_price",
|
||||
)
|
||||
cancel_discount = fields.Float(
|
||||
string="Cancelation Discount (%)",
|
||||
help="",
|
||||
readonly=False,
|
||||
default=0.0,
|
||||
store=True,
|
||||
digits=("Discount"),
|
||||
compute="_compute_cancel_discount",
|
||||
)
|
||||
avail_id = fields.Many2one(
|
||||
string="Availability Day",
|
||||
help="",
|
||||
store=True,
|
||||
comodel_name="pms.availability",
|
||||
ondelete="restrict",
|
||||
compute="_compute_avail_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
|
||||
discount = fields.Float(
|
||||
string="Discount (%)",
|
||||
help="",
|
||||
default=0.0,
|
||||
digits=("Discount"),
|
||||
)
|
||||
occupies_availability = fields.Boolean(
|
||||
string="Occupies",
|
||||
help="This record is taken into account to calculate availability",
|
||||
store=True,
|
||||
compute="_compute_occupies_availability",
|
||||
)
|
||||
impacts_quota = fields.Integer(
|
||||
string="Impacts quota",
|
||||
help="This line has been taken into account in the avail quota",
|
||||
readonly=True,
|
||||
store=True,
|
||||
compute="_compute_impacts_quota",
|
||||
)
|
||||
overnight_room = fields.Boolean(
|
||||
related="reservation_id.overnight_room",
|
||||
store=True,
|
||||
)
|
||||
_sql_constraints = [
|
||||
(
|
||||
"rule_availability",
|
||||
"EXCLUDE (room_id WITH =, date WITH =) \
|
||||
WHERE (occupies_availability = True)",
|
||||
"Room Occupied",
|
||||
),
|
||||
]
|
||||
|
||||
def name_get(self):
|
||||
result = []
|
||||
for res in self:
|
||||
date = fields.Date.from_string(res.date)
|
||||
name = u"{}/{}".format(date.day, date.month)
|
||||
result.append((res.id, name))
|
||||
return result
|
||||
|
||||
def _get_display_price(self, product):
|
||||
if self.reservation_id.pricelist_id.discount_policy == "with_discount":
|
||||
return product.with_context(
|
||||
pricelist=self.reservation_id.pricelist_id.id
|
||||
).price
|
||||
product_context = dict(
|
||||
self.env.context,
|
||||
partner_id=self.reservation_id.partner_id.id,
|
||||
date=self.date,
|
||||
uom=product.uom_id.id,
|
||||
)
|
||||
final_price, rule_id = self.reservation_id.pricelist_id.with_context(
|
||||
product_context
|
||||
).get_product_price_rule(product, 1.0, self.reservation_id.partner_id)
|
||||
base_price, currency = self.with_context(
|
||||
product_context
|
||||
)._get_real_price_currency(
|
||||
product, rule_id, 1, product.uom_id, self.reservation_id.pricelist_id.id
|
||||
)
|
||||
if currency != self.reservation_id.pricelist_id.currency_id:
|
||||
base_price = currency._convert(
|
||||
base_price,
|
||||
self.reservation_id.pricelist_id.currency_id,
|
||||
self.reservation_id.company_id or self.env.company,
|
||||
fields.Date.today(),
|
||||
)
|
||||
# negative discounts (= surcharge) are included in the display price
|
||||
return max(base_price, final_price)
|
||||
|
||||
@api.depends("reservation_id.room_type_id", "reservation_id.preferred_room_id")
|
||||
def _compute_room_id(self):
|
||||
for line in self.filtered("reservation_id.room_type_id").sorted(
|
||||
key=lambda r: (r.reservation_id, r.date)
|
||||
):
|
||||
reservation = line.reservation_id
|
||||
if (
|
||||
reservation.preferred_room_id
|
||||
and reservation.preferred_room_id != line.room_id
|
||||
) or (
|
||||
(reservation.preferred_room_id or reservation.room_type_id)
|
||||
and not line.room_id
|
||||
):
|
||||
free_room_select = True if reservation.preferred_room_id else False
|
||||
|
||||
# we get the rooms available for the entire stay
|
||||
# (real_avail if True if the reservation was created with
|
||||
# specific room selected)
|
||||
pms_property = line.pms_property_id
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=reservation.checkin,
|
||||
checkout=reservation.checkout,
|
||||
room_type_id=reservation.room_type_id.id
|
||||
if not free_room_select
|
||||
else False,
|
||||
current_lines=reservation.reservation_line_ids.ids,
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
real_avail=free_room_select,
|
||||
)
|
||||
rooms_available = pms_property.free_room_ids
|
||||
|
||||
# Check if the room assigment is manual or automatic to set the
|
||||
# to_assign value on reservation
|
||||
manual_assigned = False
|
||||
if (
|
||||
free_room_select
|
||||
and reservation.preferred_room_id.id
|
||||
not in reservation.reservation_line_ids.room_id.ids
|
||||
):
|
||||
# This case is a preferred_room_id manually assigned
|
||||
manual_assigned = True
|
||||
# if there is availability for the entire stay
|
||||
if rooms_available:
|
||||
# Avoid that reservation._compute_splitted set the
|
||||
# reservation like splitted in intermediate calculations
|
||||
reservation = reservation.with_context(not_split=True)
|
||||
# if the reservation has a preferred room
|
||||
if reservation.preferred_room_id:
|
||||
|
||||
# if the preferred room is available
|
||||
if reservation.preferred_room_id in rooms_available:
|
||||
line.room_id = reservation.preferred_room_id
|
||||
reservation.to_assign = (
|
||||
False if manual_assigned else reservation.to_assign
|
||||
)
|
||||
|
||||
# if the preferred room is NOT available
|
||||
else:
|
||||
if self.env.context.get("force_overbooking"):
|
||||
reservation.overbooking = True
|
||||
line.room_id = reservation.preferred_room_id
|
||||
else:
|
||||
raise ValidationError(
|
||||
_("%s: No room available in %s <-> %s.")
|
||||
% (
|
||||
reservation.preferred_room_id.name,
|
||||
reservation.checkin,
|
||||
reservation.checkout,
|
||||
)
|
||||
)
|
||||
|
||||
# otherwise we assign the first of those
|
||||
# available for the entire stay
|
||||
else:
|
||||
line.room_id = rooms_available[0]
|
||||
# check that the reservation cannot be allocated even by dividing it
|
||||
elif not self.env["pms.property"].splitted_availability(
|
||||
checkin=reservation.checkin,
|
||||
checkout=reservation.checkout,
|
||||
room_type_id=reservation.room_type_id.id,
|
||||
current_lines=line._origin.reservation_id.reservation_line_ids.ids,
|
||||
pricelist=reservation.pricelist_id,
|
||||
pms_property_id=line.pms_property_id.id,
|
||||
):
|
||||
if self.env.context.get("force_overbooking"):
|
||||
reservation.overbooking = True
|
||||
line.room_id = reservation.room_type_id.room_ids[0]
|
||||
else:
|
||||
raise ValidationError(
|
||||
_("%s: No room type available")
|
||||
% (reservation.room_type_id.name)
|
||||
)
|
||||
|
||||
# the reservation can be allocated into several rooms
|
||||
else:
|
||||
rooms_ranking = dict()
|
||||
|
||||
# we go through the rooms of the type
|
||||
for room in self.env["pms.room"].search(
|
||||
[
|
||||
("room_type_id", "=", reservation.room_type_id.id),
|
||||
("pms_property_id", "=", reservation.pms_property_id.id),
|
||||
]
|
||||
):
|
||||
# we iterate the dates from the date of the line to the checkout
|
||||
for date_iterator in [
|
||||
line.date + datetime.timedelta(days=x)
|
||||
for x in range(0, (reservation.checkout - line.date).days)
|
||||
]:
|
||||
# if the room is already assigned for
|
||||
# a date we go to the next room
|
||||
ids = reservation.reservation_line_ids.ids
|
||||
if (
|
||||
self.env["pms.reservation.line"].search_count(
|
||||
[
|
||||
("date", "=", date_iterator),
|
||||
("room_id", "=", room.id),
|
||||
("id", "not in", ids),
|
||||
("occupies_availability", "=", True),
|
||||
]
|
||||
)
|
||||
> 0
|
||||
):
|
||||
break
|
||||
# if the room is not assigned for a date we
|
||||
# add it to the ranking / update its ranking
|
||||
else:
|
||||
rooms_ranking[room.id] = (
|
||||
1
|
||||
if room.id not in rooms_ranking
|
||||
else rooms_ranking[room.id] + 1
|
||||
)
|
||||
|
||||
if len(rooms_ranking) > 0:
|
||||
# we get the best score in the ranking
|
||||
best = max(rooms_ranking.values())
|
||||
|
||||
# we keep the rooms with the best ranking
|
||||
bests = {
|
||||
key: value
|
||||
for (key, value) in rooms_ranking.items()
|
||||
if value == best
|
||||
}
|
||||
|
||||
# if there is a tie in the rankings
|
||||
if len(bests) > 1:
|
||||
|
||||
# we get the line from last night
|
||||
date_last_night = line.date + datetime.timedelta(days=-1)
|
||||
line_past_night = self.env["pms.reservation.line"].search(
|
||||
[
|
||||
("date", "=", date_last_night),
|
||||
("reservation_id", "=", reservation.id),
|
||||
]
|
||||
)
|
||||
# if there is the night before and if the room
|
||||
# from the night before is in the ranking
|
||||
if line_past_night and line_past_night.room_id.id in bests:
|
||||
line.room_id = line_past_night.room_id.id
|
||||
|
||||
# if the room from the night before is not in the ranking
|
||||
# or there is no night before
|
||||
else:
|
||||
# At this point we set the room with the best ranking,
|
||||
# no matter what it is
|
||||
line.room_id = list(bests.keys())[0]
|
||||
|
||||
# if there is no tie in the rankings
|
||||
else:
|
||||
# At this point we set the room with the best ranking,
|
||||
# no matter what it is
|
||||
line.room_id = list(bests.keys())[0]
|
||||
|
||||
@api.depends("reservation_id.room_type_id", "reservation_id.pricelist_id")
|
||||
def _compute_impacts_quota(self):
|
||||
for line in self:
|
||||
reservation = line.reservation_id
|
||||
if isinstance(line.id, int):
|
||||
impacts_quota = False
|
||||
else:
|
||||
impacts_quota = line.impacts_quota
|
||||
line.impacts_quota = self.env["pms.availability.plan"].update_quota(
|
||||
pricelist_id=reservation.pricelist_id,
|
||||
room_type_id=reservation.room_type_id,
|
||||
date=line.date,
|
||||
impacts_quota_id=impacts_quota,
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"reservation_id",
|
||||
"reservation_id.room_type_id",
|
||||
"reservation_id.reservation_type",
|
||||
"reservation_id.pms_property_id",
|
||||
)
|
||||
def _compute_price(self):
|
||||
for line in self:
|
||||
reservation = line.reservation_id
|
||||
if (
|
||||
not reservation.room_type_id
|
||||
or not reservation.pricelist_id
|
||||
or not reservation.pms_property_id
|
||||
or reservation.reservation_type != "normal"
|
||||
):
|
||||
line.price = 0
|
||||
elif not line.price or self._context.get("force_recompute"):
|
||||
room_type_id = reservation.room_type_id.id
|
||||
product = self.env["pms.room.type"].browse(room_type_id).product_id
|
||||
partner = self.env["res.partner"].browse(reservation.partner_id.id)
|
||||
product = product.with_context(
|
||||
lang=partner.lang,
|
||||
partner=partner.id,
|
||||
quantity=1,
|
||||
date=reservation.date_order,
|
||||
consumption_date=line.date,
|
||||
pricelist=reservation.pricelist_id.id,
|
||||
uom=product.uom_id.id,
|
||||
property=reservation.pms_property_id.id,
|
||||
)
|
||||
line.price = self.env["account.tax"]._fix_tax_included_price_company(
|
||||
line._get_display_price(product),
|
||||
product.taxes_id,
|
||||
reservation.tax_ids,
|
||||
reservation.company_id,
|
||||
)
|
||||
# TODO: Out of service 0 amount
|
||||
|
||||
@api.depends("reservation_id.state", "reservation_id.overbooking")
|
||||
def _compute_occupies_availability(self):
|
||||
for line in self:
|
||||
if line.reservation_id.state == "cancel" or line.reservation_id.overbooking:
|
||||
line.occupies_availability = False
|
||||
else:
|
||||
line.occupies_availability = True
|
||||
|
||||
# TODO: Refact method and allowed cancelled single days
|
||||
@api.depends("reservation_id.cancelled_reason")
|
||||
def _compute_cancel_discount(self):
|
||||
for line in self:
|
||||
line.cancel_discount = 0
|
||||
reservation = line.reservation_id
|
||||
pricelist = reservation.pricelist_id
|
||||
if reservation.state == "cancel":
|
||||
if (
|
||||
reservation.cancelled_reason
|
||||
and pricelist
|
||||
and pricelist.cancelation_rule_id
|
||||
):
|
||||
checkin = fields.Date.from_string(reservation.checkin)
|
||||
checkout = fields.Date.from_string(reservation.checkout)
|
||||
days = abs((checkin - checkout).days)
|
||||
rule = pricelist.cancelation_rule_id
|
||||
discount = 0
|
||||
if reservation.cancelled_reason == "late":
|
||||
discount = 100 - rule.penalty_late
|
||||
if rule.apply_on_late == "first":
|
||||
days = 1
|
||||
elif rule.apply_on_late == "days":
|
||||
days = rule.days_late
|
||||
elif reservation.cancelled_reason == "noshow":
|
||||
discount = 100 - rule.penalty_noshow
|
||||
if rule.apply_on_noshow == "first":
|
||||
days = 1
|
||||
elif rule.apply_on_noshow == "days":
|
||||
days = rule.days_late - 1
|
||||
elif reservation.cancelled_reason == "intime":
|
||||
discount = 100
|
||||
|
||||
dates = []
|
||||
for i in range(0, days):
|
||||
dates.append(
|
||||
fields.Date.from_string(
|
||||
fields.Date.from_string(checkin)
|
||||
+ datetime.timedelta(days=i)
|
||||
)
|
||||
)
|
||||
reservation.reservation_line_ids.filtered(
|
||||
lambda r: r.date in dates
|
||||
).update({"cancel_discount": discount})
|
||||
reservation.reservation_line_ids.filtered(
|
||||
lambda r: r.date not in dates
|
||||
).update({"cancel_discount": 100})
|
||||
else:
|
||||
reservation.reservation_line_ids.update({"cancel_discount": 0})
|
||||
else:
|
||||
reservation.reservation_line_ids.update({"cancel_discount": 0})
|
||||
|
||||
@api.depends("room_id", "pms_property_id", "date", "occupies_availability")
|
||||
def _compute_avail_id(self):
|
||||
for record in self:
|
||||
if record.room_id.room_type_id and record.date and record.pms_property_id:
|
||||
avail = self.env["pms.availability"].search(
|
||||
[
|
||||
("date", "=", record.date),
|
||||
("room_type_id", "=", record.room_id.room_type_id.id),
|
||||
("pms_property_id", "=", record.pms_property_id.id),
|
||||
]
|
||||
)
|
||||
if avail:
|
||||
record.avail_id = avail.id
|
||||
else:
|
||||
record.avail_id = self.env["pms.availability"].create(
|
||||
{
|
||||
"date": record.date,
|
||||
"room_type_id": record.room_id.room_type_id.id,
|
||||
"pms_property_id": record.pms_property_id.id,
|
||||
}
|
||||
)
|
||||
else:
|
||||
record.avail_id = False
|
||||
|
||||
# Constraints and onchanges
|
||||
@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
|
||||
)
|
||||
if duplicated:
|
||||
raise ValidationError(_("Duplicated reservation line date"))
|
||||
@@ -1,185 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# Copyright 2018 Pablo Quesada
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class PmsRoom(models.Model):
|
||||
"""The rooms for lodging can be for sleeping, usually called rooms,
|
||||
and also for speeches (conference rooms), parking,
|
||||
relax with cafe con leche, spa...
|
||||
"""
|
||||
|
||||
_name = "pms.room"
|
||||
_description = "Property Room"
|
||||
_order = "sequence, room_type_id, name"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
name = fields.Char(
|
||||
string="Room Name",
|
||||
help="Room Name",
|
||||
required=True,
|
||||
)
|
||||
active = fields.Boolean(
|
||||
string="Active", help="Determines if room is active", default=True
|
||||
)
|
||||
sequence = fields.Integer(
|
||||
string="Sequence",
|
||||
help="Field used to change the position of the rooms in tree view."
|
||||
"Changing the position changes the sequence",
|
||||
default=0,
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
required=True,
|
||||
default=lambda self: self.env.user.get_active_property_ids()[0],
|
||||
comodel_name="pms.property",
|
||||
ondelete="restrict",
|
||||
)
|
||||
room_type_id = fields.Many2one(
|
||||
string="Property Room Type",
|
||||
help="Unique room type for the rooms",
|
||||
required=True,
|
||||
comodel_name="pms.room.type",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
parent_id = fields.Many2one(
|
||||
string="Parent Room",
|
||||
help="Indicates that this room is a child of another room",
|
||||
comodel_name="pms.room",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
child_ids = fields.One2many(
|
||||
string="Child Rooms",
|
||||
help="Child rooms of the room",
|
||||
comodel_name="pms.room",
|
||||
inverse_name="parent_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
ubication_id = fields.Many2one(
|
||||
string="Ubication",
|
||||
help="At which ubication the room is located.",
|
||||
comodel_name="pms.ubication",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
capacity = fields.Integer(
|
||||
string="Capacity", help="The maximum number of people that can occupy a room"
|
||||
)
|
||||
extra_beds_allowed = fields.Integer(
|
||||
string="Extra Beds Allowed",
|
||||
help="Number of extra beds allowed in room",
|
||||
required=True,
|
||||
default="0",
|
||||
)
|
||||
room_amenity_ids = fields.Many2many(
|
||||
string="Room Amenities",
|
||||
help="List of amenities included in room",
|
||||
comodel_name="pms.amenity",
|
||||
relation="pms_room_amenity_rel",
|
||||
column1="room_id",
|
||||
column2="amenity_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
is_shared_room = fields.Boolean(
|
||||
string="Is a Shared Room",
|
||||
help="allows you to reserve units " " smaller than the room itself (eg beds)",
|
||||
compute="_compute_is_shared_room",
|
||||
readonly=False,
|
||||
store=True,
|
||||
)
|
||||
description_sale = fields.Text(
|
||||
string="Sale Description",
|
||||
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",
|
||||
translate=True,
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
"room_property_unique",
|
||||
"unique(name, pms_property_id)",
|
||||
"you cannot have more than one room "
|
||||
"with the same name in the same property",
|
||||
)
|
||||
]
|
||||
|
||||
@api.depends("child_ids")
|
||||
def _compute_is_shared_room(self):
|
||||
for record in self:
|
||||
if record.child_ids:
|
||||
record.is_shared_room = True
|
||||
elif not record.is_shared_room:
|
||||
record.is_shared_room = False
|
||||
|
||||
def name_get(self):
|
||||
result = []
|
||||
for room in self:
|
||||
name = room.name
|
||||
if room.room_type_id:
|
||||
name += " [%s]" % room.room_type_id.default_code
|
||||
if room.room_amenity_ids:
|
||||
for amenity in room.room_amenity_ids:
|
||||
if amenity.is_add_code_room_name:
|
||||
name += " %s" % amenity.default_code
|
||||
result.append((room.id, name))
|
||||
return result
|
||||
|
||||
# Constraints and onchanges
|
||||
@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."
|
||||
)
|
||||
)
|
||||
|
||||
@api.constrains("is_shared_room")
|
||||
def _check_shared_room(self):
|
||||
for record in self:
|
||||
if record.is_shared_room and not record.child_ids:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"The reservation units are required \
|
||||
on shared rooms."
|
||||
)
|
||||
)
|
||||
|
||||
@api.model
|
||||
def _check_adults(self, reservation, service_line_ids=False):
|
||||
for line in reservation.reservation_line_ids:
|
||||
num_extra_beds = 0
|
||||
if service_line_ids:
|
||||
extra_beds = service_line_ids.filtered(
|
||||
lambda x: x.date == line.date and x.product_id.is_extra_bed is True
|
||||
)
|
||||
num_extra_beds = sum(extra_beds.mapped("day_qty")) if extra_beds else 0
|
||||
if line.room_id:
|
||||
if (
|
||||
reservation.adults + reservation.children_occupying
|
||||
) > line.room_id.get_capacity(num_extra_beds):
|
||||
raise ValidationError(
|
||||
_(
|
||||
"Persons can't be higher than room capacity (%s)",
|
||||
reservation.name,
|
||||
)
|
||||
)
|
||||
|
||||
# Business methods
|
||||
|
||||
def get_capacity(self, extra_bed=0):
|
||||
for record in self:
|
||||
if extra_bed > record.extra_beds_allowed:
|
||||
raise ValidationError(
|
||||
_("Extra beds can't be greater than allowed beds for this room")
|
||||
)
|
||||
return record.capacity + extra_bed
|
||||
@@ -1,30 +0,0 @@
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class RoomClosureReason(models.Model):
|
||||
_name = "room.closure.reason"
|
||||
_description = "Cause of out of service"
|
||||
|
||||
name = fields.Char(
|
||||
string="Name",
|
||||
help="The name that identifies the room closure reason",
|
||||
required=True,
|
||||
translate=True,
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
relation="pms_room_closure_reason_pms_property_rel",
|
||||
column1="room_closure_reason_type_id",
|
||||
column2="pms_property_id",
|
||||
ondelete="restrict",
|
||||
)
|
||||
description = fields.Text(
|
||||
string="Description",
|
||||
help="Explanation of the reason for closing a room",
|
||||
translate=True,
|
||||
)
|
||||
@@ -1,207 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# Copyright 2021 Eric Antones <eantones@nuobit.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class PmsRoomType(models.Model):
|
||||
"""Before creating a 'room type', you need to consider the following:
|
||||
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"}
|
||||
_order = "sequence,default_code,name"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
sequence = fields.Integer(
|
||||
string="Sequence",
|
||||
help="Field used to change the position of the room types in tree view.",
|
||||
default=0,
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
string="Product Room Type",
|
||||
help="Product identifier associated with room type",
|
||||
comodel_name="product.product",
|
||||
required=True,
|
||||
delegate=True,
|
||||
ondelete="cascade",
|
||||
)
|
||||
room_ids = fields.One2many(
|
||||
string="Rooms",
|
||||
help="Rooms that belong to room type.",
|
||||
comodel_name="pms.room",
|
||||
inverse_name="room_type_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
class_id = fields.Many2one(
|
||||
string="Property Type Class",
|
||||
help="Class to which the room type belongs",
|
||||
comodel_name="pms.room.type.class",
|
||||
required=True,
|
||||
check_pms_properties=True,
|
||||
)
|
||||
board_service_room_type_ids = fields.One2many(
|
||||
string="Board Services",
|
||||
help="Board Service included in room type",
|
||||
comodel_name="pms.board.service.room.type",
|
||||
inverse_name="pms_room_type_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
room_amenity_ids = fields.Many2many(
|
||||
string="Room Type Amenities",
|
||||
help="List of amenities included in room type",
|
||||
comodel_name="pms.amenity",
|
||||
relation="pms_room_type_amenity_rel",
|
||||
column1="room_type_id",
|
||||
column2="amenity_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
default_code = fields.Char(
|
||||
string="Code",
|
||||
help="Identification code for a room type",
|
||||
required=True,
|
||||
)
|
||||
total_rooms_count = fields.Integer(
|
||||
string="Total Rooms Count",
|
||||
help="The number of rooms in a room type",
|
||||
compute="_compute_total_rooms_count",
|
||||
store=True,
|
||||
)
|
||||
default_max_avail = fields.Integer(
|
||||
string="Default Max. Availability",
|
||||
help="Maximum simultaneous availability on own Booking Engine "
|
||||
"given no availability rules. "
|
||||
"Use `-1` for using maximum simultaneous availability.",
|
||||
default=-1,
|
||||
)
|
||||
default_quota = fields.Integer(
|
||||
string="Default Quota",
|
||||
help="Quota assigned to the own Booking Engine given no availability rules. "
|
||||
"Use `-1` for managing no quota.",
|
||||
default=-1,
|
||||
)
|
||||
overnight_room = fields.Boolean(
|
||||
related="class_id.overnight",
|
||||
store=True,
|
||||
)
|
||||
|
||||
def name_get(self):
|
||||
result = []
|
||||
for room_type in self:
|
||||
name = room_type.name
|
||||
if self._context.get("checkin") and self._context.get("checkout"):
|
||||
pms_property = self.env["pms.property"].browse(
|
||||
self._context.get("pms_property_id")
|
||||
)
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=self._context.get("checkin"),
|
||||
checkout=self._context.get("checkout"),
|
||||
room_type_id=room_type.id,
|
||||
pricelist_id=self._context.get("pricelist_id") or False,
|
||||
)
|
||||
avail = pms_property.availability
|
||||
name += " (%s)" % avail
|
||||
result.append((room_type.id, name))
|
||||
return result
|
||||
|
||||
@api.depends("room_ids", "room_ids.active")
|
||||
def _compute_total_rooms_count(self):
|
||||
for record in self:
|
||||
record.total_rooms_count = len(record.room_ids)
|
||||
|
||||
@api.model
|
||||
def get_room_types_by_property(self, pms_property_id, default_code=None):
|
||||
"""
|
||||
:param pms_property_id: property ID
|
||||
:param default_code: room type code (optional)
|
||||
:return: - recordset of
|
||||
- all the pms.room.type of the pms_property_id
|
||||
if default_code not defined
|
||||
- one or 0 pms.room.type if default_code defined
|
||||
- ValidationError if more than one default_code found by
|
||||
the same pms_property_id
|
||||
"""
|
||||
domain = []
|
||||
if default_code:
|
||||
domain += ["&", ("default_code", "=", default_code)]
|
||||
company_id = self.env["pms.property"].browse(pms_property_id).company_id.id
|
||||
domain += [
|
||||
"|",
|
||||
("pms_property_ids", "in", pms_property_id),
|
||||
"|",
|
||||
"&",
|
||||
("pms_property_ids", "=", False),
|
||||
("company_id", "=", company_id),
|
||||
"&",
|
||||
("pms_property_ids", "=", False),
|
||||
("company_id", "=", False),
|
||||
]
|
||||
records = self.search(domain)
|
||||
res, res_priority = {}, {}
|
||||
for rec in records:
|
||||
res_priority.setdefault(rec.default_code, -1)
|
||||
priority = (rec.pms_property_ids and 2) or (rec.company_id and 1 or 0)
|
||||
if priority > res_priority[rec.default_code]:
|
||||
res.setdefault(rec.default_code, rec.id)
|
||||
res[rec.default_code], res_priority[rec.default_code] = rec.id, priority
|
||||
elif priority == res_priority[rec.default_code]:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"Integrity error: There's multiple room types "
|
||||
"with the same code %s and properties"
|
||||
)
|
||||
% rec.default_code
|
||||
)
|
||||
return self.browse(list(res.values()))
|
||||
|
||||
@api.constrains("default_code", "pms_property_ids", "company_id")
|
||||
def _check_code_property_company_uniqueness(self):
|
||||
msg = _("Already exists another room type with the same code and properties")
|
||||
for rec in self:
|
||||
if not rec.pms_property_ids:
|
||||
if self.search(
|
||||
[
|
||||
("id", "!=", rec.id),
|
||||
("default_code", "=", rec.default_code),
|
||||
("pms_property_ids", "=", False),
|
||||
("company_id", "=", rec.company_id.id),
|
||||
]
|
||||
):
|
||||
raise ValidationError(msg)
|
||||
else:
|
||||
for pms_property in rec.pms_property_ids:
|
||||
other = rec.get_room_types_by_property(
|
||||
pms_property.id, rec.default_code
|
||||
)
|
||||
if other and other != rec:
|
||||
raise ValidationError(msg)
|
||||
|
||||
# ORM Overrides
|
||||
# TODO: Review Check product fields default values to room
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
""" Add room types as not purchase services. """
|
||||
vals.update(
|
||||
{
|
||||
"purchase_ok": False,
|
||||
"sale_ok": False,
|
||||
"type": "service",
|
||||
}
|
||||
)
|
||||
return super().create(vals)
|
||||
|
||||
# def unlink(self):
|
||||
# for record in self:
|
||||
# record.product_id.unlink()
|
||||
# return super().unlink()
|
||||
|
||||
def get_capacity(self):
|
||||
self.ensure_one()
|
||||
capacities = self.room_ids.mapped("capacity")
|
||||
return min(capacities) if any(capacities) else 0
|
||||
@@ -1,127 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# Copyright 2021 Eric Antones <eantones@nuobit.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class PmsRoomTypeClass(models.Model):
|
||||
"""Before creating a 'room type_class', you need to consider the following:
|
||||
With the term 'room type class' is meant a physical class of
|
||||
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, default_code"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
name = fields.Char(
|
||||
string="Class Name",
|
||||
help="Name of the room type class",
|
||||
required=True,
|
||||
translate=True,
|
||||
)
|
||||
active = fields.Boolean(
|
||||
string="Active",
|
||||
help="If unchecked, it will allow you to hide the room type",
|
||||
default=True,
|
||||
)
|
||||
sequence = fields.Integer(
|
||||
string="Sequence",
|
||||
help="Field used to change the position of the room type classes in tree view.",
|
||||
default=0,
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
relation="pms_room_type_class_property_rel",
|
||||
column1="room_type_class_id",
|
||||
column2="pms_property_id",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
room_type_ids = fields.One2many(
|
||||
string="Types",
|
||||
help="Room Types that belong to this Room Type Class",
|
||||
comodel_name="pms.room.type",
|
||||
inverse_name="class_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
default_code = fields.Char(
|
||||
string="Code",
|
||||
help="Room type class identification code",
|
||||
required=True,
|
||||
)
|
||||
overnight = fields.Boolean(
|
||||
string="Use for overnight stays",
|
||||
help="Set False if if these types of spaces are not used for overnight stays",
|
||||
default=True,
|
||||
)
|
||||
|
||||
@api.model
|
||||
def get_unique_by_property_code(self, pms_property_id, default_code=None):
|
||||
"""
|
||||
:param pms_property_id: property ID
|
||||
:param default_code: room type code (optional)
|
||||
:return: - recordset of
|
||||
- all the pms.room.type.class of the pms_property_id
|
||||
if default_code not defined
|
||||
- one or 0 pms.room.type.class if default_code defined
|
||||
- ValidationError if more than one default_code found by
|
||||
the same pms_property_id
|
||||
"""
|
||||
# TODO: similiar code as room.type -> unify
|
||||
domain = []
|
||||
if default_code:
|
||||
domain += ["&", ("default_code", "=", default_code)]
|
||||
domain += [
|
||||
"|",
|
||||
("pms_property_ids", "in", pms_property_id),
|
||||
("pms_property_ids", "=", False),
|
||||
]
|
||||
records = self.search(domain)
|
||||
res, res_priority = {}, {}
|
||||
for rec in records:
|
||||
res_priority.setdefault(rec.default_code, -1)
|
||||
priority = rec.pms_property_ids and 1 or 0
|
||||
if priority > res_priority[rec.default_code]:
|
||||
res.setdefault(rec.default_code, rec.id)
|
||||
res[rec.default_code], res_priority[rec.default_code] = rec.id, priority
|
||||
elif priority == res_priority[rec.default_code]:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"Integrity error: There's multiple room types "
|
||||
"with the same code %s and properties"
|
||||
)
|
||||
% rec.default_code
|
||||
)
|
||||
return self.browse(list(res.values()))
|
||||
|
||||
@api.constrains("default_code", "pms_property_ids")
|
||||
def _check_code_property_uniqueness(self):
|
||||
# TODO: similiar code as room.type -> unify
|
||||
msg = _(
|
||||
"Already exists another room type class with the same code and properties"
|
||||
)
|
||||
for rec in self:
|
||||
if not rec.pms_property_ids:
|
||||
if self.search(
|
||||
[
|
||||
("id", "!=", rec.id),
|
||||
("default_code", "=", rec.default_code),
|
||||
("pms_property_ids", "=", False),
|
||||
]
|
||||
):
|
||||
raise ValidationError(msg)
|
||||
else:
|
||||
for pms_property in rec.pms_property_ids:
|
||||
other = rec.get_unique_by_property_code(
|
||||
pms_property.id, rec.default_code
|
||||
)
|
||||
if other and other != rec:
|
||||
raise ValidationError(msg)
|
||||
@@ -1,40 +0,0 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class PmsSaleChannel(models.Model):
|
||||
_name = "pms.sale.channel"
|
||||
_description = "Sales Channel"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
name = fields.Text(string="Sale Channel Name", help="The name of the sale channel")
|
||||
channel_type = fields.Selection(
|
||||
string="Sale Channel Type",
|
||||
help="Type of sale channel; it can be 'direct'(if there is"
|
||||
"no intermediary) or 'indirect'(if there are"
|
||||
"intermediaries between partner and property",
|
||||
selection=[("direct", "Direct"), ("indirect", "Indirect")],
|
||||
)
|
||||
is_on_line = fields.Boolean(
|
||||
string="On Line", help="Indicates if the sale channel is on-line"
|
||||
)
|
||||
product_pricelist_ids = fields.Many2many(
|
||||
string="Pricelists",
|
||||
help="Pricelists for a sale channel",
|
||||
comodel_name="product.pricelist",
|
||||
relation="pms_sale_channel_product_pricelist_rel",
|
||||
column1="pms_sale_channel_id",
|
||||
column2="product_pricelist_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
required=False,
|
||||
ondelete="restrict",
|
||||
comodel_name="pms.property",
|
||||
relation="pms_sale_channel_pms_property_rel",
|
||||
column1="pms_sale_channel_id",
|
||||
column2="pms_property_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
@@ -1,590 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PmsService(models.Model):
|
||||
_name = "pms.service"
|
||||
_description = "Services and its charges"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
name = fields.Char(
|
||||
string="Service description",
|
||||
help="Service description",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_name",
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
string="Service",
|
||||
help="Product associated with this service",
|
||||
required=True,
|
||||
comodel_name="product.product",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
folio_id = fields.Many2one(
|
||||
string="Folio",
|
||||
help="Folio in which the service is included",
|
||||
readonly=False,
|
||||
store=True,
|
||||
comodel_name="pms.folio",
|
||||
compute="_compute_folio_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
sale_line_ids = fields.One2many(
|
||||
string="Sale Lines",
|
||||
help="",
|
||||
copy=False,
|
||||
comodel_name="folio.sale.line",
|
||||
inverse_name="service_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
reservation_id = fields.Many2one(
|
||||
string="Room",
|
||||
help="Reservation in which the service is included",
|
||||
default=lambda self: self._default_reservation_id(),
|
||||
comodel_name="pms.reservation",
|
||||
ondelete="cascade",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
service_line_ids = fields.One2many(
|
||||
string="Service Lines",
|
||||
help="Subservices included in this service",
|
||||
readonly=False,
|
||||
store=True,
|
||||
comodel_name="pms.service.line",
|
||||
inverse_name="service_id",
|
||||
compute="_compute_service_line_ids",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
string="Company",
|
||||
help="Company to which the service belongs",
|
||||
readonly=True,
|
||||
store=True,
|
||||
related="folio_id.company_id",
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Property to which the service belongs",
|
||||
readonly=True,
|
||||
store=True,
|
||||
comodel_name="pms.property",
|
||||
related="folio_id.pms_property_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
tax_ids = fields.Many2many(
|
||||
string="Taxes",
|
||||
help="Taxes applied in the service",
|
||||
readonly=False,
|
||||
store=True,
|
||||
comodel_name="account.tax",
|
||||
domain=["|", ("active", "=", False), ("active", "=", True)],
|
||||
compute="_compute_tax_ids",
|
||||
)
|
||||
analytic_tag_ids = fields.Many2many(
|
||||
string="Analytic Tags",
|
||||
help="",
|
||||
comodel_name="account.analytic.tag",
|
||||
)
|
||||
currency_id = fields.Many2one(
|
||||
string="Currency",
|
||||
help="The currency used in relation to the folio",
|
||||
readonly=True,
|
||||
store=True,
|
||||
related="folio_id.currency_id",
|
||||
)
|
||||
sequence = fields.Integer(string="Sequence", help="", default=10)
|
||||
state = fields.Selection(
|
||||
string="State",
|
||||
help="Service status, it corresponds with folio status",
|
||||
related="folio_id.state",
|
||||
)
|
||||
per_day = fields.Boolean(
|
||||
string="Per Day",
|
||||
help="Indicates if service is sold by days",
|
||||
related="product_id.per_day",
|
||||
related_sudo=True,
|
||||
)
|
||||
product_qty = fields.Integer(
|
||||
string="Quantity",
|
||||
help="Number of services that were sold",
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_product_qty",
|
||||
)
|
||||
is_board_service = fields.Boolean(
|
||||
string="Is Board Service",
|
||||
help="Indicates if the service is part of a board service",
|
||||
)
|
||||
# Non-stored related field to allow portal user to
|
||||
# see the image of the product he has ordered
|
||||
product_image = fields.Binary(
|
||||
string="Product Image",
|
||||
help="Image of the service",
|
||||
store=False,
|
||||
related="product_id.image_1024",
|
||||
related_sudo=True,
|
||||
)
|
||||
invoice_status = fields.Selection(
|
||||
string="Invoice Status",
|
||||
help="State in which the service is with respect to invoices."
|
||||
"It can be 'invoiced', 'to_invoice' or 'no'",
|
||||
readonly=True,
|
||||
default="no",
|
||||
store=True,
|
||||
compute="_compute_invoice_status",
|
||||
selection=[
|
||||
("invoiced", "Fully Invoiced"),
|
||||
("to_invoice", "To Invoice"),
|
||||
("no", "Nothing to Invoice"),
|
||||
],
|
||||
)
|
||||
channel_type = fields.Selection(
|
||||
string="Sales Channel",
|
||||
help="sales channel through which the service was sold."
|
||||
"It can be 'door', 'mail', 'phone', 'call' or 'web'",
|
||||
selection=[
|
||||
("door", "Door"),
|
||||
("mail", "Mail"),
|
||||
("phone", "Phone"),
|
||||
("call", "Call Center"),
|
||||
("web", "Web"),
|
||||
],
|
||||
)
|
||||
price_subtotal = fields.Monetary(
|
||||
string="Subtotal",
|
||||
help="Subtotal price without taxes",
|
||||
readonly=True,
|
||||
store=True,
|
||||
compute="_compute_amount_service",
|
||||
)
|
||||
price_total = fields.Monetary(
|
||||
string="Total",
|
||||
help="Total price with taxes",
|
||||
readonly=True,
|
||||
store=True,
|
||||
compute="_compute_amount_service",
|
||||
)
|
||||
price_tax = fields.Float(
|
||||
string="Taxes Amount",
|
||||
help="Total of taxes in service",
|
||||
readonly=True,
|
||||
store=True,
|
||||
compute="_compute_amount_service",
|
||||
)
|
||||
|
||||
discount = fields.Float(
|
||||
string="Discount (€)",
|
||||
help="Discount of total price",
|
||||
readonly=False,
|
||||
store=True,
|
||||
digits=("Discount"),
|
||||
compute="_compute_discount",
|
||||
)
|
||||
|
||||
# Compute and Search methods
|
||||
@api.depends("product_id")
|
||||
def _compute_tax_ids(self):
|
||||
for service in self:
|
||||
service.tax_ids = service.product_id.taxes_id.filtered(
|
||||
lambda r: not service.company_id or r.company_id == service.company_id
|
||||
)
|
||||
|
||||
@api.depends("service_line_ids", "service_line_ids.day_qty")
|
||||
def _compute_product_qty(self):
|
||||
self.product_qty = 0
|
||||
for service in self.filtered("service_line_ids"):
|
||||
qty = sum(service.service_line_ids.mapped("day_qty"))
|
||||
service.product_qty = qty
|
||||
|
||||
@api.depends("reservation_id", "reservation_id.folio_id")
|
||||
def _compute_folio_id(self):
|
||||
for record in self:
|
||||
if record.reservation_id:
|
||||
record.folio_id = record.reservation_id.folio_id
|
||||
elif not record.folio_id:
|
||||
record.folio_id = False
|
||||
|
||||
@api.depends(
|
||||
"sale_line_ids",
|
||||
"sale_line_ids.invoice_status",
|
||||
)
|
||||
def _compute_invoice_status(self):
|
||||
"""
|
||||
Compute the invoice status of a Reservation. Possible statuses:
|
||||
Base on folio sale line invoice status
|
||||
"""
|
||||
for line in self:
|
||||
states = list(set(line.sale_line_ids.mapped("invoice_status")))
|
||||
if len(states) == 1:
|
||||
line.invoice_status = states[0]
|
||||
elif len(states) >= 1:
|
||||
if "to_invoice" in states:
|
||||
line.invoice_status = "to_invoice"
|
||||
elif "invoiced" in states:
|
||||
line.invoice_status = "invoiced"
|
||||
else:
|
||||
line.invoice_status = "no"
|
||||
else:
|
||||
line.invoice_status = "no"
|
||||
|
||||
@api.depends("service_line_ids.price_day_total")
|
||||
def _compute_amount_service(self):
|
||||
for service in self:
|
||||
if service.service_line_ids:
|
||||
service.update(
|
||||
{
|
||||
"price_tax": sum(
|
||||
service.service_line_ids.mapped("price_day_tax")
|
||||
),
|
||||
"price_total": sum(
|
||||
service.service_line_ids.mapped("price_day_total")
|
||||
),
|
||||
"price_subtotal": sum(
|
||||
service.service_line_ids.mapped("price_day_subtotal")
|
||||
),
|
||||
}
|
||||
)
|
||||
else:
|
||||
service.update(
|
||||
{
|
||||
"price_tax": 0,
|
||||
"price_total": 0,
|
||||
"price_subtotal": 0,
|
||||
}
|
||||
)
|
||||
|
||||
@api.depends("product_id")
|
||||
def _compute_name(self):
|
||||
self.name = False
|
||||
for service in self.filtered("product_id"):
|
||||
product = service.product_id.with_context(
|
||||
lang=service.folio_id.partner_id.lang,
|
||||
partner=service.folio_id.partner_id.id,
|
||||
)
|
||||
title = False
|
||||
message = False
|
||||
warning = {}
|
||||
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":
|
||||
self.product_id = False
|
||||
return result
|
||||
name = product.name_get()[0][1]
|
||||
if product.description_sale:
|
||||
name += "\n" + product.description_sale
|
||||
service.name = name
|
||||
|
||||
@api.depends(
|
||||
"reservation_id.checkin",
|
||||
"reservation_id.checkout",
|
||||
"product_id",
|
||||
"reservation_id.adults",
|
||||
)
|
||||
def _compute_service_line_ids(self):
|
||||
for service in self:
|
||||
if service.product_id:
|
||||
day_qty = 1
|
||||
if service.reservation_id and service.product_id:
|
||||
reservation = service.reservation_id
|
||||
# REVIEW: review method dependencies, reservation_line_ids
|
||||
# instead of checkin/checkout
|
||||
if not reservation.checkin or not reservation.checkout:
|
||||
if not service.service_line_ids:
|
||||
service.service_line_ids = False
|
||||
continue
|
||||
product = service.product_id
|
||||
consumed_on = product.consumed_on
|
||||
if product.per_day:
|
||||
lines = []
|
||||
day_qty = service._service_day_qty()
|
||||
days_diff = (reservation.checkout - reservation.checkin).days
|
||||
for i in range(0, days_diff):
|
||||
if consumed_on == "after":
|
||||
i += 1
|
||||
idate = reservation.checkin + timedelta(days=i)
|
||||
old_line = service.service_line_ids.filtered(
|
||||
lambda r: r.date == idate
|
||||
)
|
||||
price_unit = service._get_price_unit_line(idate)
|
||||
if old_line and old_line.auto_qty:
|
||||
lines.append(
|
||||
(
|
||||
1,
|
||||
old_line.id,
|
||||
{
|
||||
"day_qty": day_qty,
|
||||
"auto_qty": True,
|
||||
},
|
||||
)
|
||||
)
|
||||
elif not old_line:
|
||||
lines.append(
|
||||
(
|
||||
0,
|
||||
False,
|
||||
{
|
||||
"date": idate,
|
||||
"day_qty": day_qty,
|
||||
"auto_qty": True,
|
||||
"price_unit": price_unit,
|
||||
},
|
||||
)
|
||||
)
|
||||
move_day = 0
|
||||
if consumed_on == "after":
|
||||
move_day = 1
|
||||
for del_service_id in service.service_line_ids.filtered_domain(
|
||||
[
|
||||
"|",
|
||||
(
|
||||
"date",
|
||||
"<",
|
||||
reservation.checkin + timedelta(move_day),
|
||||
),
|
||||
(
|
||||
"date",
|
||||
">=",
|
||||
reservation.checkout + timedelta(move_day),
|
||||
),
|
||||
]
|
||||
).ids:
|
||||
lines.append((2, del_service_id))
|
||||
# TODO: check intermediate states in check_adults restriction
|
||||
# when lines are removed
|
||||
service.service_line_ids = lines
|
||||
else:
|
||||
if not service.service_line_ids:
|
||||
price_unit = service._get_price_unit_line()
|
||||
service.service_line_ids = [
|
||||
(
|
||||
0,
|
||||
False,
|
||||
{
|
||||
"date": fields.Date.today(),
|
||||
"day_qty": day_qty,
|
||||
"price_unit": price_unit,
|
||||
},
|
||||
)
|
||||
]
|
||||
else:
|
||||
if not service.service_line_ids:
|
||||
price_unit = service._get_price_unit_line()
|
||||
service.service_line_ids = [
|
||||
(
|
||||
0,
|
||||
False,
|
||||
{
|
||||
"date": fields.Date.today(),
|
||||
"day_qty": day_qty,
|
||||
"price_unit": price_unit,
|
||||
},
|
||||
)
|
||||
]
|
||||
else:
|
||||
service.service_line_ids = False
|
||||
|
||||
@api.depends("service_line_ids.cancel_discount")
|
||||
def _compute_discount(self):
|
||||
for record in self:
|
||||
discount = 0
|
||||
for line in record.service_line_ids:
|
||||
first_discount = line.price_day_total * ((line.discount or 0.0) * 0.01)
|
||||
price = line.price_day_total - first_discount
|
||||
cancel_discount = price * ((line.cancel_discount or 0.0) * 0.01)
|
||||
discount += first_discount + cancel_discount
|
||||
record.discount = discount
|
||||
|
||||
def name_get(self):
|
||||
result = []
|
||||
for rec in self:
|
||||
name = []
|
||||
name.append("{name}".format(name=rec.name))
|
||||
if 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")
|
||||
return False
|
||||
|
||||
# Action methods
|
||||
def open_service_ids(self):
|
||||
action = self.env.ref("pms.action_pms_services_form").sudo().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):
|
||||
if args is None:
|
||||
args = []
|
||||
if not (name == "" and operator == "ilike"):
|
||||
args += [
|
||||
"|",
|
||||
("reservation_id.name", operator, name),
|
||||
("name", operator, name),
|
||||
]
|
||||
return super(PmsService, self).name_search(
|
||||
name="", args=args, operator="ilike", limit=limit
|
||||
)
|
||||
|
||||
def _get_display_price(self, product):
|
||||
folio = self.folio_id
|
||||
reservation = self.reservation_id
|
||||
origin = folio if folio else reservation
|
||||
if origin.pricelist_id.discount_policy == "with_discount":
|
||||
return product.price
|
||||
final_price, rule_id = origin.pricelist_id.with_context(
|
||||
product._context
|
||||
).get_product_price_rule(product, 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,
|
||||
)
|
||||
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)
|
||||
)
|
||||
# negative discounts (= surcharge) are included in the display price
|
||||
return max(base_price, final_price)
|
||||
|
||||
def _get_real_price_currency(self, product, rule_id, qty, uom, pricelist_id):
|
||||
"""Retrieve the price before applying the pricelist
|
||||
:param obj product: object of current product record
|
||||
:parem float qty: total quantity of product
|
||||
:param tuple price_and_rule: tuple(price, suitable_rule)
|
||||
coming from pricelist computation
|
||||
:param obj uom: unit of measure of current order line
|
||||
:param integer pricelist_id: pricelist id of sales order"""
|
||||
PricelistItem = self.env["product.pricelist.item"]
|
||||
field_name = "lst_price"
|
||||
currency_id = None
|
||||
product_currency = product.currency_id
|
||||
if rule_id:
|
||||
pricelist_item = PricelistItem.browse(rule_id)
|
||||
if pricelist_item.pricelist_id.discount_policy == "without_discount":
|
||||
while (
|
||||
pricelist_item.base == "pricelist"
|
||||
and pricelist_item.base_pricelist_id
|
||||
and pricelist_item.base_pricelist_id.discount_policy
|
||||
== "without_discount"
|
||||
):
|
||||
price, rule_id = pricelist_item.base_pricelist_id.with_context(
|
||||
uom=uom.id
|
||||
).get_product_price_rule(product, qty, self.order_id.partner_id)
|
||||
pricelist_item = PricelistItem.browse(rule_id)
|
||||
|
||||
if pricelist_item.base == "standard_price":
|
||||
field_name = "standard_price"
|
||||
product_currency = product.cost_currency_id
|
||||
elif (
|
||||
pricelist_item.base == "pricelist" and pricelist_item.base_pricelist_id
|
||||
):
|
||||
field_name = "price"
|
||||
product = product.with_context(
|
||||
pricelist=pricelist_item.base_pricelist_id.id
|
||||
)
|
||||
product_currency = pricelist_item.base_pricelist_id.currency_id
|
||||
currency_id = pricelist_item.pricelist_id.currency_id
|
||||
|
||||
if not currency_id:
|
||||
currency_id = product_currency
|
||||
cur_factor = 1.0
|
||||
else:
|
||||
if currency_id.id == product_currency.id:
|
||||
cur_factor = 1.0
|
||||
else:
|
||||
cur_factor = currency_id._get_conversion_rate(
|
||||
product_currency,
|
||||
currency_id,
|
||||
self.company_id or self.env.company,
|
||||
self.folio_id.date_order or fields.Date.today(),
|
||||
)
|
||||
|
||||
product_uom = self.env.context.get("uom") or product.uom_id.id
|
||||
if uom and uom.id != product_uom:
|
||||
# the unit price is in a different uom
|
||||
uom_factor = uom._compute_price(1.0, product.uom_id)
|
||||
else:
|
||||
uom_factor = 1.0
|
||||
|
||||
return product[field_name] * uom_factor * cur_factor, currency_id
|
||||
|
||||
# Businness Methods
|
||||
def _service_day_qty(self):
|
||||
self.ensure_one()
|
||||
qty = self.product_qty if len(self.service_line_ids) == 1 else 1
|
||||
if not self.reservation_id:
|
||||
return qty
|
||||
# TODO: Pass per_person to service line from product default_per_person
|
||||
# When the user modifies the quantity avoid overwriting
|
||||
if self.product_id.per_person:
|
||||
qty = self.reservation_id.adults
|
||||
return qty
|
||||
|
||||
def _get_price_unit_line(self, date=False):
|
||||
self.ensure_one()
|
||||
if self.reservation_id.reservation_type == "normal":
|
||||
folio = self.folio_id
|
||||
reservation = self.reservation_id
|
||||
origin = reservation if reservation else folio
|
||||
if origin:
|
||||
partner = origin.partner_id
|
||||
pricelist = origin.pricelist_id
|
||||
board_room_type = False
|
||||
product_context = dict(
|
||||
self.env.context,
|
||||
lang=partner.lang,
|
||||
partner=partner.id,
|
||||
quantity=self.product_qty,
|
||||
date=folio.date_order if folio else fields.Date.today(),
|
||||
pricelist=pricelist.id,
|
||||
board_service=board_room_type.id if board_room_type else False,
|
||||
uom=self.product_id.uom_id.id,
|
||||
fiscal_position=False,
|
||||
property=self.reservation_id.pms_property_id.id,
|
||||
)
|
||||
if date:
|
||||
product_context["consumption_date"] = date
|
||||
if reservation and self.is_board_service:
|
||||
product_context[
|
||||
"board_service"
|
||||
] = reservation.board_service_room_id.id
|
||||
product = self.product_id.with_context(product_context)
|
||||
return self.env["account.tax"]._fix_tax_included_price_company(
|
||||
self._get_display_price(product),
|
||||
product.taxes_id,
|
||||
self.tax_ids,
|
||||
origin.company_id,
|
||||
)
|
||||
else:
|
||||
return 0
|
||||
@@ -1,249 +0,0 @@
|
||||
# Copyright 2017-2018 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import datetime
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class PmsServiceLine(models.Model):
|
||||
_name = "pms.service.line"
|
||||
_description = "Service by day"
|
||||
_order = "date"
|
||||
_rec_name = "service_id"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
service_id = fields.Many2one(
|
||||
string="Service Room",
|
||||
help="Service identifier",
|
||||
required=True,
|
||||
copy=False,
|
||||
comodel_name="pms.service",
|
||||
ondelete="cascade",
|
||||
)
|
||||
is_board_service = fields.Boolean(
|
||||
string="Is Board Service",
|
||||
help="Indicates if the service line is part of a board service",
|
||||
store=True,
|
||||
related="service_id.is_board_service",
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
string="Product",
|
||||
help="Product associated with this service line",
|
||||
store=True,
|
||||
related="service_id.product_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
tax_ids = fields.Many2many(
|
||||
string="Taxes",
|
||||
help="Taxes applied in the service line",
|
||||
readonly="True",
|
||||
comodel_name="account.tax",
|
||||
related="service_id.tax_ids",
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Property to which the service belongs",
|
||||
readonly=True,
|
||||
store=True,
|
||||
comodel_name="pms.property",
|
||||
related="service_id.pms_property_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
date = fields.Date(
|
||||
string="Date",
|
||||
help="Sate on which the product is to be consumed",
|
||||
)
|
||||
day_qty = fields.Integer(
|
||||
string="Units",
|
||||
help="Amount to be consumed per day",
|
||||
)
|
||||
price_unit = fields.Float(
|
||||
string="Unit Price",
|
||||
help="Price per unit of service",
|
||||
digits=("Product Price"),
|
||||
)
|
||||
price_day_subtotal = fields.Monetary(
|
||||
string="Subtotal",
|
||||
help="Subtotal price without taxes",
|
||||
readonly=True,
|
||||
store=True,
|
||||
compute="_compute_day_amount_service",
|
||||
)
|
||||
price_day_total = fields.Monetary(
|
||||
string="Total",
|
||||
help="Total price with taxes",
|
||||
readonly=True,
|
||||
store=True,
|
||||
compute="_compute_day_amount_service",
|
||||
)
|
||||
price_day_tax = fields.Float(
|
||||
string="Taxes Amount",
|
||||
help="",
|
||||
readonly=True,
|
||||
store=True,
|
||||
compute="_compute_day_amount_service",
|
||||
)
|
||||
currency_id = fields.Many2one(
|
||||
string="Currency",
|
||||
help="The currency used in relation to the service where it's included",
|
||||
readonly=True,
|
||||
store=True,
|
||||
related="service_id.currency_id",
|
||||
)
|
||||
reservation_id = fields.Many2one(
|
||||
string="Reservation",
|
||||
help="Room to which the services will be applied",
|
||||
readonly=True,
|
||||
store=True,
|
||||
related="service_id.reservation_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
discount = fields.Float(
|
||||
string="Discount (%)",
|
||||
help="Discount in the price of the service.",
|
||||
readonly=False,
|
||||
store=True,
|
||||
default=0.0,
|
||||
digits=("Discount"),
|
||||
compute="_compute_discount",
|
||||
)
|
||||
cancel_discount = fields.Float(
|
||||
string="Cancelation Discount",
|
||||
help="",
|
||||
compute="_compute_cancel_discount",
|
||||
readonly=True,
|
||||
store=True,
|
||||
)
|
||||
auto_qty = fields.Boolean(
|
||||
string="Qty automated setted",
|
||||
help="Show if the day qty was calculated automatically",
|
||||
compute="_compute_auto_qty",
|
||||
readonly=False,
|
||||
store=True,
|
||||
)
|
||||
|
||||
@api.depends("day_qty", "discount", "price_unit", "tax_ids")
|
||||
def _compute_day_amount_service(self):
|
||||
for line in self:
|
||||
amount_service = line.price_unit
|
||||
if amount_service > 0:
|
||||
currency = line.service_id.currency_id
|
||||
product = line.product_id
|
||||
price = amount_service * (1 - (line.discount or 0.0) * 0.01)
|
||||
# REVIEW: line.day_qty is not the total qty (the total is on service_id)
|
||||
taxes = line.tax_ids.compute_all(
|
||||
price, currency, line.day_qty, product=product
|
||||
)
|
||||
line.update(
|
||||
{
|
||||
"price_day_tax": sum(
|
||||
t.get("amount", 0.0) for t in taxes.get("taxes", [])
|
||||
),
|
||||
"price_day_total": taxes["total_included"],
|
||||
"price_day_subtotal": taxes["total_excluded"],
|
||||
}
|
||||
)
|
||||
else:
|
||||
line.update(
|
||||
{
|
||||
"price_day_tax": 0,
|
||||
"price_day_total": 0,
|
||||
"price_day_subtotal": 0,
|
||||
}
|
||||
)
|
||||
|
||||
@api.depends("service_id.reservation_id", "service_id.reservation_id.discount")
|
||||
def _compute_discount(self):
|
||||
"""
|
||||
On board service the line discount is always
|
||||
equal to reservation line discount
|
||||
"""
|
||||
for record in self:
|
||||
if record.is_board_service:
|
||||
consumed_date = (
|
||||
record.date
|
||||
if record.product_id.consumed_on == "before"
|
||||
else record.date + datetime.timedelta(days=-1)
|
||||
)
|
||||
record.discount = (
|
||||
record.service_id.reservation_id.reservation_line_ids.filtered(
|
||||
lambda l: l.date == consumed_date
|
||||
).discount
|
||||
)
|
||||
elif not record.discount:
|
||||
record.discount = 0
|
||||
|
||||
# TODO: Refact method and allowed cancelled single days
|
||||
@api.depends("service_id.reservation_id.reservation_line_ids.cancel_discount")
|
||||
def _compute_cancel_discount(self):
|
||||
for line in self:
|
||||
line.cancel_discount = 0
|
||||
reservation = line.reservation_id
|
||||
if reservation.state == "cancel":
|
||||
if (
|
||||
reservation.cancelled_reason
|
||||
and reservation.pricelist_id
|
||||
and reservation.pricelist_id.cancelation_rule_id
|
||||
and reservation.reservation_line_ids.mapped("cancel_discount")
|
||||
):
|
||||
if line.is_board_service:
|
||||
consumed_date = (
|
||||
line.date
|
||||
if line.product_id.consumed_on == "before"
|
||||
else line.date + datetime.timedelta(days=-1)
|
||||
)
|
||||
line.cancel_discount = (
|
||||
reservation.reservation_line_ids.filtered(
|
||||
lambda l: l.date == consumed_date
|
||||
).cancel_discount
|
||||
)
|
||||
else:
|
||||
line.cancel_discount = 100
|
||||
else:
|
||||
line.cancel_discount = 0
|
||||
else:
|
||||
line.cancel_discount = 0
|
||||
|
||||
@api.depends("day_qty")
|
||||
def _compute_auto_qty(self):
|
||||
"""
|
||||
Set auto_qty = False if the service is no linked to room or
|
||||
if the day_qty was set manually
|
||||
(See autogeneration of service lines in
|
||||
_compute_service_line_ids -pms.service-)
|
||||
"""
|
||||
self.auto_qty = False
|
||||
|
||||
# Constraints and onchanges
|
||||
@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")
|
||||
)
|
||||
if limit < out_qty + record.day_qty:
|
||||
raise ValidationError(
|
||||
_("%s limit exceeded for %s")
|
||||
% (record.service_id.product_id.name, record.date)
|
||||
)
|
||||
|
||||
# Business methods
|
||||
def _cancel_discount(self):
|
||||
for record in self:
|
||||
if record.reservation_id:
|
||||
day = record.reservation_id.reservation_line_ids.filtered(
|
||||
lambda d: d.date == record.date
|
||||
)
|
||||
record.cancel_discount = day.cancel_discount
|
||||
@@ -1,50 +0,0 @@
|
||||
# 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 ValidationError
|
||||
|
||||
|
||||
class PmsUbication(models.Model):
|
||||
_name = "pms.ubication"
|
||||
_description = "Ubication"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
name = fields.Char(
|
||||
string="Ubication Name",
|
||||
help="Ubication Name",
|
||||
required=True,
|
||||
translate=True,
|
||||
)
|
||||
sequence = fields.Integer(
|
||||
string="Sequence",
|
||||
help="Field used to change the position of the ubications in tree view."
|
||||
"Changing the position changes the sequence",
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
relation="pms_ubication_pms_property_rel",
|
||||
column1="ubication_type_id",
|
||||
column2="pms_property_id",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_room_ids = fields.One2many(
|
||||
string="Rooms",
|
||||
help="Rooms found in this location",
|
||||
comodel_name="pms.room",
|
||||
inverse_name="ubication_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
|
||||
@api.constrains(
|
||||
"pms_property_ids",
|
||||
"pms_room_ids",
|
||||
)
|
||||
def _check_property_integrity(self):
|
||||
for rec in self:
|
||||
if rec.pms_property_ids and rec.pms_room_ids:
|
||||
if rec.pms_room_ids.pms_property_id not in rec.pms_property_ids:
|
||||
raise ValidationError(_("Property not allowed"))
|
||||
@@ -1,206 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz, Pablo Quesada, Darío Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import logging
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProductPricelist(models.Model):
|
||||
"""Before creating a 'daily' pricelist, you need to consider the following:
|
||||
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"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
# Fields declaration
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
required=False,
|
||||
comodel_name="pms.property",
|
||||
relation="product_pricelist_pms_property_rel",
|
||||
column1="product_pricelist_id",
|
||||
column2="pms_property_id",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
string="Company",
|
||||
help="Company to which the pricelist belongs",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
cancelation_rule_id = fields.Many2one(
|
||||
string="Cancelation Policy",
|
||||
help="Cancelation Policy included in the room",
|
||||
comodel_name="pms.cancelation.rule",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pricelist_type = fields.Selection(
|
||||
string="Pricelist Type",
|
||||
help="Pricelist types, it can be Daily Plan",
|
||||
default="daily",
|
||||
selection=[("daily", "Daily Plan")],
|
||||
)
|
||||
pms_sale_channel_ids = fields.Many2many(
|
||||
string="Available Channels",
|
||||
help="Sale channel for which the pricelist is included",
|
||||
comodel_name="pms.sale.channel",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
availability_plan_id = fields.Many2one(
|
||||
string="Availability Plan",
|
||||
help="Availability Plan for which the pricelist is included",
|
||||
comodel_name="pms.availability.plan",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
item_ids = fields.One2many(
|
||||
string="Items",
|
||||
help="Items for which the pricelist is made up",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
|
||||
def _compute_price_rule_get_items(
|
||||
self, products_qty_partner, date, uom_id, prod_tmpl_ids, prod_ids, categ_ids
|
||||
):
|
||||
board_service = True if self._context.get("board_service") else False
|
||||
if (
|
||||
"property" in self._context
|
||||
and self._context["property"]
|
||||
and self._context.get("consumption_date")
|
||||
):
|
||||
self.env.cr.execute(
|
||||
"""
|
||||
SELECT item.id
|
||||
FROM product_pricelist_item item
|
||||
LEFT JOIN product_category categ
|
||||
ON item.categ_id = categ.id
|
||||
LEFT JOIN product_pricelist_pms_property_rel cab
|
||||
ON item.pricelist_id = cab.product_pricelist_id
|
||||
LEFT JOIN product_pricelist_item_pms_property_rel lin
|
||||
ON item.id = lin.product_pricelist_item_id
|
||||
WHERE (lin.pms_property_id = %s OR lin.pms_property_id IS NULL)
|
||||
AND (cab.pms_property_id = %s OR cab.pms_property_id IS NULL)
|
||||
AND (item.product_tmpl_id IS NULL
|
||||
OR item.product_tmpl_id = ANY(%s))
|
||||
AND (item.product_id IS NULL OR item.product_id = ANY(%s))
|
||||
AND (item.categ_id IS NULL OR item.categ_id = ANY(%s))
|
||||
AND (item.pricelist_id = %s)
|
||||
AND (item.date_start IS NULL OR item.date_start <=%s)
|
||||
AND (item.date_end IS NULL OR item.date_end >=%s)
|
||||
AND (item.date_start_consumption IS NULL
|
||||
OR item.date_start_consumption <=%s)
|
||||
AND (item.date_end_consumption IS NULL
|
||||
OR item.date_end_consumption >=%s)
|
||||
GROUP BY item.id
|
||||
ORDER BY item.applied_on,
|
||||
/* REVIEW: priotrity date sale / date consumption */
|
||||
item.date_end - item.date_start ASC,
|
||||
item.date_end_consumption - item.date_start_consumption ASC,
|
||||
NULLIF((SELECT COUNT(1)
|
||||
FROM product_pricelist_item_pms_property_rel l
|
||||
WHERE item.id = l.product_pricelist_item_id)
|
||||
+ (SELECT COUNT(1)
|
||||
FROM product_pricelist_pms_property_rel c
|
||||
WHERE item.pricelist_id = c.product_pricelist_id),0)
|
||||
NULLS LAST,
|
||||
item.id DESC;
|
||||
""",
|
||||
(
|
||||
self._context["property"],
|
||||
self._context["property"],
|
||||
prod_tmpl_ids,
|
||||
prod_ids,
|
||||
categ_ids,
|
||||
self.id,
|
||||
date,
|
||||
date,
|
||||
self._context["consumption_date"],
|
||||
self._context["consumption_date"],
|
||||
),
|
||||
)
|
||||
item_ids = [x[0] for x in self.env.cr.fetchall()]
|
||||
items = self.env["product.pricelist.item"].browse(item_ids)
|
||||
if board_service:
|
||||
items = items.filtered(
|
||||
lambda x: x.board_service_room_type_id.id
|
||||
== self._context.get("board_service")
|
||||
)
|
||||
else:
|
||||
items = items.filtered(lambda x: not x.board_service_room_type_id.id)
|
||||
else:
|
||||
items = super(ProductPricelist, self)._compute_price_rule_get_items(
|
||||
products_qty_partner, date, uom_id, prod_tmpl_ids, prod_ids, categ_ids
|
||||
)
|
||||
return items
|
||||
|
||||
@api.constrains("pricelist_type", "item_ids", "pms_property_ids")
|
||||
def _check_pricelist_type(self):
|
||||
for record in self:
|
||||
if record.item_ids:
|
||||
for item in record.item_ids:
|
||||
if record.pricelist_type == "daily" and (
|
||||
item.compute_price != "fixed"
|
||||
or len(item.pms_property_ids) != 1
|
||||
or not item.date_end_consumption
|
||||
or not item.date_start_consumption
|
||||
or item.date_end_consumption != item.date_start_consumption
|
||||
):
|
||||
raise ValidationError(
|
||||
_(
|
||||
"Daily Plan must have fixed price, "
|
||||
"only one property and its items must be daily"
|
||||
)
|
||||
)
|
||||
|
||||
# Action methods
|
||||
# Constraints and onchanges
|
||||
# @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:
|
||||
# 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."
|
||||
# )
|
||||
# )
|
||||
|
||||
# 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."
|
||||
# )
|
||||
# )
|
||||
|
||||
def open_massive_changes_wizard(self):
|
||||
|
||||
if self.ensure_one():
|
||||
return {
|
||||
"view_type": "form",
|
||||
"view_mode": "form",
|
||||
"name": "Massive changes on Pricelist: " + self.name,
|
||||
"res_model": "pms.massive.changes.wizard",
|
||||
"target": "new",
|
||||
"type": "ir.actions.act_window",
|
||||
"context": {
|
||||
"pricelist_id": self.id,
|
||||
},
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
# 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 api, fields, models
|
||||
|
||||
|
||||
class ProductPricelistItem(models.Model):
|
||||
_inherit = "product.pricelist.item"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
relation="product_pricelist_item_pms_property_rel",
|
||||
column1="product_pricelist_item_id",
|
||||
column2="pms_property_id",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
date_start_consumption = fields.Date(
|
||||
string="Start Date Consumption",
|
||||
help="Start date to apply daily pricelist items",
|
||||
)
|
||||
date_end_consumption = fields.Date(
|
||||
string="End Date Consumption",
|
||||
help="End date to apply daily pricelist items",
|
||||
)
|
||||
board_service_room_type_id = fields.Many2one(
|
||||
string="Board Service",
|
||||
help="Specify a Board services on Room Types.",
|
||||
comodel_name="pms.board.service.room.type",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pricelist_id = fields.Many2one(
|
||||
string="Pricelist",
|
||||
help="Pricelist in which this item is included",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
string="Product",
|
||||
help="Product associated with the item",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
product_tmpl_id = fields.Many2one(
|
||||
string="Product Template",
|
||||
help="Product template associated with the item",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
allowed_board_service_product_ids = fields.Many2many(
|
||||
string="Allowed board service products",
|
||||
comodel_name="product.product",
|
||||
store=True,
|
||||
readonly=False,
|
||||
compute="_compute_allowed_board_service_product_ids",
|
||||
)
|
||||
|
||||
allowed_board_service_room_type_ids = fields.Many2many(
|
||||
string="Allowed board service room types",
|
||||
comodel_name="pms.board.service.room.type",
|
||||
store=True,
|
||||
readonly=False,
|
||||
compute="_compute_allowed_board_service_room_type_ids",
|
||||
)
|
||||
|
||||
@api.depends("board_service_room_type_id")
|
||||
def _compute_allowed_board_service_product_ids(self):
|
||||
for record in self:
|
||||
domain = []
|
||||
if record.board_service_room_type_id:
|
||||
domain.append(
|
||||
(
|
||||
"id",
|
||||
"in",
|
||||
record.board_service_room_type_id.board_service_line_ids.mapped(
|
||||
"product_id"
|
||||
).ids,
|
||||
)
|
||||
)
|
||||
allowed_board_service_product_ids = self.env["product.product"].search(
|
||||
domain
|
||||
)
|
||||
record.allowed_board_service_product_ids = allowed_board_service_product_ids
|
||||
|
||||
@api.depends("product_id")
|
||||
def _compute_allowed_board_service_room_type_ids(self):
|
||||
for record in self:
|
||||
allowed_board_service_room_type_ids = []
|
||||
all_board_service_room_type_ids = self.env[
|
||||
"pms.board.service.room.type"
|
||||
].search([])
|
||||
if record.product_id:
|
||||
for board_service_room_type_id in all_board_service_room_type_ids:
|
||||
if (
|
||||
record.product_id
|
||||
in board_service_room_type_id.board_service_line_ids.mapped(
|
||||
"product_id"
|
||||
)
|
||||
):
|
||||
allowed_board_service_room_type_ids.append(
|
||||
board_service_room_type_id.id
|
||||
)
|
||||
else:
|
||||
allowed_board_service_room_type_ids = (
|
||||
all_board_service_room_type_ids.ids
|
||||
)
|
||||
domain = []
|
||||
if allowed_board_service_room_type_ids:
|
||||
domain.append(("id", "in", allowed_board_service_room_type_ids))
|
||||
record.allowed_board_service_room_type_ids = (
|
||||
self.env["pms.board.service.room.type"].search(domain)
|
||||
if domain
|
||||
else False
|
||||
)
|
||||
@@ -1,64 +0,0 @@
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = "product.product"
|
||||
|
||||
board_price = fields.Float(
|
||||
string="Board Service Price",
|
||||
help="Get price on board service",
|
||||
digits="Product Price",
|
||||
compute="_compute_board_price",
|
||||
)
|
||||
|
||||
room_type_id = fields.Many2one(
|
||||
string="Room Type",
|
||||
comodel_name="pms.room.type",
|
||||
compute="_compute_room_type_id",
|
||||
)
|
||||
|
||||
@api.depends_context("consumption_date")
|
||||
def _compute_product_price(self):
|
||||
super(ProductProduct, self)._compute_product_price()
|
||||
|
||||
def _compute_board_price(self):
|
||||
for record in self:
|
||||
if self._context.get("board_service"):
|
||||
record.board_price = (
|
||||
self.env["pms.board.service.room.type.line"]
|
||||
.search(
|
||||
[
|
||||
(
|
||||
"pms_board_service_room_type_id",
|
||||
"=",
|
||||
self._context.get("board_service"),
|
||||
),
|
||||
("product_id", "=", record.id),
|
||||
]
|
||||
)
|
||||
.amount
|
||||
)
|
||||
else:
|
||||
record.board_price = False
|
||||
|
||||
def _compute_room_type_id(self):
|
||||
for rec in self:
|
||||
room_type = self.env["pms.room.type"].search(
|
||||
[
|
||||
("product_id", "=", rec.id),
|
||||
]
|
||||
)
|
||||
if room_type:
|
||||
if len(room_type) > 1:
|
||||
raise ValidationError(
|
||||
_("More than one room found for the same product")
|
||||
)
|
||||
rec.room_type_id = room_type
|
||||
|
||||
def price_compute(self, price_type, uom=False, currency=False, company=None):
|
||||
if self._context.get("board_service"):
|
||||
price_type = "board_price"
|
||||
return super(ProductProduct, self).price_compute(
|
||||
price_type, uom, currency, company
|
||||
)
|
||||
@@ -1,51 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = "product.template"
|
||||
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
required=False,
|
||||
comodel_name="pms.property",
|
||||
relation="product_template_pms_property_rel",
|
||||
column1="product_tmpl_id",
|
||||
column2="pms_property_id",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
check_pms_properties=True,
|
||||
)
|
||||
per_day = fields.Boolean(
|
||||
string="Unit increment per day",
|
||||
help="Indicates that the product is sold by days",
|
||||
)
|
||||
per_person = fields.Boolean(
|
||||
string="Unit increment per person",
|
||||
help="Indicates that the product is sold per person",
|
||||
)
|
||||
consumed_on = fields.Selection(
|
||||
string="Consumed",
|
||||
help="Indicates when the product is consumed",
|
||||
selection=[("before", "Before night"), ("after", "After night")],
|
||||
default="before",
|
||||
)
|
||||
daily_limit = fields.Integer(
|
||||
string="Daily limit", help="Indicates how much products can consumed in one day"
|
||||
)
|
||||
is_extra_bed = fields.Boolean(
|
||||
string="Is extra bed",
|
||||
help="Indicates if that product is a extra bed, add +1 capacity in the room",
|
||||
default=False,
|
||||
)
|
||||
is_crib = fields.Boolean(
|
||||
string="Is a baby crib",
|
||||
help="Indicates if that product is a crib",
|
||||
default=False,
|
||||
)
|
||||
@@ -1,20 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = "res.company"
|
||||
|
||||
pms_property_ids = fields.One2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element",
|
||||
comodel_name="pms.property",
|
||||
inverse_name="company_id",
|
||||
)
|
||||
|
||||
privacy_policy = fields.Text(
|
||||
string="Privacy Policy",
|
||||
help="Authorization by the user for the" "manage of their personal data",
|
||||
)
|
||||
@@ -1,403 +0,0 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import logging
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
_inherit = "res.partner"
|
||||
|
||||
reservations_count = fields.Integer(
|
||||
string="Number of Reservations",
|
||||
help="Number of reservations of the partner",
|
||||
compute="_compute_reservations_count",
|
||||
)
|
||||
folios_count = fields.Integer(
|
||||
string="Number of Folios",
|
||||
help="Number of folios of the partner",
|
||||
compute="_compute_folios_count",
|
||||
)
|
||||
is_agency = fields.Boolean(
|
||||
string="Is Agency", help="Indicates if the partner is an agency"
|
||||
)
|
||||
sale_channel_id = fields.Many2one(
|
||||
string="Sale Channel",
|
||||
help="The sale channel of the partner",
|
||||
comodel_name="pms.sale.channel",
|
||||
domain=[("channel_type", "=", "indirect")],
|
||||
ondelete="restrict",
|
||||
)
|
||||
default_commission = fields.Integer(string="Commission", help="Default commission")
|
||||
apply_pricelist = fields.Boolean(
|
||||
string="Apply Pricelist",
|
||||
help="Indicates if agency pricelist is applied to his reservations",
|
||||
)
|
||||
invoice_to_agency = fields.Boolean(
|
||||
string="Invoice Agency",
|
||||
help="Indicates if agency invoices partner",
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
required=False,
|
||||
comodel_name="pms.property",
|
||||
relation="res_partner_pms_property_rel",
|
||||
column1="res_partner_id",
|
||||
column2="pms_property_id",
|
||||
ondelete="restrict",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_checkin_partner_ids = fields.One2many(
|
||||
string="Checkin Partners",
|
||||
help="Associated checkin partners",
|
||||
comodel_name="pms.checkin.partner",
|
||||
inverse_name="partner_id",
|
||||
)
|
||||
pms_reservation_ids = fields.One2many(
|
||||
string="Reservations",
|
||||
help="Associated reservation",
|
||||
comodel_name="pms.reservation",
|
||||
inverse_name="partner_id",
|
||||
)
|
||||
pms_folio_ids = fields.One2many(
|
||||
string="Folios",
|
||||
help="Associated Folios",
|
||||
comodel_name="pms.folio",
|
||||
inverse_name="partner_id",
|
||||
)
|
||||
gender = fields.Selection(
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_gender",
|
||||
)
|
||||
birthdate_date = fields.Date(
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_birthdate_date",
|
||||
)
|
||||
nationality_id = fields.Many2one(
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_nationality_id",
|
||||
)
|
||||
# TODO: Use new partner contact "other or "private" with
|
||||
# personal contact address complete??
|
||||
# to avoid user country_id on companies contacts.
|
||||
# view to checkin partner state_id field
|
||||
state_id = fields.Many2one(
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_state_id",
|
||||
)
|
||||
email = fields.Char(
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_email",
|
||||
)
|
||||
mobile = fields.Char(
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_mobile",
|
||||
)
|
||||
firstname = fields.Char(
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_firstname",
|
||||
)
|
||||
|
||||
lastname = fields.Char(
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_lastname",
|
||||
)
|
||||
lastname2 = fields.Char(
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_lastname2",
|
||||
)
|
||||
comment = fields.Text(
|
||||
tracking=True,
|
||||
)
|
||||
reservation_possible_customer_id = fields.Many2one(
|
||||
string="Possible Customer In Reservation", comodel_name="pms.reservation"
|
||||
)
|
||||
folio_possible_customer_id = fields.Many2one(
|
||||
string="Possible Customer In Folio", comodel_name="pms.folio"
|
||||
)
|
||||
checkin_partner_possible_customer_id = fields.Many2one(
|
||||
string="Possible Customer In Checkin Partner",
|
||||
comodel_name="pms.checkin.partner",
|
||||
)
|
||||
|
||||
@api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.gender")
|
||||
def _compute_gender(self):
|
||||
if hasattr(super(), "_compute_gender"):
|
||||
super()._compute_gender()
|
||||
for record in self:
|
||||
if not record.gender and record.pms_checkin_partner_ids:
|
||||
gender = list(
|
||||
filter(None, set(record.pms_checkin_partner_ids.mapped("gender")))
|
||||
)
|
||||
if len(gender) == 1:
|
||||
record.gender = gender[0]
|
||||
else:
|
||||
record.gender = False
|
||||
elif not record.gender:
|
||||
record.gender = False
|
||||
|
||||
@api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.birthdate_date")
|
||||
def _compute_birthdate_date(self):
|
||||
if hasattr(super(), "_compute_birthdate_date"):
|
||||
super()._compute_birthdate_date()
|
||||
for record in self:
|
||||
if not record.birthdate_date and record.pms_checkin_partner_ids:
|
||||
birthdate = list(
|
||||
filter(
|
||||
None,
|
||||
set(record.pms_checkin_partner_ids.mapped("birthdate_date")),
|
||||
)
|
||||
)
|
||||
if len(birthdate) == 1:
|
||||
record.birthdate_date = birthdate[0]
|
||||
else:
|
||||
record.birthdate_date = False
|
||||
elif not record.birthdate_date:
|
||||
record.birthdate_date = False
|
||||
|
||||
@api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.nationality_id")
|
||||
def _compute_nationality_id(self):
|
||||
if hasattr(super(), "_compute_nationality_id"):
|
||||
super()._compute_nationality_id()
|
||||
for record in self:
|
||||
if not record.nationality_id and record.pms_checkin_partner_ids:
|
||||
nationality_id = list(
|
||||
filter(
|
||||
None,
|
||||
set(record.pms_checkin_partner_ids.mapped("nationality_id")),
|
||||
)
|
||||
)
|
||||
if len(nationality_id) == 1:
|
||||
record.nationality_id = nationality_id[0]
|
||||
else:
|
||||
record.nationality_id = False
|
||||
elif not record.nationality_id:
|
||||
record.nationality_id = False
|
||||
|
||||
@api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.state_id")
|
||||
def _compute_state_id(self):
|
||||
if hasattr(super(), "_compute_state_id"):
|
||||
super()._compute_state_id()
|
||||
for record in self:
|
||||
if not record.state_id and record.pms_checkin_partner_ids:
|
||||
state_id = list(
|
||||
filter(
|
||||
None,
|
||||
set(record.pms_checkin_partner_ids.mapped("state_id")),
|
||||
)
|
||||
)
|
||||
if len(state_id) == 1:
|
||||
record.state_id = state_id[0]
|
||||
else:
|
||||
record.state_id = False
|
||||
elif not record.state_id:
|
||||
record.state_id = False
|
||||
|
||||
@api.depends(
|
||||
"pms_checkin_partner_ids",
|
||||
"pms_checkin_partner_ids.email",
|
||||
"pms_reservation_ids",
|
||||
"pms_reservation_ids.email",
|
||||
"pms_folio_ids",
|
||||
"pms_folio_ids.email",
|
||||
)
|
||||
def _compute_email(self):
|
||||
if hasattr(super(), "_compute_email"):
|
||||
super()._compute_email()
|
||||
for record in self:
|
||||
if not record.email and (
|
||||
record.pms_checkin_partner_ids
|
||||
or record.pms_reservation_ids
|
||||
or record.pms_folio_ids
|
||||
):
|
||||
email = list(
|
||||
filter(
|
||||
None,
|
||||
set(
|
||||
record.pms_checkin_partner_ids.mapped("email")
|
||||
+ record.pms_reservation_ids.mapped("email")
|
||||
+ record.pms_folio_ids.mapped("email"),
|
||||
),
|
||||
)
|
||||
)
|
||||
if len(email) == 1:
|
||||
record.email = email[0]
|
||||
else:
|
||||
record.email = False
|
||||
elif not record.email:
|
||||
record.email = False
|
||||
|
||||
@api.depends(
|
||||
"pms_checkin_partner_ids",
|
||||
"pms_checkin_partner_ids.mobile",
|
||||
"pms_reservation_ids",
|
||||
"pms_reservation_ids.mobile",
|
||||
"pms_folio_ids",
|
||||
"pms_folio_ids.mobile",
|
||||
)
|
||||
def _compute_mobile(self):
|
||||
if hasattr(super(), "_compute_mobile"):
|
||||
super()._compute_mobile()
|
||||
for record in self:
|
||||
if not record.mobile and (
|
||||
record.pms_checkin_partner_ids
|
||||
or record.pms_reservation_ids
|
||||
or record.pms_folio_ids
|
||||
):
|
||||
mobile = list(
|
||||
filter(
|
||||
None,
|
||||
set(
|
||||
record.pms_checkin_partner_ids.mapped("mobile")
|
||||
+ record.pms_reservation_ids.mapped("mobile")
|
||||
+ record.pms_folio_ids.mapped("mobile"),
|
||||
),
|
||||
)
|
||||
)
|
||||
if len(mobile) == 1:
|
||||
record.mobile = mobile[0]
|
||||
else:
|
||||
record.mobile = False
|
||||
elif not record.mobile:
|
||||
record.mobile = False
|
||||
|
||||
@api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.firstname")
|
||||
def _compute_firstname(self):
|
||||
if hasattr(super(), "_compute_firstname"):
|
||||
super()._compute_firstname()
|
||||
for record in self:
|
||||
if not record.firstname and record.pms_checkin_partner_ids:
|
||||
firstname = list(
|
||||
filter(
|
||||
None, set(record.pms_checkin_partner_ids.mapped("firstname"))
|
||||
)
|
||||
)
|
||||
if len(firstname) == 1:
|
||||
record.firstname = firstname[0]
|
||||
else:
|
||||
record.firstname = False
|
||||
elif not record.firstname:
|
||||
record.firstname = False
|
||||
|
||||
@api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.lastname")
|
||||
def _compute_lastname(self):
|
||||
if hasattr(super(), "_compute_lastname"):
|
||||
super()._compute_lastname()
|
||||
for record in self:
|
||||
if not record.lastname and record.pms_checkin_partner_ids:
|
||||
lastname = list(
|
||||
filter(None, set(record.pms_checkin_partner_ids.mapped("lastname")))
|
||||
)
|
||||
if len(lastname) == 1:
|
||||
record.lastname = lastname[0]
|
||||
else:
|
||||
record.lastname = False
|
||||
elif not record.lastname:
|
||||
record.lastname = False
|
||||
|
||||
@api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.lastname2")
|
||||
def _compute_lastname2(self):
|
||||
if hasattr(super(), "_compute_lastname2"):
|
||||
super()._compute_lastname2()
|
||||
for record in self:
|
||||
if not record.lastname2 and record.pms_checkin_partner_ids:
|
||||
lastname2 = list(
|
||||
filter(
|
||||
None, set(record.pms_checkin_partner_ids.mapped("lastname2"))
|
||||
)
|
||||
)
|
||||
if len(lastname2) == 1:
|
||||
record.lastname2 = lastname2[0]
|
||||
else:
|
||||
record.lastname2 = False
|
||||
elif not record.lastname2:
|
||||
record.lastname2 = False
|
||||
|
||||
def _compute_reservations_count(self):
|
||||
# TODO: recuperar las reservas de los folios del partner
|
||||
pms_reservation_obj = self.env["pms.reservation"]
|
||||
for record in self:
|
||||
record.reservations_count = pms_reservation_obj.search_count(
|
||||
[
|
||||
(
|
||||
"partner_id.id",
|
||||
"child_of",
|
||||
record.id if isinstance(record.id, int) else False,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
def _compute_folios_count(self):
|
||||
pms_folio_obj = self.env["pms.folio"]
|
||||
for record in self:
|
||||
record.folios_count = pms_folio_obj.search_count(
|
||||
[
|
||||
(
|
||||
"partner_id.id",
|
||||
"=",
|
||||
record.id if isinstance(record.id, int) else False,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
@api.constrains("is_agency", "sale_channel_id")
|
||||
def _check_is_agency(self):
|
||||
for record in self:
|
||||
if record.is_agency and not record.sale_channel_id:
|
||||
raise models.ValidationError(_("Sale Channel must be entered"))
|
||||
if record.is_agency and record.sale_channel_id.channel_type != "indirect":
|
||||
raise models.ValidationError(
|
||||
_("Sale Channel for an agency must be indirect")
|
||||
)
|
||||
if not record.is_agency and record.sale_channel_id:
|
||||
record.sale_channel_id = None
|
||||
|
||||
# REVIEW: problems with odoo demo data
|
||||
# @api.constrains("mobile", "email")
|
||||
# def _check_duplicated(self):
|
||||
# for record in self:
|
||||
# partner, field = record._search_duplicated()
|
||||
# if partner:
|
||||
# raise models.ValidationError(
|
||||
# _(
|
||||
# "Partner %s found with same %s (%s)",
|
||||
# partner.name,
|
||||
# partner._fields[field].string,
|
||||
# getattr(record, field),
|
||||
# )
|
||||
# )
|
||||
|
||||
def _search_duplicated(self):
|
||||
self.ensure_one()
|
||||
partner = False
|
||||
for field in self._get_key_fields():
|
||||
if getattr(self, field):
|
||||
partner = self.search(
|
||||
[(field, "=", getattr(self, field)), ("id", "!=", self.id)]
|
||||
)
|
||||
if partner:
|
||||
field = field
|
||||
return partner, field
|
||||
|
||||
@api.model
|
||||
def _get_key_fields(self):
|
||||
key_fields = super(ResPartner, self)._get_key_fields()
|
||||
key_fields.extend(["document_number"])
|
||||
return key_fields
|
||||
@@ -1,55 +0,0 @@
|
||||
# Copyright 2004-2010 Tiny SPRL http://tiny.be
|
||||
# Copyright 2010-2012 ChriCar Beteiligungs- und Beratungs- GmbH
|
||||
# http://www.camptocamp.at
|
||||
# Copyright 2015 Antiun Ingenieria, SL (Madrid, Spain)
|
||||
# http://www.antiun.com
|
||||
# Antonio Espinosa <antonioea@antiun.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class ResPartnerIdNumber(models.Model):
|
||||
_inherit = "res.partner.id_number"
|
||||
|
||||
valid_from = fields.Date(
|
||||
readonly=False,
|
||||
store=True,
|
||||
compute="_compute_valid_from",
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"partner_id", "partner_id.pms_checkin_partner_ids.document_expedition_date"
|
||||
)
|
||||
def _compute_valid_from(self):
|
||||
if hasattr(super(), "_compute_valid_from"):
|
||||
super()._compute_valid_from()
|
||||
for record in self:
|
||||
if not record.valid_from and record.partner_id.pms_checkin_partner_ids:
|
||||
document_expedition_date = list(
|
||||
set(
|
||||
record.partner_id.pms_checkin_partner_ids.mapped(
|
||||
"document_expedition_date"
|
||||
)
|
||||
)
|
||||
)
|
||||
if len(document_expedition_date) == 1:
|
||||
record.valid_from = document_expedition_date[0]
|
||||
else:
|
||||
record.valid_from = False
|
||||
elif not record.valid_from:
|
||||
record.valid_from = False
|
||||
|
||||
@api.constrains("partner_id", "category_id")
|
||||
def _check_category_id_unique(self):
|
||||
for record in self:
|
||||
id_number = self.env["res.partner.id_number"].search(
|
||||
[
|
||||
("partner_id", "=", record.partner_id.id),
|
||||
("category_id", "=", record.category_id.id),
|
||||
]
|
||||
)
|
||||
if len(id_number) > 1:
|
||||
raise ValidationError(_("Partner already has this document type"))
|
||||
@@ -1,57 +0,0 @@
|
||||
# Copyright 2019 Pablo Quesada
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class ResUsers(models.Model):
|
||||
_inherit = "res.users"
|
||||
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Default Property",
|
||||
help="The property that is selected within " "those allowed for the user",
|
||||
comodel_name="pms.property",
|
||||
domain="[('id','in',pms_property_ids)]",
|
||||
context={"user_preference": True},
|
||||
)
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Properties",
|
||||
help="The properties allowed for this user",
|
||||
comodel_name="pms.property",
|
||||
relation="pms_property_users_rel",
|
||||
column1="user_id",
|
||||
column2="pms_property_id",
|
||||
domain="[('company_id','in',company_ids)]",
|
||||
)
|
||||
|
||||
@api.model
|
||||
def get_active_property_ids(self):
|
||||
# TODO: Require performance test and security (dont allow any property id)
|
||||
# checks (Review lazy_property decorator?)
|
||||
user_property_ids = self.env.user.pms_property_ids.ids
|
||||
if request and request.httprequest.cookies.get("pms_pids"):
|
||||
active_property_ids = list(
|
||||
map(int, request.httprequest.cookies.get("pms_pids", "").split(","))
|
||||
)
|
||||
active_property_ids = [
|
||||
pid for pid in active_property_ids if pid in user_property_ids
|
||||
]
|
||||
return self.env["pms.property"].browse(active_property_ids).ids
|
||||
return user_property_ids
|
||||
|
||||
@api.constrains("pms_property_id", "pms_property_ids")
|
||||
def _check_property_in_allowed_properties(self):
|
||||
if any(user.pms_property_id not in user.pms_property_ids for user in self):
|
||||
raise ValidationError(
|
||||
_("The chosen property is not in the allowed properties for this user")
|
||||
)
|
||||
|
||||
@api.constrains("pms_property_ids", "company_id")
|
||||
def _check_company_in_property_ids(self):
|
||||
for record in self:
|
||||
for pms_property in record.pms_property_ids:
|
||||
if pms_property.company_id not in record.company_ids:
|
||||
raise ValidationError(
|
||||
_("Some properties do not belong to the allowed companies")
|
||||
)
|
||||
@@ -1,3 +0,0 @@
|
||||
You will find the hotel settings in PMS Management > Configuration > Properties > Your Property.
|
||||
|
||||
This module required additional configuration for company, accounting, invoicing and user privileges.
|
||||
@@ -1,10 +0,0 @@
|
||||
* Alexandre Díaz
|
||||
* Pablo Quesada
|
||||
* Jose Luis Algara
|
||||
* `Commit [Sun] <https://www.commitsun.com>`:
|
||||
|
||||
* Dario Lodeiros
|
||||
* Eric Antones
|
||||
* Sara Lago
|
||||
* Brais Abeijon
|
||||
* Miguel Padin
|
||||
@@ -1,5 +0,0 @@
|
||||
This module is an all-in-one property management system (PMS) focused on medium-sized properties
|
||||
for managing every aspect of your property's daily operations.
|
||||
|
||||
You can manage properties with multi-property and multi-company support, including your rooms inventory,
|
||||
reservations, check-in, daily reports, board services, rate and availability plans among other property functionalities.
|
||||
@@ -1,2 +0,0 @@
|
||||
This module depends on modules ``base``, ``mail``, ``sale`` and ``multi_pms_properties``.
|
||||
Ensure yourself to have all them in your addons list.
|
||||
@@ -1 +0,0 @@
|
||||
To use this module, please, read the complete user guide at `<roomdoo.com>`_.
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="action_report_folio" model="ir.actions.report">
|
||||
<field name="name">Report Folio</field>
|
||||
<field name="model">pms.folio</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">pms.report_folio</field>
|
||||
<field name="report_file">pms.report_folio</field>
|
||||
<field
|
||||
name="print_report_name"
|
||||
>(object.state in ('draft', 'sent') and 'Quotation - %s' % (object.name)) or 'Order - %s' % (object.name)</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user