diff --git a/.copier-answers.yml b/.copier-answers.yml new file mode 100644 index 000000000..17fdf5bea --- /dev/null +++ b/.copier-answers.yml @@ -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: [] diff --git a/.gitignore b/.gitignore index 416d59a46..818770fb1 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ diff --git a/.isort.cfg b/.isort.cfg index d2e2e305f..7683badfa 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -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 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 749967bb6..b1dce7938 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -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 diff --git a/.pylintrc b/.pylintrc index 925ffb947..acbffe7b4 100644 --- a/.pylintrc +++ b/.pylintrc @@ -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 diff --git a/.pylintrc-mandatory b/.pylintrc-mandatory index d3a8e98b2..1d979ab46 100644 --- a/.pylintrc-mandatory +++ b/.pylintrc-mandatory @@ -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, diff --git a/.travis.yml b/.travis.yml index 83d22cf69..c0f6df9b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..9ac71fee4 --- /dev/null +++ b/CONTRIBUTING.md @@ -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 + + + +This project does not have specific coding guidelines. diff --git a/LICENSE b/LICENSE index 58777e31a..be3f7b28e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ -GNU AFFERO GENERAL PUBLIC LICENSE + GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. 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) 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 . + along with this program. If not, see . 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 -. +. diff --git a/README.md b/README.md index 786053458..724ec1ea6 100644 --- a/README.md +++ b/README.md @@ -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. + -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. + -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. + -Contributing ------------- -Do you want to contribute? Please, do not hesitate to contact any of the current contributors :) \ No newline at end of file +[//]: # (addons) + +This part will be replaced when running the oca-gen-addons-table script from OCA/maintainer-tools. + +[//]: # (end addons) + + + +## 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. diff --git a/oca_dependencies.txt b/oca_dependencies.txt new file mode 100644 index 000000000..ca3c726ba --- /dev/null +++ b/oca_dependencies.txt @@ -0,0 +1 @@ +# See https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#oca_dependencies-txt diff --git a/pms/__init__.py b/pms/__init__.py index 773da928d..3f3f8679b 100644 --- a/pms/__init__.py +++ b/pms/__init__.py @@ -1,4 +1,5 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import models -#from . import wizard + +# from . import wizard diff --git a/pms/__manifest__.py b/pms/__manifest__.py index e0a4669cb..5f5e05f6d 100644 --- a/pms/__manifest__.py +++ b/pms/__manifest__.py @@ -19,9 +19,9 @@ "depends": [ "base", "mail", - #"account_payment_return", + # "account_payment_return", # "partner_firstname", - #"email_template_qweb", + # "email_template_qweb", "sale", ], "data": [ @@ -32,7 +32,7 @@ "data/pms_data.xml", "report/pms_folio.xml", "report/pms_folio_templates.xml", - #"templates/pms_email_template.xml", + # "templates/pms_email_template.xml", "views/general.xml", "data/menus.xml", "views/pms_amenity_views.xml", @@ -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",], } diff --git a/pms/data/pms_data.xml b/pms/data/pms_data.xml index 687a7ec32..e51f197dd 100644 --- a/pms/data/pms_data.xml +++ b/pms/data/pms_data.xml @@ -3,9 +3,17 @@ + + + + + + + + @@ -26,17 +34,5 @@ https://www.commitsun.com - - - - - - - - - - - - diff --git a/pms/demo/pms_folio.xml b/pms/demo/pms_folio.xml index 6e3b0db7f..10a4c7108 100644 --- a/pms/demo/pms_folio.xml +++ b/pms/demo/pms_folio.xml @@ -312,7 +312,7 @@ /> - + normal - + normal - + - + - + - + - + - + + - + - + Maintenance - Used for closing of rooms which require a maintenance. You can specify the reason in the own reservation. + + Used for closing of rooms which require a maintenance. You can specify + the reason in the own reservation. + VIP Privacy - Used for closing of rooms for extra privacy. + + Used for closing of rooms for extra privacy. + diff --git a/pms/demo/pms_reservation.xml b/pms/demo/pms_reservation.xml index 91a86d84b..56a57d5d6 100644 --- a/pms/demo/pms_reservation.xml +++ b/pms/demo/pms_reservation.xml @@ -10,7 +10,6 @@ - "out" @@ -61,7 +60,6 @@ - @@ -71,7 +69,6 @@ - @@ -81,7 +78,6 @@ - @@ -108,7 +104,6 @@ - @@ -127,7 +122,6 @@ - @@ -163,7 +157,6 @@ - @@ -198,7 +191,7 @@ 2 - + @@ -262,7 +255,6 @@ - @@ -270,7 +262,6 @@ - @@ -278,7 +269,6 @@ - diff --git a/pms/models/__init__.py b/pms/models/__init__.py index 28ee389de..8f3a54565 100644 --- a/pms/models/__init__.py +++ b/pms/models/__init__.py @@ -4,7 +4,8 @@ from . import ir_http from . import ir_sequence -#from . import payment_return + +# from . import payment_return from . import pms_board_service_room_type from . import pms_property from . import res_users @@ -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 diff --git a/pms/models/account_move.py b/pms/models/account_move.py index 71040d312..f8f01adbb 100644 --- a/pms/models/account_move.py +++ b/pms/models/account_move.py @@ -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: diff --git a/pms/models/account_payment.py b/pms/models/account_payment.py index eab93f996..ca7f2f06f 100644 --- a/pms/models/account_payment.py +++ b/pms/models/account_payment.py @@ -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,17 +129,14 @@ class AccountPayment(models.Model): 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 \ + 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.amount, + pay.currency_id.symbol, + pay.communication, + pay.journal_id.name, ) pay.folio_id.message_post(subject=_("Payment"), body=msg) diff --git a/pms/models/ir_http.py b/pms/models/ir_http.py index 1593c1923..009c42652 100644 --- a/pms/models/ir_http.py +++ b/pms/models/ir_http.py @@ -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 diff --git a/pms/models/mail_compose_message.py b/pms/models/mail_compose_message.py index c38b23ae5..62bbaad3b 100644 --- a/pms/models/mail_compose_message.py +++ b/pms/models/mail_compose_message.py @@ -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") ): + # TODO: WorkFlow Mails 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 + 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) diff --git a/pms/models/payment_return.py b/pms/models/payment_return.py index 6c8235138..c26d878d7 100644 --- a/pms/models/payment_return.py +++ b/pms/models/payment_return.py @@ -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): diff --git a/pms/models/pms_board_service_room_type.py b/pms/models/pms_board_service_room_type.py index d70440a09..24cbeb3c1 100644 --- a/pms/models/pms_board_service_room_type.py +++ b/pms/models/pms_board_service_room_type.py @@ -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")) diff --git a/pms/models/pms_folio.py b/pms/models/pms_folio.py index b58d8719b..1032e96e3 100644 --- a/pms/models/pms_folio.py +++ b/pms/models/pms_folio.py @@ -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. """ @@ -431,11 +444,9 @@ class PmsFolio(models.Model): } ) - #TODO: Add return_ids to depends - @api.depends( - "amount_total", "payment_ids", "reservation_type", "state" - ) - def compute_amount(self): + # TODO: Add return_ids to depends + @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? @@ -545,13 +558,17 @@ class PmsFolio(models.Model): # ORM Overrides @api.model def create(self, vals): - #TODO: Make sequence from property, not company + # 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") + # 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") 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 diff --git a/pms/models/pms_property.py b/pms/models/pms_property.py index 07d28a870..5f45beb2a 100644 --- a/pms/models/pms_property.py +++ b/pms/models/pms_property.py @@ -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") diff --git a/pms/models/pms_reservation.py b/pms/models/pms_reservation.py index b33d8dadb..c0fff19bc 100644 --- a/pms/models/pms_reservation.py +++ b/pms/models/pms_reservation.py @@ -43,7 +43,7 @@ class PmsReservation(models.Model): def _get_default_arrival_hour(self): folio = False - #TODO: Change by property env variable (like company) + # TODO: Change by property env variable (like company) default_arrival_hour = self.env.user.pms_property_id.default_arrival_hour if "folio_id" in self._context: folio = self.env["pms.folio"].search( @@ -56,7 +56,7 @@ class PmsReservation(models.Model): def _get_default_departure_hour(self): folio = False - #TODO: Change by property env variable (like company) + # TODO: Change by property env variable (like company) default_departure_hour = self.env.user.pms_property_id.default_departure_hour if "folio_id" in self._context: folio = self.env["pms.folio"].search( @@ -69,7 +69,7 @@ class PmsReservation(models.Model): @api.model def _get_default_pms_property(self): - #TODO: Change by property env variable (like company) + # TODO: Change by property env variable (like company) return self.env.user.pms_property_id def _get_default_segmentation(self): @@ -103,7 +103,7 @@ class PmsReservation(models.Model): compute="_compute_name", store=True, readonly=False, - #required=True, + # required=True, ) priority = fields.Integer(compute="_compute_priority", store="True", index=True) room_id = fields.Many2one( @@ -114,23 +114,29 @@ class PmsReservation(models.Model): compute="_compute_room_id", store=True, readonly=False, - #required=True, + # required=True, 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", string="Room Type", track_visibility="onchange", - #required=True, + # required=True, compute="_compute_room_type_id", store=True, readonly=False, @@ -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,13 +486,21 @@ 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( - [ - "|", - ("date", ">=", reservation.checkout), - ("date", "<", reservation.checkin), - ] + 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 @@ -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( @@ -515,14 +543,14 @@ class PmsReservation(models.Model): # TODO: Warning change de pricelist? reservation.pricelist_id = pricelist_id - #REVIEW: Dont run with set room_type_id -> room_id(compute)-> No set adults¿? + # REVIEW: Dont run with set room_type_id -> room_id(compute)-> No set adults¿? @api.depends("room_id") def _compute_adults(self): for reservation in self: 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) diff --git a/pms/models/pms_reservation_line.py b/pms/models/pms_reservation_line.py index a0bf077ac..ed39c49dd 100644 --- a/pms/models/pms_reservation_line.py +++ b/pms/models/pms_reservation_line.py @@ -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: diff --git a/pms/models/pms_room.py b/pms/models/pms_room.py index 374ebbc24..b1ed74fe0 100644 --- a/pms/models/pms_room.py +++ b/pms/models/pms_room.py @@ -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 diff --git a/pms/models/pms_room_type.py b/pms/models/pms_room_type.py index a3c0919d3..27774277b 100644 --- a/pms/models/pms_room_type.py +++ b/pms/models/pms_room_type.py @@ -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] # ] # } # ) diff --git a/pms/models/pms_room_type_availability.py b/pms/models/pms_room_type_availability.py index 106f7e17b..e4e16f332 100644 --- a/pms/models/pms_room_type_availability.py +++ b/pms/models/pms_room_type_availability.py @@ -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") diff --git a/pms/models/pms_service.py b/pms/models/pms_service.py index 6a1aed1bc..5eee63861 100644 --- a/pms/models/pms_service.py +++ b/pms/models/pms_service.py @@ -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,31 +209,41 @@ 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( - [ - "|", - ( - "date", - "<", - reservation.checkin + timedelta(move_day), - ), - ( - "date", - ">=", - reservation.checkout + timedelta(move_day), - ), - ] + service.service_line_ids -= ( + service.service_line_ids.filtered_domain( + [ + "|", + ( + "date", + "<", + reservation.checkin + timedelta(move_day), + ), + ( + "date", + ">=", + reservation.checkout + timedelta(move_day), + ), + ] + ) ) _logger.info(service) _logger.info(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. diff --git a/pms/models/pms_shared_room.py b/pms/models/pms_shared_room.py index f5f6854f5..86494bbb5 100644 --- a/pms/models/pms_shared_room.py +++ b/pms/models/pms_shared_room.py @@ -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, + } ) diff --git a/pms/models/res_partner.py b/pms/models/res_partner.py index 5eae343e5..1c135639e 100644 --- a/pms/models/res_partner.py +++ b/pms/models/res_partner.py @@ -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) diff --git a/pms/report/pms_folio_templates.xml b/pms/report/pms_folio_templates.xml index e9bca33d7..dd0f15b47 100644 --- a/pms/report/pms_folio_templates.xml +++ b/pms/report/pms_folio_templates.xml @@ -19,14 +19,16 @@ t-field="doc.partner_id" t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}' /> -

:

+

+ + : + +

- Order # - Quotation # + Order # + Quotation #

@@ -75,16 +77,22 @@ t-if="display_discount" class="text-right" groups="sale.group_discount_per_so_line" - >Disc.(%) + > + Disc.(%) + Taxes Amount + > + Amount + Total Price + > + Total Price + @@ -182,7 +190,7 @@ class="table table-condensed" style="min-width: 200px;max-width: 350px;" > - @@ -196,7 +204,8 @@ /> - - @@ -206,8 +215,9 @@ > - &nbsp;on&nbsp;&nbsp; + on + &nbsp; @@ -232,7 +242,7 @@ - + Total @@ -243,7 +253,7 @@ /> - + Pending Payment @@ -254,7 +264,7 @@ /> - +
diff --git a/pms/security/pms_security.xml b/pms/security/pms_security.xml index 81ef4a969..17347f9e6 100644 --- a/pms/security/pms_security.xml +++ b/pms/security/pms_security.xml @@ -21,17 +21,17 @@ PMS Folio Company Rule - ['|',('company_id','=',False),('company_id', 'in', company_ids)] + + ['|',('company_id','=',False),('company_id', 'in', company_ids)] +
PMS Reservation Company Rule - ['|',('company_id','=',False),('company_id', 'in', company_ids)] + + ['|',('company_id','=',False),('company_id', 'in', company_ids)] + pms.reservation.view.calendar pms.reservation - - - - + + + + - pms.reservation.checkin.form @@ -562,8 +568,9 @@ 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 +