[DEL] Cleanup

This commit is contained in:
Maxime Chambreuil
2022-01-06 11:12:15 -06:00
parent bad19e534d
commit 7919b2acbb
335 changed files with 0 additions and 80593 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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,
}

View File

@@ -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 ""

View File

@@ -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

View File

@@ -1,5 +0,0 @@
* `Commit [Sun] <https://www.commitsun.com>`:
* Dario Lodeiros
* Eric Antones
* Sara Lago

View File

@@ -1 +0,0 @@
Technical addon to support multiproperty in property management system (PMS).

View File

@@ -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"``

View File

@@ -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

View File

@@ -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 = &quot;multi_pms_properties&quot;</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&nbsp; 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] &lt;https://www.commitsun.com&gt;</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>

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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"})

View File

@@ -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.

View File

@@ -1,2 +0,0 @@
from . import models
from . import controllers

View File

@@ -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,
}

View File

@@ -1,3 +0,0 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import portal

View File

@@ -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

View File

@@ -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 ""

View File

@@ -1 +0,0 @@
from . import payment_acquirer

View File

@@ -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,
)

View File

@@ -1,3 +0,0 @@
* `Commit [Sun] <https://www.commitsun.com>`:
* Dario Lodeiros

View File

@@ -1 +0,0 @@
Set the pms property in the payment acquirer to filter on website payments

View File

@@ -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

View File

@@ -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] &lt;https://www.commitsun.com&gt;</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>

View File

@@ -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>

View File

@@ -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.

View File

@@ -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

View File

@@ -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",
}

View File

@@ -1 +0,0 @@
from . import pms_portal

View File

@@ -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)

View File

@@ -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>

View File

@@ -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>

View File

@@ -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" &lt;%s&gt;' % (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>

View File

@@ -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" &lt;%s&gt;' % (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>

View File

@@ -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>

View File

@@ -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" &lt;%s&gt;' % (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>

View File

@@ -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" &lt;%s&gt;' % (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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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"
)

View File

@@ -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

View File

@@ -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",
)

View File

@@ -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

View File

@@ -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",
)

View File

@@ -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)],
}

View File

@@ -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)]

View File

@@ -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

View File

@@ -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")
)

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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,
)
)

View File

@@ -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",
)

View File

@@ -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,
)

View File

@@ -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

View File

@@ -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")
)

View File

@@ -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,
},
}

View File

@@ -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")
)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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}

View File

@@ -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)

View File

@@ -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",
)

View File

@@ -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

View File

@@ -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

View File

@@ -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"))

View File

@@ -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

View File

@@ -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,
)

View File

@@ -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

View File

@@ -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)

View File

@@ -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,
)

View File

@@ -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

View File

@@ -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

View File

@@ -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"))

View File

@@ -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,
},
}

View File

@@ -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
)

View File

@@ -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
)

View File

@@ -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,
)

View File

@@ -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",
)

View File

@@ -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

View File

@@ -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"))

View File

@@ -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")
)

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -1 +0,0 @@
To use this module, please, read the complete user guide at `<roomdoo.com>`_.

View File

@@ -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