Precommit V14

This commit is contained in:
Darío Lodeiros
2020-10-21 12:54:21 +02:00
parent a2ead12060
commit 9554737792
50 changed files with 740 additions and 458 deletions

13
.copier-answers.yml Normal file
View File

@@ -0,0 +1,13 @@
# Do NOT update manually; changes here will be overwritten by Copier
_commit: v1.0.2
_src_path: https://github.com/OCA/oca-addons-repo-template.git
dependency_installation_mode: OCA
include_wkhtmltopdf: false
odoo_version: 14.0
rebel_module_groups: []
repo_description:
All-in-One Property Management System (PMS) focused on medium-sizeations.
repo_name: Property Management System
repo_slug: pms
travis_apt_packages: []
travis_apt_sources: []

74
.gitignore vendored
View File

@@ -1,5 +1,75 @@
*.pyc
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
/.venv
/.pytest_cache
.settings/
# C extensions
*.so
# Distribution / packaging
.Python
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
*.eggs
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Pycharm
.idea
# Eclipse
.settings
# Visual Studio cache/options directory
.vs/
.vscode
# OSX Files
.DS_Store
# Django stuff:
*.log
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Rope
.ropeproject
# Sphinx documentation
docs/_build/
# Backup files
*~
*.swp
# OCA rules
!static/lib/

View File

@@ -10,4 +10,3 @@ known_odoo=odoo
known_odoo_addons=odoo.addons
sections=FUTURE,STDLIB,THIRDPARTY,ODOO,ODOO_ADDONS,FIRSTPARTY,LOCALFOLDER
default_section=THIRDPARTY
known_third_party=openerp,werkzeug

View File

@@ -1,5 +1,7 @@
exclude: |
(?x)
# NOT INSTALLABLE ADDONS
# END NOT INSTALLABLE ADDONS
# Files and folders generated by bots, to avoid loops
^setup/|/static/description/index\.html$|
# Maybe reactivate this when all README files include prettier ignore tags?
@@ -12,28 +14,42 @@ exclude: |
(LICENSE.*|COPYING.*)
default_language_version:
python: python3
node: "14.13.0"
repos:
- repo: local
hooks:
# These files are most likely copier diff rejection junks; if found,
# review them manually, fix the problem (if needed) and remove them
- id: forbidden-files
name: forbidden files
entry: found forbidden files; remove them
language: fail
files: "\\.rej$"
- repo: https://github.com/oca/maintainer-tools
rev: 2c66e72
hooks:
# update the NOT INSTALLABLE ADDONS section above
- id: oca-update-pre-commit-excluded-addons
- repo: https://github.com/myint/autoflake
rev: v1.4
hooks:
- id: autoflake
args: ["-i", "--ignore-init-module-imports"]
- repo: https://github.com/psf/black
rev: 19.10b0
rev: 20.8b1
hooks:
- id: black
- repo: https://github.com/prettier/prettier
rev: "1.19.1"
rev: 2.1.2
hooks:
- id: prettier
# TODO Avoid awebdeveloper/pre-commit-prettier if possible
# HACK https://github.com/prettier/prettier/issues/7407
- repo: https://github.com/awebdeveloper/pre-commit-prettier
rev: v0.0.1
hooks:
- id: prettier
name: prettier xml plugin
name: prettier + plugin-xml
additional_dependencies:
- "prettier@1.19.1"
- "@prettier/plugin-xml@0.7.2"
files: \.xml$
- "@prettier/plugin-xml@0.12.0"
args:
- --plugin=@prettier/plugin-xml
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v6.8.0
rev: v7.8.1
hooks:
- id: eslint
verbose: true
@@ -41,7 +57,7 @@ repos:
- --color
- --fix
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
rev: v3.2.0
hooks:
- id: trailing-whitespace
# exclude autogenerated files
@@ -62,41 +78,47 @@ repos:
- id: check-xml
- id: mixed-line-ending
args: ["--fix=lf"]
- repo: https://gitlab.com/pycqa/flake8
rev: 3.7.9
- repo: https://github.com/asottile/pyupgrade
rev: v2.7.2
hooks:
- id: pyupgrade
- repo: https://github.com/PyCQA/isort
rev: 5.5.1
hooks:
- id: isort
name: isort except __init__.py
args:
- --settings=.
exclude: /__init__\.py$
- repo: https://github.com/acsone/setuptools-odoo
rev: 2.5.10
hooks:
- id: setuptools-odoo-make-default
- repo: https://gitlab.com/PyCQA/flake8
rev: 3.8.3
hooks:
- id: flake8
name: flake8 except __init__.py
exclude: /__init__\.py$
additional_dependencies: ["flake8-bugbear==19.8.0"]
additional_dependencies: ["flake8-bugbear==20.1.4"]
- id: flake8
name: flake8 only __init__.py
args: ["--extend-ignore=F401"] # ignore unused imports in __init__.py
files: /__init__\.py$
additional_dependencies: ["flake8-bugbear==19.8.0"]
- repo: https://github.com/pre-commit/mirrors-pylint
rev: v2.3.1
additional_dependencies: ["flake8-bugbear==20.1.4"]
- repo: https://github.com/PyCQA/pylint
rev: pylint-2.5.3
hooks:
- id: pylint
name: pylint with optional checks
args: ["--rcfile=.pylintrc", "--exit-zero"]
args:
- --rcfile=.pylintrc
- --exit-zero
verbose: true
additional_dependencies: ["pylint-odoo==3.1.0"]
additional_dependencies: &pylint_deps
- pylint-odoo==3.5.0
- id: pylint
name: pylint with mandatory checks
args: ["--rcfile=.pylintrc-mandatory"]
additional_dependencies: ["pylint-odoo==3.1.0"]
- repo: https://github.com/asottile/pyupgrade
rev: v1.26.2
hooks:
- id: pyupgrade
- repo: https://github.com/pre-commit/mirrors-isort
rev: v4.3.21
hooks:
- id: isort
name: isort except __init__.py
exclude: /__init__\.py$
- repo: https://github.com/acsone/setuptools-odoo
rev: 2.5.2
hooks:
- id: setuptools-odoo-make-default
args:
- --rcfile=.pylintrc-mandatory
additional_dependencies: *pylint_deps

View File

@@ -45,8 +45,6 @@ enable=anomalous-backslash-in-string,
method-inverse,
method-required-super,
method-search,
missing-import-error,
missing-manifest-dependency,
openerp-exception-warning,
pointless-statement,
pointless-string-statement,
@@ -72,6 +70,7 @@ enable=anomalous-backslash-in-string,
deprecated-module,
file-not-used,
invalid-commit,
missing-manifest-dependency,
missing-newline-extrafiles,
missing-readme,
no-utf8-coding-comment,
@@ -81,6 +80,7 @@ enable=anomalous-backslash-in-string,
too-complex,
unnecessary-utf8-coding-comment
[REPORTS]
msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg}
output-format=colorized

View File

@@ -38,8 +38,6 @@ enable=anomalous-backslash-in-string,
method-inverse,
method-required-super,
method-search,
missing-import-error,
missing-manifest-dependency,
openerp-exception-warning,
pointless-statement,
pointless-string-statement,

View File

@@ -1,49 +1,48 @@
language: python
cache:
directories:
- $HOME/.cache/pip
- $HOME/.cache/pre-commit
python:
- "3.5"
sudo: false
cache: pip
- "3.6"
addons:
postgresql: "9.2" # minimal postgresql version for the daterange method
postgresql: "9.6"
apt:
packages:
- expect-dev # provides unbuffer utility
- python-lxml # because pip installation is slow
stages:
- linting
- test
jobs:
include:
- stage: linting
name: "pre-commit"
install: pip install pre-commit
script: pre-commit run --all --show-diff-on-failure --verbose --color always
after_success:
before_install:
- stage: test
env:
- TESTS=1 ODOO_REPO="odoo/odoo" MAKEPOT="1"
- stage: test
env:
- TESTS=1 ODOO_REPO="OCA/OCB"
env:
global:
- VERSION="11.0" TESTS="0" LINT_CHECK="0" TRANSIFEX="0" MAKEPOT="0"
# - TRANSIFEX_USER='transbot@odoo-community.org'
# - secure: "XLhGdCIh86zcqww9qBpnk8Xqsf1Pcgw9SKr7X0KYBHJofHj4Z6Kq/oVFjpZ1LSjadsaABKbwY7h4hvKEpxZwptCv+fNTOKYy7hXFLGYnDeNeWu4zA4LI7TA5uPvyZjZ+g2xc+9dzR/VbfRHNqjvmgiEidxxqLeOnNFZ5CHdOdCw="
matrix:
# Option temporarily disabled
#- LINT_CHECK="1"
- TESTS="1" ODOO_REPO="odoo/odoo"
- TESTS="1" ODOO_REPO="OCA/OCB"
- VERSION="14.0" TESTS="0" LINT_CHECK="0" MAKEPOT="0"
install:
- git clone https://github.com/OCA/maintainer-quality-tools.git
${HOME}/maintainer-quality-tools --depth=1
- git clone --depth=1 https://github.com/OCA/maintainer-quality-tools.git
${HOME}/maintainer-quality-tools
- export PATH=${HOME}/maintainer-quality-tools/travis:${PATH}
- git clone -b ${VERSION} https://github.com/OCA/web.git ${HOME}/dependencies/web
--depth=1
- git clone -b ${VERSION} https://github.com/OCA/partner-contact.git
${HOME}/dependencies/partner-contact --depth=1
- git clone -b ${VERSION} https://github.com/OCA/account-payment.git
${HOME}/dependencies/account-payment --depth=1
- git clone -b ${VERSION} https://github.com/OCA/connector.git
${HOME}/dependencies/connector --depth=1
- git clone -b ${VERSION} https://github.com/OCA/queue.git ${HOME}/dependencies/queue
--depth=1
- pip install odoorpc
- pip install cachetools>=2.0.1
- travis_install_nightly
script:
- travis_wait travis_run_tests
- travis_run_tests
after_success:
- travis_after_tests_success

10
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,10 @@
# OCA Guidelines
Please follow the official guide from the
[OCA Guidelines page](https://odoo-community.org/page/contributing).
## Project Specific Guidelines
<!-- /!\ do not modify above this line -->
This project does not have specific coding guidelines.

10
LICENSE
View File

@@ -1,7 +1,7 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -633,8 +633,8 @@ the "copyright" line and a pointer to where the full notice is found.
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
@@ -643,7 +643,7 @@ the "copyright" line and a pointer to where the full notice is found.
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
@@ -658,4 +658,4 @@ specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
<https://www.gnu.org/licenses/>.

View File

@@ -1,22 +1,36 @@
[![Build Status](https://travis-ci.org/hootel/hootel.svg?branch=11.0)](https://travis-ci.org/hootel/hootel) [![codecov](https://codecov.io/gh/hootel/hootel/branch/11.0/graph/badge.svg)](https://codecov.io/gh/hootel/hootel) ![Unstable](https://img.shields.io/badge/stability-unstable-yellow.svg)
[![Runbot Status](https://runbot.odoo-community.org/runbot/badge/flat//14.0.svg)](https://runbot.odoo-community.org/runbot/repo/github-com-oca-pms-)
[![Build Status](https://travis-ci.com/OCA/pms.svg?branch=14.0)](https://travis-ci.com/OCA/pms)
[![codecov](https://codecov.io/gh/OCA/pms/branch/14.0/graph/badge.svg)](https://codecov.io/gh/OCA/pms)
[![Translation Status](https://translation.odoo-community.org/widgets/pms-14-0/-/svg-badge.svg)](https://translation.odoo-community.org/engage/pms-14-0/?utm_source=widget)
# ROOMDOO
All-in-One Property Management System (PMS) focused on medium-sized hotels for managing every aspect of your property's daily operations.
<!-- /!\ do not modify above this line -->
You will find modules for:
# Property Management System
- Manage hotel properties with multi-hotel and multi-company support.
- Manage your rooms inventory, reservations, check-in, daily reports, board services, rate and restriction plans.
- Handle reservations in a user friendly calendar management view.
- Connect your hotel with a channel manager for booking though Online Travel Agencies, such as, Booking.com, Expedia, Hotelbeds, ...
- Revenue management tools for daily pricing and availability strategies.
All-in-One Property Management System (PMS) focused on medium-sizeations.
<!-- /!\ do not modify below this line -->
Bug Tracker
-----------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback here.
<!-- prettier-ignore-start -->
Contributing
------------
Do you want to contribute? Please, do not hesitate to contact any of the current contributors :)
[//]: # (addons)
This part will be replaced when running the oca-gen-addons-table script from OCA/maintainer-tools.
[//]: # (end addons)
<!-- prettier-ignore-end -->
## Licenses
This repository is licensed under [AGPL-3.0](LICENSE).
However, each module can have a totally different license, as long as they adhere to OCA
policy. Consult each module's `__manifest__.py` file, which contains a `license` key
that explains its license.
----
OCA, or the [Odoo Community Association](http://odoo-community.org/), is a nonprofit
organization whose mission is to support the collaborative development of Odoo features
and promote its widespread use.

1
oca_dependencies.txt Normal file
View File

@@ -0,0 +1 @@
# See https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#oca_dependencies-txt

View File

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

View File

@@ -61,8 +61,14 @@
"views/product_pricelist_views.xml",
"views/product_template_views.xml",
"views/webclient_templates.xml",
"views/ir_sequence_views.xml"
"views/ir_sequence_views.xml",
],
"demo": [
"demo/pms_master_data.xml",
"demo/pms_folio.xml",
"demo/pms_reservation.xml",
],
"qweb": [
"static/src/xml/pms_base_templates.xml",
],
"demo": ["demo/pms_master_data.xml", "demo/pms_folio.xml"],
"qweb": ["static/src/xml/pms_base_templates.xml",],
}

View File

@@ -3,9 +3,17 @@
<data noupdate="1">
<!-- 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>
<!-- Basic pms -->
@@ -26,17 +34,5 @@
<field name="website">https://www.commitsun.com</field>
<field name="folio_sequence_id" ref="pms.seq_pms_folio" />
</record>
<record model="res.users" id="base.user_root">
<field name="company_id" ref="base.main_company" />
<field name="company_ids" eval="[(4, ref('base.main_company'))]" />
<field name="pms_property_id" ref="main_pms_property" />
<field name="pms_property_ids" eval="[(4, ref('main_pms_property'))]" />
</record>
<record model="res.users" id="base.user_admin">
<field name="company_id" ref="base.main_company" />
<field name="company_ids" eval="[(4, ref('base.main_company'))]" />
<field name="pms_property_id" ref="main_pms_property" />
<field name="pms_property_ids" eval="[(4, ref('main_pms_property'))]" />
</record>
</data>
</odoo>

View File

@@ -286,15 +286,16 @@
<!-- room.closure.reason -->
<record id="pms_room_closure_reason_0" model="room.closure.reason">
<field name="name">Maintenance</field>
<field
name="description"
>Used for closing of rooms which require a maintenance. You can specify the reason in the own reservation.</field>
<field name="description">
Used for closing of rooms which require a maintenance. You can specify
the reason in the own reservation.
</field>
</record>
<record id="pms_room_closure_reason_1" model="room.closure.reason">
<field name="name">VIP Privacy</field>
<field
name="description"
>Used for closing of rooms for extra privacy.</field>
<field name="description">
Used for closing of rooms for extra privacy.
</field>
</record>
<!-- Multi pms Demo -->
<record id="demo_pms_room_type_restriction" model="pms.room.type.restriction">

View File

@@ -10,7 +10,6 @@
<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" />
</record>
<record id="pms_reservation_1" model="pms.reservation">
<field name="reservation_type">"out"</field>
@@ -61,7 +60,6 @@
<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" />
</record>
<record id="pms_reservation_7" model="pms.reservation">
<field name="partner_id" ref="base.res_partner_address_10" />
@@ -71,7 +69,6 @@
<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" />
</record>
<record id="pms_reservation_8" model="pms.reservation">
<field name="partner_id" ref="base.res_partner_address_13" />
@@ -81,7 +78,6 @@
<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" />
</record>
<record id="pms_reservation_9" model="pms.reservation">
<field name="partner_id" ref="base.res_partner_address_15" />
@@ -108,7 +104,6 @@
<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" />
</record>
<record id="pms_reservation_12" model="pms.reservation">
<field name="partner_id" ref="base.res_partner_address_10" />
@@ -127,7 +122,6 @@
<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" />
</record>
<record id="pms_reservation_14" model="pms.reservation">
<field name="partner_id" ref="base.res_partner_address_33" />
@@ -163,7 +157,6 @@
<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" />
</record>
<record id="pms_reservation_18" model="pms.reservation">
<field name="partner_id" ref="base.res_partner_12" />
@@ -262,7 +255,6 @@
<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)" />
</record>
<record id="pms_reservation_29" model="pms.reservation">
<field name="partner_id" ref="base.res_partner_address_32" />
@@ -270,7 +262,6 @@
<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)" />
</record>
<record id="pms_reservation_30" model="pms.reservation">
<field name="partner_id" ref="base.res_partner_address_33" />
@@ -278,7 +269,6 @@
<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)" />
</record>
</data>
</odoo>

View File

@@ -4,6 +4,7 @@
from . import ir_http
from . import ir_sequence
# from . import payment_return
from . import pms_board_service_room_type
from . import pms_property
@@ -28,7 +29,8 @@ from . import pms_reservation_line
from . import pms_checkin_partner
from . import product_pricelist
from . import res_partner
from . import mail_compose_message
# from . import mail_compose_message
from . import pms_room_type_class
from . import pms_room_closure_reason
from . import pms_service_line

View File

@@ -3,7 +3,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
import json
from odoo import _, api, fields, models
from odoo import _, fields, models
from odoo.tools import float_is_zero
@@ -12,18 +12,20 @@ class AccountMove(models.Model):
# Field Declarations
folio_ids = fields.Many2many(
comodel_name="pms.folio", compute="_computed_folio_origin"
comodel_name="pms.folio", compute="_compute_folio_origin"
)
pms_property_id = fields.Many2one("pms.property")
from_folio = fields.Boolean(compute="_computed_folio_origin")
from_folio = fields.Boolean(compute="_compute_folio_origin")
outstanding_folios_debits_widget = fields.Text(
compute="_get_outstanding_folios_JSON"
compute="_compute_get_outstanding_folios_JSON"
)
has_folios_outstanding = fields.Boolean(
compute="_compute_get_outstanding_folios_JSON"
)
has_folios_outstanding = fields.Boolean(compute="_get_outstanding_folios_JSON")
# Compute and Search methods
def _computed_folio_origin(self):
def _compute_folio_origin(self):
for inv in self:
inv.from_folio = False
inv.folio_ids = False
@@ -53,7 +55,7 @@ class AccountMove(models.Model):
}
# Business methods
def _get_outstanding_folios_JSON(self):
def _compute_get_outstanding_folios_JSON(self):
self.ensure_one()
self.outstanding_folios_debits_widget = json.dumps(False)
if self.from_folio:

View File

@@ -10,7 +10,9 @@ class AccountPayment(models.Model):
# Fields declaration
folio_id = fields.Many2one("pms.folio", string="Folio")
amount_total_folio = fields.Float(
compute="_compute_folio_amount", store=True, string="Total amount in folio",
compute="_compute_folio_amount",
store=True,
string="Total amount in folio",
)
save_amount = fields.Monetary(string="onchange_amount")
save_date = fields.Date()
@@ -53,8 +55,6 @@ class AccountPayment(models.Model):
self.save_date = self._origin.payment_date
# Action methods
"""WIP"""
# def return_payment_folio(self):
# journal = self.journal_id
# partner = self.partner_id
@@ -129,18 +129,15 @@ class AccountPayment(models.Model):
if rec and not self._context.get("ignore_notification_post", False):
for pay in self:
if pay.folio_id:
msg = (
_(
msg = _(
"Payment of %s %s registered from %s \
using %s payment method"
)
% (
) % (
pay.amount,
pay.currency_id.symbol,
pay.communication,
pay.journal_id.name,
)
)
pay.folio_id.message_post(subject=_("Payment"), body=msg)
def modify_payment(self):

View File

@@ -2,8 +2,7 @@
# Copyright 2019 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, models
from odoo.exceptions import MissingError
from odoo import models
from odoo.http import request
@@ -21,7 +20,8 @@ class IrHttp(models.AbstractModel):
user.pms_property_id.id,
user.pms_property_id.name,
),
# TODO: filter all properties based on the current set of active companies
# 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

View File

@@ -1,7 +1,7 @@
# Copyright 2017 Alexandre Díaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models
from odoo import models
class MailComposeMessage(models.TransientModel):
@@ -13,12 +13,12 @@ class MailComposeMessage(models.TransientModel):
and self._context.get("default_res_id")
and self._context.get("mark_so_as_sent")
):
folio = self.env["pms.folio"].browse([self._context["default_res_id"]])
# TODO: WorkFlow Mails
# if folio:
# cmds = [
# (1, lid, {"to_send": False}) for lid in folio.reservation_ids.ids
# ]
# if any(cmds):
# folio.reservation_ids = cmds
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
return super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)

View File

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

View File

@@ -18,7 +18,8 @@ class PmsBoardServiceRoomType(models.Model):
for res in self:
if res.pricelist_id:
name = u"{} ({})".format(
res.pms_board_service_id.name, res.pricelist_id.name,
res.pms_board_service_id.name,
res.pricelist_id.name,
)
else:
name = u"{} ({})".format(res.pms_board_service_id.name, _("Generic"))

View File

@@ -21,7 +21,7 @@ class PmsFolio(models.Model):
for folio in self:
name = folio.name
if len(folio.reservation_ids) > 1:
name += ' (%s)' % len(folio.reservation_ids)
name += " (%s)" % len(folio.reservation_ids)
result.append((folio.id, name))
return result
@@ -39,7 +39,9 @@ class PmsFolio(models.Model):
@api.model
def _get_default_pms_property(self):
return self.env.user.pms_property_id #TODO: Change by property env variable (like company)
return (
self.env.user.pms_property_id
) # TODO: Change by property env variable (like company)
# Fields declaration
name = fields.Char(
@@ -59,7 +61,9 @@ class PmsFolio(models.Model):
help="Room reservation detail.",
)
number_of_rooms = fields.Integer(
"Number of Rooms", compute="_compute_number_of_rooms", store="True",
"Number of Rooms",
compute="_compute_number_of_rooms",
store="True",
)
service_ids = fields.One2many(
"pms.service",
@@ -70,7 +74,10 @@ class PmsFolio(models.Model):
"include in main Invoice.",
)
company_id = fields.Many2one(
"res.company", "Company", required=True, default=lambda self: self.env.company,
"res.company",
"Company",
required=True,
default=lambda self: self.env.company,
)
analytic_account_id = fields.Many2one(
"account.analytic.account",
@@ -108,7 +115,10 @@ class PmsFolio(models.Model):
readonly=False,
)
agency_id = fields.Many2one(
"res.partner", "Agency", ondelete="restrict", domain=[("is_agency", "=", True)],
"res.partner",
"Agency",
ondelete="restrict",
domain=[("is_agency", "=", True)],
)
payment_ids = fields.One2many("account.payment", "folio_id", readonly=True)
# return_ids = fields.One2many("payment.return", "folio_id", readonly=True)
@@ -125,7 +135,7 @@ class PmsFolio(models.Model):
move_ids = fields.Many2many(
"account.move",
string="Invoices",
compute="_get_invoiced",
compute="_compute_get_invoiced",
readonly=True,
copy=False,
)
@@ -155,7 +165,10 @@ class PmsFolio(models.Model):
default=lambda *a: "normal",
)
channel_type = fields.Selection(
[("direct", "Direct"), ("agency", "Agency"),],
[
("direct", "Direct"),
("agency", "Agency"),
],
string="Sales Channel",
compute="_compute_channel_type",
store=True,
@@ -203,13 +216,13 @@ class PmsFolio(models.Model):
# Amount Fields------------------------------------------------------
pending_amount = fields.Monetary(
compute="compute_amount", store=True, string="Pending in Folio"
compute="_compute_amount", store=True, string="Pending in Folio"
)
# refund_amount = fields.Monetary(
# compute="compute_amount", store=True, string="Payment Returns"
# compute="_compute_amount", store=True, string="Payment Returns"
# )
invoices_paid = fields.Monetary(
compute="compute_amount",
compute="_compute_amount",
store=True,
track_visibility="onchange",
string="Payments",
@@ -218,17 +231,17 @@ class PmsFolio(models.Model):
string="Untaxed Amount",
store=True,
readonly=True,
compute="_amount_all",
compute="_compute_amount_all",
track_visibility="onchange",
)
amount_tax = fields.Monetary(
string="Taxes", store=True, readonly=True, compute="_amount_all"
string="Taxes", store=True, readonly=True, compute="_compute_amount_all"
)
amount_total = fields.Monetary(
string="Total",
store=True,
readonly=True,
compute="_amount_all",
compute="_compute_amount_all",
track_visibility="always",
)
# Checkin Fields-----------------------------------------------------
@@ -249,7 +262,7 @@ class PmsFolio(models.Model):
("no", "Nothing to Invoice"),
],
string="Invoice Status",
compute="_get_invoiced",
compute="_compute_get_invoiced",
store=True,
readonly=True,
default="no",
@@ -300,9 +313,9 @@ class PmsFolio(models.Model):
def _compute_channel_type(self):
for folio in self:
if folio.agency_id:
folio.channel_type = 'agency'
folio.channel_type = "agency"
else:
folio.channel_type = 'direct'
folio.channel_type = "direct"
@api.depends("partner_id")
def _compute_payment_term_id(self):
@@ -317,7 +330,7 @@ class PmsFolio(models.Model):
@api.depends(
"state", "reservation_ids.invoice_status", "service_ids.invoice_status"
)
def _get_invoiced(self):
def _compute_get_invoiced(self):
"""
Compute the invoice status of a Folio. Possible statuses:
- no: if the Folio is not in status 'sale' or 'done', we
@@ -409,7 +422,7 @@ class PmsFolio(models.Model):
)
@api.depends("reservation_ids.price_total", "service_ids.price_total")
def _amount_all(self):
def _compute_amount_all(self):
"""
Compute the total amounts of the SO.
"""
@@ -432,10 +445,8 @@ class PmsFolio(models.Model):
)
# TODO: Add return_ids to depends
@api.depends(
"amount_total", "payment_ids", "reservation_type", "state"
)
def compute_amount(self):
@api.depends("amount_total", "payment_ids", "reservation_type", "state")
def _compute_amount(self):
acc_pay_obj = self.env["account.payment"]
for record in self:
if record.reservation_type in ("staff", "out"):
@@ -455,7 +466,9 @@ class PmsFolio(models.Model):
# ("return_id.state", "=", "done"),
# ]
# )
# total_inv_refund = sum(pay_return.amount for pay_return in return_lines)
# total_inv_refund = sum(
# pay_return.amount for pay_return in return_lines
# )
total = record.amount_total
# REVIEW: Must We ignored services in cancelled folios
# pending amount?
@@ -548,10 +561,14 @@ class PmsFolio(models.Model):
# TODO: Make sequence from property, not company
if vals.get("name", _("New")) == _("New") or "name" not in vals:
# TODO: change for property env variable
pms_property_id = self.env.user.pms_property_id.id if "pms_property_id" not in vals else vals["pms_property_id"]
vals["name"] = self.env["ir.sequence"].search([
('pms_property_id', '=', pms_property_id)
]).next_by_code("pms.folio") or _("New")
pms_property_id = (
self.env.user.pms_property_id.id
if "pms_property_id" not in vals
else vals["pms_property_id"]
)
vals["name"] = self.env["ir.sequence"].search(
[("pms_property_id", "=", pms_property_id)]
).next_by_code("pms.folio") or _("New")
result = super(PmsFolio, self).create(vals)
return result
@@ -569,7 +586,9 @@ class PmsFolio(models.Model):
):
reservation.action_cancel()
self.write(
{"state": "cancel",}
{
"state": "cancel",
}
)
return True
@@ -589,9 +608,7 @@ class PmsFolio(models.Model):
# self._create_analytic_account()
return True
"""
CHECKIN/OUT PROCESS
"""
# CHECKIN/OUT PROCESS
def _compute_checkin_partner_count(self):
for record in self:
@@ -636,6 +653,8 @@ class PmsFolio(models.Model):
if t["id"] == tax.id or t["id"] in tax.children_tax_ids.ids:
res[group]["amount"] += t["amount"]
res[group]["base"] += t["base"]
res = sorted(res.items(), key=lambda l: l[0].sequence)
res = [(l[0].name, l[1]["amount"], l[1]["base"], len(res)) for l in res]
res = sorted(res.items(), key=lambda line: line[0].sequence)
res = [
(line[0].name, line[1]["amount"], line[1]["base"], len(res)) for line in res
]
return res

View File

@@ -53,8 +53,8 @@ class PmsProperty(models.Model):
default_cancel_policy_days = fields.Integer("Cancellation Days")
default_cancel_policy_percent = fields.Float("Percent to pay")
folio_sequence_id = fields.Many2one(
'ir.sequence', 'Folio Sequence',
check_company=True, copy=False)
"ir.sequence", "Folio Sequence", check_company=True, copy=False
)
# Constraints and onchanges
@api.constrains("default_arrival_hour", "default_departure_hour")

View File

@@ -118,13 +118,19 @@ class PmsReservation(models.Model):
domain="[('id', 'in', allowed_room_ids)]",
)
allowed_room_ids = fields.Many2many(
"pms.room", string="Allowed Rooms", compute="_compute_allowed_room_ids",
"pms.room",
string="Allowed Rooms",
compute="_compute_allowed_room_ids",
)
folio_id = fields.Many2one(
"pms.folio", string="Folio", track_visibility="onchange", ondelete="restrict",
"pms.folio",
string="Folio",
track_visibility="onchange",
ondelete="restrict",
)
board_service_room_id = fields.Many2one(
"pms.board.service.room.type", string="Board Service",
"pms.board.service.room.type",
string="Board Service",
)
room_type_id = fields.Many2one(
"pms.room.type",
@@ -157,7 +163,8 @@ class PmsReservation(models.Model):
related="folio_id.company_id", string="Company", store=True, readonly=True
)
pms_property_id = fields.Many2one(
"pms.property", default=_get_default_pms_property, #required=True
"pms.property",
default=_get_default_pms_property, # required=True
)
reservation_line_ids = fields.One2many(
"pms.reservation.line",
@@ -247,7 +254,11 @@ class PmsReservation(models.Model):
reservation_type = fields.Selection(
related="folio_id.reservation_type", default=lambda *a: "normal"
)
splitted = fields.Boolean("Splitted", compute="_compute_splitted", store=True,)
splitted = fields.Boolean(
"Splitted",
compute="_compute_splitted",
store=True,
)
credit_card_details = fields.Text(related="folio_id.credit_card_details")
cancelled_reason = fields.Selection(
@@ -283,14 +294,21 @@ class PmsReservation(models.Model):
)
overbooking = fields.Boolean("Is Overbooking", default=False)
reselling = fields.Boolean("Is Reselling", default=False)
nights = fields.Integer("Nights", compute="_computed_nights", store=True)
nights = fields.Integer("Nights", compute="_compute_nights", store=True)
channel_type = fields.Selection(
selection=[("direct", "Direct"), ("agency", "Agency"),],
selection=[
("direct", "Direct"),
("agency", "Agency"),
],
string="Sales Channel",
default="direct",
)
subchannel_direct = fields.Selection(
selection=[("door", "Door"), ("mail", "Mail"), ("phone", "Phone"),],
selection=[
("door", "Door"),
("mail", "Mail"),
("phone", "Phone"),
],
string="Direct Channel",
)
origin = fields.Char("Origin", compute="_compute_origin", store=True)
@@ -298,7 +316,7 @@ class PmsReservation(models.Model):
"Detail Origin", compute="_compute_detail_origin", store=True
)
folio_pending_amount = fields.Monetary(related="folio_id.pending_amount")
shared_folio = fields.Boolean(compute="_computed_shared")
shared_folio = fields.Boolean(compute="_compute_shared")
# Used to notify is the reservation folio has other reservations/services
email = fields.Char("E-mail", related="partner_id.email")
mobile = fields.Char("Mobile", related="partner_id.mobile")
@@ -323,14 +341,14 @@ class PmsReservation(models.Model):
default="no",
)
qty_to_invoice = fields.Float(
compute="_get_to_invoice_qty",
compute="_compute_get_to_invoice_qty",
string="To Invoice",
store=True,
readonly=True,
digits=("Product Unit of Measure"),
)
qty_invoiced = fields.Float(
compute="_get_invoice_qty",
compute="_compute_get_invoice_qty",
string="Invoiced",
store=True,
readonly=True,
@@ -468,14 +486,22 @@ class PmsReservation(models.Model):
lambda r: r.date == idate
)
if not old_line:
cmds.append((0, False, {"date": idate},))
reservation.reservation_line_ids -= reservation.reservation_line_ids.filtered_domain(
cmds.append(
(
0,
False,
{"date": idate},
)
)
reservation.reservation_line_ids -= (
reservation.reservation_line_ids.filtered_domain(
[
"|",
("date", ">=", reservation.checkout),
("date", "<", reservation.checkin),
]
)
)
reservation.reservation_line_ids = cmds
@api.depends("board_service_room_id")
@@ -483,7 +509,9 @@ class PmsReservation(models.Model):
for reservation in self:
board_services = []
old_board_lines = reservation.service_ids.filtered_domain(
[("is_board_service", "=", True),]
[
("is_board_service", "=", True),
]
)
if reservation.board_service_room_id:
board = self.env["pms.board.service.room.type"].browse(
@@ -522,7 +550,7 @@ class PmsReservation(models.Model):
if reservation.room_id:
if reservation.adults == 0:
reservation.adults = reservation.room_id.capacity
elif reservation.adults == False:
elif not reservation.adults:
reservation.adults = 0
@api.depends("reservation_line_ids", "reservation_line_ids.room_id")
@@ -541,7 +569,7 @@ class PmsReservation(models.Model):
that there is nothing to invoice. This is also hte default value
if the conditions of no other status is met.
- to invoice: we refer to the quantity to invoice of the line.
Refer to method `_get_to_invoice_qty()` for more information
Refer to method `_compute_get_to_invoice_qty()` for more information
on how this quantity is calculated.
- invoiced: the quantity invoiced is larger or equal to the
quantity ordered.
@@ -567,7 +595,7 @@ class PmsReservation(models.Model):
line.invoice_status = "no"
@api.depends("qty_invoiced", "nights", "folio_id.state")
def _get_to_invoice_qty(self):
def _compute_get_to_invoice_qty(self):
"""
Compute the quantity to invoice. If the invoice policy is order,
the quantity to invoice is calculated from the ordered quantity.
@@ -580,7 +608,7 @@ class PmsReservation(models.Model):
line.qty_to_invoice = 0
@api.depends("move_line_ids.move_id.state", "move_line_ids.quantity")
def _get_invoice_qty(self):
def _compute_get_invoice_qty(self):
"""
Compute the quantity invoiced. If case of a refund, the quantity
invoiced is decreased. We must check day per day and sum or
@@ -600,7 +628,7 @@ class PmsReservation(models.Model):
line.qty_invoiced = qty_invoiced
@api.depends("reservation_line_ids")
def _computed_nights(self):
def _compute_nights(self):
for res in self:
res.nights = len(res.reservation_line_ids)
@@ -657,7 +685,11 @@ class PmsReservation(models.Model):
)
else:
record.update(
{"price_tax": 0, "price_total": 0, "price_subtotal": 0,}
{
"price_tax": 0,
"price_total": 0,
"price_subtotal": 0,
}
)
# TODO: Use default values on checkin /checkout is empty
@@ -690,16 +722,21 @@ class PmsReservation(models.Model):
@api.constrains("reservation_type", "partner_id")
def _check_partner_reservation(self):
for reservation in self:
if reservation.reservation_type == "out" and \
reservation.partner_id != reservation.pms_property_id.partner_id.id:
raise models.ValidationError(_("The partner on out reservations must be a property partner"))
if (
reservation.reservation_type == "out"
and reservation.partner_id != reservation.pms_property_id.partner_id.id
):
raise models.ValidationError(
_("The partner on out reservations must be a property partner")
)
@api.constrains("closure_reason_id", "reservation_type")
def _check_partner_reservation(self):
def _check_clousure_reservation(self):
for reservation in self:
if reservation.closure_reason_id and \
reservation.reservation_type != 'out':
raise models.ValidationError(_("Only the out reservations can has a clousure reason"))
if reservation.closure_reason_id and reservation.reservation_type != "out":
raise models.ValidationError(
_("Only the out reservations can has a clousure reason")
)
# @api.onchange("checkin_partner_ids")
# def onchange_checkin_partner_ids(self):
@@ -811,7 +848,7 @@ class PmsReservation(models.Model):
# Business methods
def _computed_shared(self):
def _compute_shared(self):
# Has this reservation more charges associates in folio?,
# Yes?, then, this is share folio ;)
for record in self:
@@ -884,8 +921,6 @@ class PmsReservation(models.Model):
@param self: object pointer
"""
_logger.info("confirm")
pms_reserv_obj = self.env["pms.reservation"]
user = self.env["res.users"].browse(self.env.uid)
for record in self:
vals = {}
if record.checkin_partner_ids:
@@ -961,8 +996,6 @@ class PmsReservation(models.Model):
lines = self.env["pms.reservation.line"].search(domain)
reservations_dates = {}
for record in lines:
# kumari.net/index.php/programming/programmingcat/22-python-making-a-dictionary-of-lists-a-hash-of-arrays
# reservations_dates.setdefault(record.date,[]).append(record.reservation_id.room_type_id)
reservations_dates.setdefault(record.date, []).append(
[record.reservation_id, record.reservation_id.room_type_id]
)
@@ -994,8 +1027,6 @@ class PmsReservation(models.Model):
if reservation.channel_type in ["direct", "agency"]:
reservation.detail_origin = reservation.sudo().create_uid.name
# https://www.odoo.com/es_ES/forum/ayuda-1/question/calculated-fields-in-search-filter-possible-118501
def _search_checkin_partner_pending(self, operator, value):
self.ensure_one()
recs = self.search([]).filtered(lambda x: x.checkin_partner_pending_count > 0)

View File

@@ -84,14 +84,16 @@ class PmsReservationLine(models.Model):
_sql_constraints = [
(
"rule_availability",
"EXCLUDE (room_id WITH =, date WITH =) WHERE (occupies_availability = True)",
"EXCLUDE (room_id WITH =, date WITH =) \
WHERE (occupies_availability = True)",
"Room Occupied",
),
]
# Compute and Search methods
@api.depends(
"reservation_id.adults", "reservation_id.room_type_id",
"reservation_id.adults",
"reservation_id.room_type_id",
)
def _compute_room_id(self):
for line in self:
@@ -160,7 +162,7 @@ class PmsReservationLine(models.Model):
for line in self:
if (
line.reservation_id.state == "cancelled"
or line.reservation_id.overbooking == True
or line.reservation_id.overbooking
):
line.occupies_availability = False
else:

View File

@@ -22,7 +22,7 @@ class PmsRoom(models.Model):
for room in self:
name = room.name
if room.room_type_id:
name += ' [%s]' % room.room_type_id.code_type
name += " [%s]" % room.room_type_id.code_type
result.append((room.id, name))
return result

View File

@@ -1,7 +1,6 @@
# Copyright 2017 Alexandre Díaz
# Copyright 2017 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import timedelta
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
@@ -51,7 +50,10 @@ class PmsRoomType(models.Model):
string="Room Type Amenities",
help="List of Amenities.",
)
code_type = fields.Char("Code", required=True,)
code_type = fields.Char(
"Code",
required=True,
)
shared_room = fields.Boolean(
"Shared Room", default=False, help="This room type is reservation by beds"
)
@@ -91,7 +93,10 @@ class PmsRoomType(models.Model):
def create(self, vals):
""" Add room types as not purchase services. """
vals.update(
{"purchase_ok": False, "type": "service",}
{
"purchase_ok": False,
"type": "service",
}
)
return super().create(vals)
@@ -119,27 +124,30 @@ class PmsRoomType(models.Model):
Return Dict Code Room Types: subdict with day, discount, price
"""
vals = {}
room_type_ids = kwargs.get("room_type_ids", False)
room_types = (
self.env["pms.room.type"].browse(room_type_ids)
if room_type_ids
else self.env["pms.room.type"].search([])
)
# room_type_ids = kwargs.get("room_type_ids", False)
# room_types = (
# self.env["pms.room.type"].browse(room_type_ids)
# if room_type_ids
# else self.env["pms.room.type"].search([])
# )
date_from = kwargs.get("date_from", False)
days = kwargs.get("days", False)
discount = kwargs.get("discount", False)
if not date_from or not days:
raise ValidationError(_("Date From and days are mandatory"))
partner_id = kwargs.get("partner_id", False)
partner = self.env["res.partner"].browse(partner_id)
pricelist_id = kwargs.get(
"pricelist_id",
partner.property_product_pricelist.id
and partner.property_product_pricelist.id
or self.env.user.pms_property_id.default_pricelist_id.id,
)
# partner = self.env["res.partner"].browse(partner_id)
# pricelist_id = kwargs.get(
# "pricelist_id",
# partner.property_product_pricelist.id
# and partner.property_product_pricelist.id
# or self.env.user.pms_property_id.default_pricelist_id.id,
# )
vals.update(
{"partner_id": partner_id if partner_id else False, "discount": discount,}
{
"partner_id": partner_id if partner_id else False,
"discount": discount,
}
)
rate_vals = {}
# TODO: Now it is computed field, We need other way to return rates
@@ -155,7 +163,9 @@ class PmsRoomType(models.Model):
# rate_vals.update(
# {
# room_type.id: [
# item[2] for item in room_vals["reservation_line_ids"] if item[2]
# item[2] for item in room_vals[
# "reservation_line_ids"
# ] if item[2]
# ]
# }
# )

View File

@@ -4,8 +4,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import timedelta
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo import api, fields, models
class PmsRoomTypeAvailability(models.Model):
@@ -62,7 +61,9 @@ class PmsRoomTypeAvailability(models.Model):
self, checkin, checkout, room_type_id=False, current_lines=False
):
domain = self._get_domain_reservations_occupation(
dfrom=checkin, dto=checkout - timedelta(1), current_lines=current_lines,
dfrom=checkin,
dto=checkout - timedelta(1),
current_lines=current_lines,
)
reservation_lines = self.env["pms.reservation.line"].search(domain)
reservations_rooms = reservation_lines.mapped("room_id.id")

View File

@@ -5,7 +5,7 @@ import logging
from datetime import timedelta
from odoo import _, api, fields, models
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, float_compare, float_is_zero
from odoo.tools import float_compare, float_is_zero
_logger = logging.getLogger(__name__)
@@ -43,7 +43,10 @@ class PmsService(models.Model):
# Fields declaration
name = fields.Char(
"Service description", compute="_compute_name", store=True, readonly=False,
"Service description",
compute="_compute_name",
store=True,
readonly=False,
)
product_id = fields.Many2one(
"product.product", "Service", ondelete="restrict", required=True
@@ -91,7 +94,10 @@ class PmsService(models.Model):
state = fields.Selection(related="folio_id.state")
per_day = fields.Boolean(related="product_id.per_day", related_sudo=True)
product_qty = fields.Integer(
"Quantity", compute="_compute_product_qty", store=True, readonly=False,
"Quantity",
compute="_compute_product_qty",
store=True,
readonly=False,
)
is_board_service = fields.Boolean()
# Non-stored related field to allow portal user to
@@ -130,14 +136,14 @@ class PmsService(models.Model):
)
discount = fields.Float(string="Discount (%)", digits=("Discount"), default=0.0)
qty_to_invoice = fields.Float(
compute="_get_to_invoice_qty",
compute="_compute_get_to_invoice_qty",
string="To Invoice",
store=True,
readonly=True,
digits=("Product Unit of Measure"),
)
qty_invoiced = fields.Float(
compute="_get_invoice_qty",
compute="_compute_get_invoice_qty",
string="Invoiced",
store=True,
readonly=True,
@@ -203,18 +209,27 @@ class PmsService(models.Model):
if idate in [
line.date for line in service.service_line_ids
]:
# REVIEW: If the date is already cached (otherwise double the date)
# REVIEW: If the date is already
# cached (otherwise double the date)
pass
elif not old_line:
lines.append(
(0, False, {"date": idate, "day_qty": day_qty,})
(
0,
False,
{
"date": idate,
"day_qty": day_qty,
},
)
)
else:
lines.append((4, old_line.id))
move_day = 0
if consumed_on == "after":
move_day = 1
service.service_line_ids -= service.service_line_ids.filtered_domain(
service.service_line_ids -= (
service.service_line_ids.filtered_domain(
[
"|",
(
@@ -229,6 +244,7 @@ class PmsService(models.Model):
),
]
)
)
_logger.info(service)
_logger.info(lines)
service.service_line_ids = lines
@@ -239,7 +255,10 @@ class PmsService(models.Model):
(
0,
False,
{"date": fields.Date.today(), "day_qty": day_qty,},
{
"date": fields.Date.today(),
"day_qty": day_qty,
},
)
]
else:
@@ -250,7 +269,10 @@ class PmsService(models.Model):
(
0,
False,
{"date": fields.Date.today(), "day_qty": day_qty,},
{
"date": fields.Date.today(),
"day_qty": day_qty,
},
)
]
else:
@@ -258,7 +280,6 @@ class PmsService(models.Model):
def _search_old_lines(self, date):
self.ensure_one()
old_lines = self.env["pms.service.line"]
if isinstance(self._origin.id, int):
old_line = self._origin.service_line_ids.filtered(lambda r: r.date == date)
return old_line
@@ -366,7 +387,7 @@ class PmsService(models.Model):
return False
@api.depends("qty_invoiced", "product_qty", "folio_id.state")
def _get_to_invoice_qty(self):
def _compute_get_to_invoice_qty(self):
"""
Compute the quantity to invoice. If the invoice policy is order,
the quantity to invoice is calculated from the ordered quantity.
@@ -379,7 +400,7 @@ class PmsService(models.Model):
line.qty_to_invoice = 0
@api.depends("move_line_ids.move_id.state", "move_line_ids.quantity")
def _get_invoice_qty(self):
def _compute_get_invoice_qty(self):
"""
Compute the quantity invoiced. If case of a refund,
the quantity invoiced is decreased. Note that this is the case only
@@ -398,7 +419,7 @@ class PmsService(models.Model):
invoice_line.quantity, line.product_id.uom_id
)
elif invoice_line.move_id.type == "out_refund":
qty_invoiced -= move_line.uom_id._compute_quantity(
qty_invoiced -= invoice_line.uom_id._compute_quantity(
invoice_line.quantity, line.product_id.uom_id
)
line.qty_invoiced = qty_invoiced
@@ -412,7 +433,7 @@ class PmsService(models.Model):
This is also hte default value if the conditions of no other
status is met.
- to invoice: we refer to the quantity to invoice of the line.
Refer to method `_get_to_invoice_qty()` for more information on
Refer to method `_compute_get_to_invoice_qty()` for more information on
how this quantity is calculated.
- upselling: this is possible only for a product invoiced on ordered
quantities for which we delivered more than expected.

View File

@@ -33,7 +33,10 @@ class PmsSharedRoom(models.Model):
help="At which floor the room is located.",
)
bed_ids = fields.One2many(
"pms.room", "shared_room_id", readonly=True, ondelete="restrict",
"pms.room",
"shared_room_id",
readonly=True,
ondelete="restrict",
)
active = fields.Boolean("Active", default=True)
sequence = fields.Integer("Sequence", required=True)
@@ -85,29 +88,39 @@ class PmsSharedRoom(models.Model):
@api.constrains("active")
def _constrain_active(self):
self.bed_ids.write(
{"active": self.active,}
{
"active": self.active,
}
)
@api.constrains("room_type_id")
def _constrain_room_type_id(self):
self.bed_ids.write(
{"room_type_id": self.room_type_id.id,}
{
"room_type_id": self.room_type_id.id,
}
)
@api.constrains("floor_id")
def _constrain_floor_id(self):
self.bed_ids.write(
{"floor_id": self.floor_id.id,}
{
"floor_id": self.floor_id.id,
}
)
@api.constrains("sequence")
def _constrain_sequence(self):
self.bed_ids.write(
{"sequence": self.sequence,}
{
"sequence": self.sequence,
}
)
@api.constrains("descrition_sale")
def _constrain_descrition_sale(self):
self.bed_ids.write(
{"description_sale": self.descrition_sale,}
{
"description_sale": self.descrition_sale,
}
)

View File

@@ -49,7 +49,10 @@ class ResPartner(models.Model):
("mobile", operator, name),
("email", operator, name),
]
partners = self.search(domain + args, limit=limit,)
partners = self.search(
domain + args,
limit=limit,
)
res = partners.name_get()
if limit:
limit_rest = limit - len(partners)

View File

@@ -19,9 +19,11 @@
t-field="doc.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'
/>
<p t-if="doc.partner_id.vat"><t
t-esc="doc.company_id.country_id.vat_label or 'TIN'"
/>: <span t-field="doc.partner_id.vat" /></p>
<p t-if="doc.partner_id.vat">
<t t-esc="doc.company_id.country_id.vat_label or 'TIN'" />
:
<span t-field="doc.partner_id.vat" />
</p>
</div>
</div>
<h2>
@@ -75,16 +77,22 @@
t-if="display_discount"
class="text-right"
groups="sale.group_discount_per_so_line"
>Disc.(%)</th>
>
Disc.(%)
</th>
<th class="text-right">Taxes</th>
<th
class="text-right"
groups="sale.group_show_price_subtotal"
>Amount</th>
>
Amount
</th>
<th
class="text-right price_tax_included"
groups="sale.group_show_price_total"
>Total Price</th>
>
Total Price
</th>
</tr>
</thead>
<tbody class="sale_tbody">
@@ -196,7 +204,8 @@
/>
</td>
</tr>
-<t
-
<t
t-foreach="doc._get_tax_amount_by_group()"
t-as="amount_by_group"
>
@@ -206,8 +215,9 @@
>
<td>
<span t-esc="amount_by_group[0]" />
<span>&amp;nbsp;<span
>on</span>&amp;nbsp;<t
<span>&amp;nbsp;<span>
on
</span>&amp;nbsp;<t
t-esc="amount_by_group[2]"
t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'
/></span>

View File

@@ -21,17 +21,17 @@
<field name="name">PMS Folio Company Rule</field>
<field name="model_id" ref="model_pms_folio" />
<field name="global" eval="True" />
<field
name="domain_force"
>['|',('company_id','=',False),('company_id', 'in', company_ids)]</field>
<field name="domain_force">
['|',('company_id','=',False),('company_id', 'in', company_ids)]
</field>
</record>
<record id="pms_reservation_company_rule" model="ir.rule">
<field name="name">PMS Reservation Company Rule</field>
<field name="model_id" ref="model_pms_reservation" />
<field name="global" eval="True" />
<field
name="domain_force"
>['|',('company_id','=',False),('company_id', 'in', company_ids)]</field>
<field name="domain_force">
['|',('company_id','=',False),('company_id', 'in', company_ids)]
</field>
</record>
<!-- Property Rules -->
<!--<record id="pms_folio_property_rule" model="ir.rule">

View File

@@ -8,12 +8,12 @@ odoo.define("web.SwitchPmsMenu", function(require) {
*/
var config = require("web.config");
var core = require("web.core");
// Var core = require("web.core");
var session = require("pms.session");
var SystrayMenu = require("web.SystrayMenu");
var Widget = require("web.Widget");
var _t = core._t;
// Var _t = core._t;
var SwitchPmsMenu = Widget.extend({
template: "SwitchPmsMenu",

View File

@@ -6,14 +6,17 @@
<div class="row">
<div class="col-sm-4">
<t t-esc="object.pms_property_id.street" />
<t t-if="object.pms_property_id.street2">- <t
t-esc="object.pms_property_id.street2"
/></t> <br />
<t t-if="object.pms_property_id.street2">
-
<t t-esc="object.pms_property_id.street2" />
</t>
<br />
<t t-esc="object.pms_property_id.zip" />
<t t-esc="object.pms_property_id.city" />,
<t t-esc="object.pms_property_id.state_id.name" /> <br />
<t t-esc="object.pms_property_id.city" />
,
<t t-esc="object.pms_property_id.state_id.name" />
<br />
<t t-esc="object.pms_property_id.country_id.name" />
</div>
<div class="col-sm-4">
<i class="glyphicon glyphicon-phone-alt" />
@@ -38,9 +41,10 @@
<th scope="col">Room Type</th>
<th scope="col">Checkin</th>
<th scope="col">Nights</th>
<th scope="col">Price <t
t-esc="object.currency_id.name"
/></th>
<th scope="col">
Price
<t t-esc="object.currency_id.name" />
</th>
</tr>
</thead>
<tbody>
@@ -71,19 +75,30 @@
<template id="template_reservation">
<div class="row" style="padding-top: 20px;">
<div class="col-sm-12">
<p>Dear <span t-field="object.partner_id.name" />,<br />
Thank you for your reservation.</p>
<p>Here is your confirmation code: <b t-esc="object.name" />.
Keep this code for any question about your booking order.</p>
<p>
Dear
<span t-field="object.partner_id.name" />
,
<br />
Thank you for your reservation.
</p>
<p>
Here is your confirmation code:
<b t-esc="object.name" />
.
Keep this code for any question about your booking order.
</p>
<p>You can find the reservation details below:</p>
</div>
</div>
<t t-call="pms.template_reservation_details" />
<div class="row" style="padding-top: 20px;">
<div class="col-sm-12">
If you have any questions, please do not hesitate to contact with the property's staff. <br
/>
Looking forward to seeing you at our property, <br />
If you have any questions, please do not hesitate to contact with
the property's staff.
<br />
Looking forward to seeing you at our property,
<br />
Best regards.
</div>
</div>
@@ -91,8 +106,10 @@
<template id="template_footer">
<div class="row" style="padding-top: 20px;">
<div class="col-sm-12">
Privacy Policy: We use your Personal Information only for managing your reservation. By using the property, you
agree to the collection and use of information in accordance with this policy.
Privacy Policy: We use your Personal Information only for managing
your reservation. By using the property, you
agree to the collection and use of information in accordance with this
policy.
</div>
</div>
</template>
@@ -128,9 +145,9 @@
<field name="email_to">${(object.email or '')|safe}</field>
<field name="partner_to">${(object.partner_id.id or '')}</field>
<field name="lang">${object.partner_id.lang}</field>
<field
name="subject"
>Your reservation ${object.name} has been confirmed by the property staff</field>
<field name="subject">
Your reservation ${object.name} has been confirmed by the property staff
</field>
<field name="auto_delete" eval="True" />
<field name="body_type">qweb</field>
<field name="body_view_id" ref="pms.template_reservation_confirmed" />

View File

@@ -20,11 +20,8 @@
#
##############################################################################
import logging
from datetime import timedelta
from odoo import api, fields
from odoo.tests import common
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
_logger = logging.getLogger(__name__)

View File

@@ -5,25 +5,17 @@
<field name="inherit_id" ref="base.sequence_view" />
<field name="arch" type="xml">
<xpath expr="//field[@name='company_id']" position="after">
<field
string="Property"
name="pms_property_id"
/>
<field string="Property" name="pms_property_id" />
</xpath>
</field>
</record>
<record id="ir_sequence_view_tree" model="ir.ui.view">
<field name="model">ir.sequence</field>
<field name="inherit_id" ref="base.sequence_view_tree" />
<field name="arch" type="xml">
<xpath expr="//field[@name='company_id']" position="after">
<field
string="Property"
name="pms_property_id"
/>
<field string="Property" name="pms_property_id" />
</xpath>
</field>
</record>
</odoo>

View File

@@ -178,7 +178,10 @@
role="alert"
style="margin-bottom:0px;"
>
these are the billing information associated with the booking client or the company (if a company is assigned). If you want to bill an independent contact, you can select it in the billing assistant
these are the billing information associated with the
booking client or the company (if a company is
assigned). If you want to bill an independent contact,
you can select it in the billing assistant
</div>
<group>
<field
@@ -366,6 +369,7 @@
<field name="model">pms.folio</field>
<field name="arch" type="xml">
<graph type="bar">
</graph>
</field>
</record>

View File

@@ -14,6 +14,7 @@
<notebook>
<page string="General Information" name="property_general">
<group>
</group>
</page>
<page string="Settings" name="property_settings">

View File

@@ -41,10 +41,7 @@
class="oe_highlight"
type="object"
/>
<field
name="state"
widget="statusbar"
/>
<field name="state" widget="statusbar" />
</header>
<div
class="alert alert-info"
@@ -52,7 +49,8 @@
style="margin-bottom:0px;"
attrs="{'invisible': ['|',('shared_folio','=',False),('splitted', '=', True)]}"
>
This reservation has other reservantions and/or services in the folio, you can check it in the
This reservation has other reservantions and/or services in the
folio, you can check it in the
<bold>
<button
class="alert-link"
@@ -68,7 +66,8 @@
style="margin-bottom:0px;"
attrs="{'invisible': [('splitted','=',False)]}"
>
This reservation is part of splitted reservation!, you can check it in the
This reservation is part of splitted reservation!, you can check it
in the
<bold>
<button
class="alert-link"
@@ -151,11 +150,15 @@
<span
class="label label-danger"
attrs="{'invisible': [('state', 'not in', ('cancelled'))]}"
>Cancelled Reservation!</span>
>
Cancelled Reservation!
</span>
<span
class="label label-warning"
attrs="{'invisible': [('overbooking', '=', False)]}"
>OverBooking!</span>
>
OverBooking!
</span>
<h1>
<field
name="room_id"
@@ -526,22 +529,25 @@
</form>
</field>
</record>
<!-- Calendar -->
<record id="pms_reservation_view_calendar" model="ir.ui.view">
<field name="name">pms.reservation.view.calendar</field>
<field name="model">pms.reservation</field>
<field name="arch" type="xml">
<calendar date_start="checkin" date_stop="checkout"
string="Reservations" quick_add="False"
mode="month" scales="month,year">
<calendar
date_start="checkin"
date_stop="checkout"
string="Reservations"
quick_add="False"
mode="month"
scales="month,year"
>
<field name="partner_id" avatar_field="image_128" />
<field name="room_type_id" />
<field name="room_id" />
</calendar>
</field>
</record>
<!-- Form view Checkin Partners from reservation -->
<record model="ir.ui.view" id="pms_reservation_checkin_view_form">
<field name="name">pms.reservation.checkin.form</field>
@@ -562,7 +568,8 @@
style="margin-bottom:0px;"
attrs="{'invisible': ['|',('shared_folio','=',False),('splitted', '=', True)]}"
>
This reservation has other reservantions and/or services in the folio, you can check it in the
This reservation has other reservantions and/or services in the
folio, you can check it in the
<bold>
<button
class="alert-link"
@@ -578,11 +585,15 @@
<span
class="label label-danger"
attrs="{'invisible': [('state', 'not in', ('cancelled'))]}"
>Cancelled Reservation!</span>
>
Cancelled Reservation!
</span>
<span
class="label label-warning"
attrs="{'invisible': [('overbooking', '=', False)]}"
>OverBooking!</span>
>
OverBooking!
</span>
<h2>
<field
name="room_id"
@@ -607,7 +618,8 @@
attrs="{'invisible': [('reservation_type','not in',('staff'))]}"
/> -->
<h3>
From <span class="fa-sign-in" style="margin: 5px;" />
From
<span class="fa-sign-in" style="margin: 5px;" />
<field
name="checkin"
style="margin-right: 10px;"
@@ -642,15 +654,16 @@
<field name="name">pms.reservation.tree</field>
<field name="model">pms.reservation</field>
<field name="arch" type="xml">
<tree
string="Reservation"
multi_edit="1" sample="1"
class="o_sale_order"
>
<tree string="Reservation" multi_edit="1" sample="1" class="o_sale_order">
<field name="splitted" invisible="1" />
<field name="pricelist_id" invisible="1" />
<field name="room_id" options="{'no_create': True,'no_open': True}" />
<field name="checkin" widget="daterange" class="oe_inline" options="{'related_end_date': 'checkout'}"/>
<field
name="checkin"
widget="daterange"
class="oe_inline"
options="{'related_end_date': 'checkout'}"
/>
<field name="checkout" widget="date" />
<field name="nights" />
<button
@@ -666,7 +679,11 @@
<field name="adults" string="Persons" />
<field name="overbooking" invisible="1" />
<field name="activity_ids" widget="list_activity" optional="show" />
<field name="create_uid" optional="show" widget="many2one_avatar_user"/>
<field
name="create_uid"
optional="show"
widget="many2one_avatar_user"
/>
<field name="origin" />
<field name="checkin_partner_ids" invisible="1" />
<field name="to_assign" invisible="1" />
@@ -675,8 +692,19 @@
<field name="price_subtotal" invisible="1" />
<field name="price_total" />
<field name="folio_pending_amount" string="Folio Pending Amount" />
<field name="company_id" groups="base.group_multi_company" optional="show" readonly="1" />
<field name="state" decoration-success="state == 'done'" decoration-info="state == 'confirm'" widget="badge" optional="show"/>
<field
name="company_id"
groups="base.group_multi_company"
optional="show"
readonly="1"
/>
<field
name="state"
decoration-success="state == 'done'"
decoration-info="state == 'confirm'"
widget="badge"
optional="show"
/>
</tree>
</field>
</record>
@@ -866,7 +894,12 @@
<searchpanel>
<field name="room_type_id" string="Room Type" enable_counters="1" />
<field name="pricelist_id" string="Pricelist" enable_counters="1" />
<field name="state" string="State" enable_counters="1" select="multi" />
<field
name="state"
string="State"
enable_counters="1"
select="multi"
/>
</searchpanel>
</search>
</field>

View File

@@ -119,13 +119,15 @@
<field name="name" />
</strong>
</li>
<li class="mb4">Room Type: <field
name="room_type_id"
/></li>
<li class="mb4">
Room Type:
<field name="room_type_id" />
</li>
<li class="badge mb4">
<strong>Capacity <field
name="capacity"
/></strong>
<strong>
Capacity
<field name="capacity" />
</strong>
</li>
</ul>
</div>

View File

@@ -74,11 +74,15 @@
<field name="name" />
</strong>
</li>
<li class="mb4">Room Type: <field
name="room_type_id"
/></li>
<li class="mb4">
Room Type:
<field name="room_type_id" />
</li>
<li class="badge mb4">
<strong>Beds <field name="beds" /></strong>
<strong>
Beds
<field name="beds" />
</strong>
</li>
</ul>
</div>