Repository: OCA/vertical-abbey (language: python)

Issue:
Add module icons



Discussion / hints:

Fix patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 29e2f619..626b1c4b 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -5,7 +5,7 @@ exclude: |
   # Files and folders generated by bots, to avoid loops
   ^setup/|/static/description/index\.html$|
   # We don't want to mess with tool-generated files
-  .svg$|/tests/([^/]+/)?cassettes/|
+  .svg$|/tests/([^/]+/)?cassettes/|^.copier-answers.yml$|^.github/|
   # Maybe reactivate this when all README files include prettier ignore tags?
   ^README\.md$|
   # Library files can have extraneous formatting (even minimized)
@@ -46,7 +46,7 @@ repos:
           - --remove-duplicate-keys
           - --remove-unused-variables
   - repo: https://github.com/psf/black
-    rev: 20.8b1
+    rev: 22.3.0
     hooks:
       - id: black
   - repo: https://github.com/pre-commit/mirrors-prettier
@@ -120,7 +120,7 @@ repos:
         name: flake8
         additional_dependencies: ["flake8-bugbear==20.1.4"]
   - repo: https://github.com/PyCQA/pylint
-    rev: pylint-2.5.3
+    rev: v2.11.1
     hooks:
       - id: pylint
         name: pylint with optional checks
@@ -129,7 +129,7 @@ repos:
           - --exit-zero
         verbose: true
         additional_dependencies: &pylint_deps
-          - pylint-odoo==3.5.0
+          - pylint-odoo==5.0.5
       - id: pylint
         name: pylint with mandatory checks
         args:
diff --git a/donation_stay/README.rst b/donation_stay/README.rst
new file mode 100644
index 00000000..8a1132c7
--- /dev/null
+++ b/donation_stay/README.rst
@@ -0,0 +1,1 @@
+Generated from readme subdir
diff --git a/donation_stay/__init__.py b/donation_stay/__init__.py
new file mode 100644
index 00000000..9b429614
--- /dev/null
+++ b/donation_stay/__init__.py
@@ -0,0 +1,2 @@
+from . import models
+from . import wizard
diff --git a/donation_stay/__manifest__.py b/donation_stay/__manifest__.py
new file mode 100644
index 00000000..ddbce53d
--- /dev/null
+++ b/donation_stay/__manifest__.py
@@ -0,0 +1,24 @@
+# Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+# Copyright 2014-2021 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+    "name": "Donation Stay",
+    "version": "14.0.1.0.0",
+    "category": "Lodging",
+    "license": "AGPL-3",
+    "summary": "Create donations from a stay",
+    "author": "Barroux Abbey, Akretion, Odoo Community Association (OCA)",
+    "maintainers": ["alexis-via"],
+    "website": "https://github.com/OCA/vertical-abbey",
+    "depends": ["donation", "stay"],
+    "data": [
+        "security/ir.model.access.csv",
+        "wizard/create_donation_stay_view.xml",
+        "wizard/res_config_settings.xml",
+        "views/stay.xml",
+    ],
+    "demo": ["demo/demo.xml"],
+    "installable": True,
+}
diff --git a/donation_stay/demo/demo.xml b/donation_stay/demo/demo.xml
new file mode 100644
index 00000000..072aff6a
--- /dev/null
+++ b/donation_stay/demo/demo.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<odoo noupdate="1">
+
+<record id="product_product_stay_donation" model="product.product">
+    <field name="name">Stay Donation</field>
+    <field name="default_code">STAYDON</field>
+    <field name="categ_id" ref="product.product_category_all" />
+    <field name="sale_ok">0</field>
+    <field name="donation">1</field>
+    <field name="list_price">0</field>
+    <field name="type">service</field>
+    <field name="taxes_id" eval="False" />
+    <field name="supplier_taxes_id" eval="False" />
+</record>
+
+<record id="stay_campaign" model="donation.campaign">
+    <field name="name">Stay</field>
+</record>
+
+<record id="base.main_company" model="res.company">
+    <field name="donation_stay_product_id" ref="product_product_stay_donation" />
+    <field name="donation_stay_campaign_id" ref="stay_campaign" />
+</record>
+
+</odoo>
diff --git a/donation_stay/i18n/fr.po b/donation_stay/i18n/fr.po
new file mode 100644
index 00000000..80044811
--- /dev/null
+++ b/donation_stay/i18n/fr.po
@@ -0,0 +1,190 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# 	* donation_stay
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-08-14 19:41+0000\n"
+"PO-Revision-Date: 2021-08-14 19:41+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_res_company__donation_stay_campaign_id
+#: model:ir.model.fields,field_description:donation_stay.field_res_config_settings__donation_stay_campaign_id
+msgid "Campaign for Stay Donations"
+msgstr "Campagne pour les dons hôtellerie"
+
+#. module: donation_stay
+#: model_terms:ir.ui.view,arch_db:donation_stay.create_donation_stay_form
+msgid "Cancel"
+msgstr "Annuler"
+
+#. module: donation_stay
+#: model:ir.model,name:donation_stay.model_res_company
+msgid "Companies"
+msgstr "Sociétés"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__company_id
+msgid "Company"
+msgstr "Société"
+
+#. module: donation_stay
+#: model:ir.model,name:donation_stay.model_res_config_settings
+msgid "Config Settings"
+msgstr "res.config.settings"
+
+#. module: donation_stay
+#: model_terms:ir.ui.view,arch_db:donation_stay.create_donation_stay_form
+#: model_terms:ir.ui.view,arch_db:donation_stay.stay_add_donation_form
+msgid "Create Donation"
+msgstr "Créer un don"
+
+#. module: donation_stay
+#: model:ir.model,name:donation_stay.model_donation_stay_create
+msgid "Create Donation from a Stay"
+msgstr "Créer un don à partir d'un séjour"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__create_uid
+msgid "Created by"
+msgstr "Créé par"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__create_date
+msgid "Created on"
+msgstr "Créé le"
+
+#. module: donation_stay
+#: model:ir.actions.act_window,name:donation_stay.create_donation_stay_action
+msgid "Creation of Donation for a Guest Stay"
+msgstr "Créer un don depuis le séjour d'un hôte"
+
+#. module: donation_stay
+#: model_terms:ir.ui.view,arch_db:donation_stay.create_donation_stay_form
+msgid "Creation of a Donation for a Guest Stay"
+msgstr "Créer un don lié depuis le séjour d'un hôte"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__currency_id
+msgid "Currency"
+msgstr "Devise"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__display_name
+#: model:ir.model.fields,field_description:donation_stay.field_res_company__display_name
+#: model:ir.model.fields,field_description:donation_stay.field_res_config_settings__display_name
+#: model:ir.model.fields,field_description:donation_stay.field_stay_stay__display_name
+msgid "Display Name"
+msgstr "Nom à afficher"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_stay_stay__donation_id
+msgid "Donation"
+msgstr "Don"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__amount
+msgid "Donation Amount"
+msgstr "Montant du don"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__date_donation
+msgid "Donation Date"
+msgstr "Date du don"
+
+#. module: donation_stay
+#: code:addons/donation_stay/wizard/create_donation_stay.py:0
+#, python-format
+msgid "Donation Stay Product not set on company '%s'."
+msgstr "Article de don pour séjour non configuré sur la société '%s'."
+
+#. module: donation_stay
+#: code:addons/donation_stay/wizard/create_donation_stay.py:0
+#, python-format
+msgid ""
+"Donation created from stay <a href=# data-oe-model=stay.stay data-oe-"
+"id=%d>%s</a>."
+msgstr "Don créé depuis le séjour <a href=# data-oe-model=stay.stay data-oe-id=%d>%s</a>."
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__partner_id
+msgid "Guest"
+msgstr "Hôte"
+
+#. module: donation_stay
+#: model:ir.model,name:donation_stay.model_stay_stay
+msgid "Guest Stay"
+msgstr "Séjour de l'hôte"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__id
+#: model:ir.model.fields,field_description:donation_stay.field_res_company__id
+#: model:ir.model.fields,field_description:donation_stay.field_res_config_settings__id
+#: model:ir.model.fields,field_description:donation_stay.field_stay_stay__id
+msgid "ID"
+msgstr ""
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create____last_update
+#: model:ir.model.fields,field_description:donation_stay.field_res_company____last_update
+#: model:ir.model.fields,field_description:donation_stay.field_res_config_settings____last_update
+#: model:ir.model.fields,field_description:donation_stay.field_stay_stay____last_update
+msgid "Last Modified on"
+msgstr "Dernière modification le"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__write_uid
+msgid "Last Updated by"
+msgstr "Dernière modification par"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__write_date
+msgid "Last Updated on"
+msgstr "Dernière modification le"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__payment_mode_id
+msgid "Payment Mode"
+msgstr "Mode de paiement"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__payment_ref
+msgid "Payment Reference"
+msgstr "Référence de paiement"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_res_company__donation_stay_product_id
+#: model:ir.model.fields,field_description:donation_stay.field_res_config_settings__donation_stay_product_id
+msgid "Product for Stay Donations"
+msgstr "Article pour les dons de séjour"
+
+#. module: donation_stay
+#: model:ir.model.fields,field_description:donation_stay.field_donation_stay_create__stay_id
+msgid "Stay"
+msgstr "Séjour"
+
+#. module: donation_stay
+#: model:product.product,name:donation_stay.product_product_stay_donation
+#: model:product.template,name:donation_stay.product_product_stay_donation_product_template
+msgid "Stay Donation"
+msgstr "Don hôtellerie"
+
+#. module: donation_stay
+#: code:addons/donation_stay/wizard/create_donation_stay.py:0
+#, python-format
+msgid "The amount of the donation is not set or negative."
+msgstr "Le montant du don n'est pas renseigné ou est négatif."
+
+#. module: donation_stay
+#: model:product.product,uom_name:donation_stay.product_product_stay_donation
+#: model:product.template,uom_name:donation_stay.product_product_stay_donation_product_template
+msgid "Units"
+msgstr "Unités"
diff --git a/donation_stay/models/__init__.py b/donation_stay/models/__init__.py
new file mode 100644
index 00000000..7e860c3c
--- /dev/null
+++ b/donation_stay/models/__init__.py
@@ -0,0 +1,2 @@
+from . import stay
+from . import res_company
diff --git a/donation_stay/models/res_company.py b/donation_stay/models/res_company.py
new file mode 100644
index 00000000..b5f2c31b
--- /dev/null
+++ b/donation_stay/models/res_company.py
@@ -0,0 +1,16 @@
+# Copyright 2021 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class ResCompany(models.Model):
+    _inherit = "res.company"
+
+    donation_stay_product_id = fields.Many2one(
+        "product.product", string="Product for Stay Donations", ondelete="restrict"
+    )
+    donation_stay_campaign_id = fields.Many2one(
+        "donation.campaign", string="Campaign for Stay Donations", ondelete="restrict"
+    )
diff --git a/donation_stay/models/stay.py b/donation_stay/models/stay.py
new file mode 100644
index 00000000..af2022c6
--- /dev/null
+++ b/donation_stay/models/stay.py
@@ -0,0 +1,13 @@
+# Copyright 2021 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class StayStay(models.Model):
+    _inherit = "stay.stay"
+
+    donation_id = fields.Many2one(
+        "donation.donation", string="Donation", copy=False, tracking=True
+    )
diff --git a/donation_stay/readme/CONTRIBUTORS.rst b/donation_stay/readme/CONTRIBUTORS.rst
new file mode 100644
index 00000000..a0f15c8b
--- /dev/null
+++ b/donation_stay/readme/CONTRIBUTORS.rst
@@ -0,0 +1,3 @@
+* Alexis de Lattre <alexis.delattre@akretion.com>
+* Brother Bernard <informatique - at - barroux.org>
+* Brother Irénée (Barroux Abbey)
diff --git a/donation_stay/readme/DESCRIPTION.rst b/donation_stay/readme/DESCRIPTION.rst
new file mode 100644
index 00000000..f30a8156
--- /dev/null
+++ b/donation_stay/readme/DESCRIPTION.rst
@@ -0,0 +1,1 @@
+This module adds a wizard to create a donation from a stay.
diff --git a/donation_stay/readme/USAGE.rst b/donation_stay/readme/USAGE.rst
new file mode 100644
index 00000000..3dade293
--- /dev/null
+++ b/donation_stay/readme/USAGE.rst
@@ -0,0 +1,1 @@
+This module adds a button *Create Donation* on the form view of a stay. This button starts a wizard to easily create a draft donation. Then the user will have to validate the donation.
diff --git a/donation_stay/security/ir.model.access.csv b/donation_stay/security/ir.model.access.csv
new file mode 100644
index 00000000..492e796b
--- /dev/null
+++ b/donation_stay/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_donation_stay_create,Full access on donation.stay.create,model_donation_stay_create,donation.group_donation_user,1,1,1,1
diff --git a/donation_stay/static/description/icon.png b/donation_stay/static/description/icon.png
new file mode 100644
index 00000000..b3019fd7
Binary files /dev/null and b/donation_stay/static/description/icon.png differ
diff --git a/donation_stay/views/stay.xml b/donation_stay/views/stay.xml
new file mode 100644
index 00000000..940a6e90
--- /dev/null
+++ b/donation_stay/views/stay.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2021 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  @author: Brother Bernard <informatique@barroux.org>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<record id="stay_add_donation_form" model="ir.ui.view">
+    <field name="name">add.donation.from.stay.form</field>
+    <field name="model">stay.stay</field>
+    <field name="inherit_id" ref="stay.stay_form" />
+    <field name="arch" type="xml">
+        <button name="cancel" position="before">
+            <button
+                    type="action"
+                    string="Create Donation"
+                    name="%(create_donation_stay_action)d"
+                    groups="donation.group_donation_user"
+                    attrs="{'invisible': ['|', ('donation_id', '!=', False), ('state', 'in', ('cancel', 'draft'))]}"
+                />
+        </button>
+        <group name="left" position="inside">
+            <field name="donation_id" />
+        </group>
+    </field>
+</record>
+
+<record id="stay_tree" model="ir.ui.view">
+    <field name="name">donation.stay.tree</field>
+    <field name="model">stay.stay</field>
+    <field name="inherit_id" ref="stay.stay_tree" />
+    <field name="arch" type="xml">
+            <field name="assign_status" position="after">
+                    <field name="donation_id" optional="show" />
+            </field>
+            </field>
+    </record>
+
+<record id="stay_search" model="ir.ui.view">
+    <field name="name">donation.stay.search</field>
+    <field name="model">stay.stay</field>
+    <field name="inherit_id" ref="stay.stay_search" />
+    <field name="arch" type="xml">
+        <filter name="departure_date" position="after">
+            <separator />
+            <filter
+                    name="donation_todo"
+                    string="No Donation"
+                    domain="[('donation_id', '=', False)]"
+                />
+            <filter
+                    name="donation_done"
+                    string="Donation Recorded"
+                    domain="[('donation_id', '!=', False)]"
+                />
+        </filter>
+    </field>
+</record>
+
+
+</odoo>
diff --git a/donation_stay/wizard/__init__.py b/donation_stay/wizard/__init__.py
new file mode 100644
index 00000000..76fb7c04
--- /dev/null
+++ b/donation_stay/wizard/__init__.py
@@ -0,0 +1,2 @@
+from . import res_config_settings
+from . import create_donation_stay
diff --git a/donation_stay/wizard/create_donation_stay.py b/donation_stay/wizard/create_donation_stay.py
new file mode 100644
index 00000000..14486230
--- /dev/null
+++ b/donation_stay/wizard/create_donation_stay.py
@@ -0,0 +1,103 @@
+# Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+# Copyright 2014-2021 Akretion France (www.akretion.com)
+# @author: Brother Irénée
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import _, api, fields, models
+from odoo.exceptions import UserError
+
+
+class DonationStayCreate(models.TransientModel):
+    _name = "donation.stay.create"
+    _description = "Create Donation from a Stay"
+
+    stay_id = fields.Many2one("stay.stay", string="Stay", required=True)
+    company_id = fields.Many2one("res.company", string="Company", required=True)
+    partner_id = fields.Many2one("res.partner", string="Guest", required=True)
+    payment_mode_id = fields.Many2one(
+        "account.payment.mode",
+        string="Payment Mode",
+        required=True,
+        domain="[('donation', '=', True), ('company_id', '=', company_id)]",
+    )
+    currency_id = fields.Many2one(
+        "res.currency",
+        string="Currency",
+        required=True,
+        default=lambda self: self.env.company.currency_id,
+    )
+    amount = fields.Monetary(
+        string="Donation Amount", currency_field="currency_id", required=True
+    )
+    date_donation = fields.Date(
+        "Donation Date", required=True, default=fields.Date.context_today
+    )
+    payment_ref = fields.Char("Payment Reference")
+
+    @api.model
+    def default_get(self, fields_list):
+        res = super().default_get(fields_list)
+        assert self._context.get("active_model") == "stay.stay"
+        stay = self.env["stay.stay"].browse(self._context.get("active_id"))
+        res.update(
+            {
+                "stay_id": stay.id,
+                "company_id": stay.company_id.id,
+                "partner_id": stay.partner_id.id or False,
+            }
+        )
+        return res
+
+    def _prepare_donation(self):
+        if self.currency_id.compare_amounts(self.amount, 0) <= 0:
+            raise UserError(_("The amount of the donation is not set or negative."))
+        company = self.company_id
+        assert self.stay_id.company_id == company
+        campaign_id = company.donation_stay_campaign_id.id or False
+        stay_donation_product = company.donation_stay_product_id
+        if not stay_donation_product:
+            raise UserError(
+                _("Donation Stay Product not set on company '%s'.")
+                % company.display_name
+            )
+        line_vals = {
+            "product_id": stay_donation_product.id,
+            "quantity": 1,
+            "unit_price": self.amount,
+        }
+        vals = {
+            "partner_id": self.partner_id.id,
+            "payment_mode_id": self.payment_mode_id.id,
+            "currency_id": self.currency_id.id,
+            "payment_ref": self.payment_ref,
+            "check_total": self.amount,
+            "donation_date": self.date_donation,
+            "campaign_id": campaign_id,
+            "line_ids": [(0, 0, line_vals)],
+            "company_id": self.company_id.id,
+            "tax_receipt_option": self.partner_id.commercial_partner_id.tax_receipt_option,
+        }
+        return vals
+
+    def create_donation(self):
+        self.ensure_one()
+        donation_vals = self._prepare_donation()
+        donation = self.env["donation.donation"].create(donation_vals)
+        donation.message_post(
+            body=_(
+                "Donation created from stay "
+                "<a href=# data-oe-model=stay.stay data-oe-id=%d>%s</a>."
+            )
+            % (self.stay_id.id, self.stay_id.name)
+        )
+        self.stay_id.write({"donation_id": donation.id})
+        action = self.env.ref("donation.donation_action").sudo().read()[0]
+        action.update(
+            {
+                "views": False,
+                "view_mode": "form,tree,pivot,graph",
+                "res_id": donation.id,
+            }
+        )
+        return action
diff --git a/donation_stay/wizard/create_donation_stay_view.xml b/donation_stay/wizard/create_donation_stay_view.xml
new file mode 100644
index 00000000..62cf9f30
--- /dev/null
+++ b/donation_stay/wizard/create_donation_stay_view.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2021 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  @author: Brother Bernard <informatique@barroux.org>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<record id="create_donation_stay_form" model="ir.ui.view">
+    <field name="name">donation.stay.create.form</field>
+    <field name="model">donation.stay.create</field>
+    <field name="arch" type="xml">
+        <form string="Creation of a Donation for a Guest Stay">
+            <group name="main">
+                <field name="stay_id" readonly="1" />
+                <field name="company_id" invisible="1" />
+                <field name="partner_id" />
+                <field name="payment_mode_id" widget="selection" />
+                <field name="currency_id" />
+                <field name="amount" />
+                <field name="payment_ref" />
+                <field
+                        name="date_donation"
+                        options="{'datepicker': {'warn_future': true}}"
+                    />
+            </group>
+            <footer>
+                <button
+                        type="object"
+                        name="create_donation"
+                        string="Create Donation"
+                        class="btn-primary"
+                    />
+                <button special="cancel" string="Cancel" />
+            </footer>
+        </form>
+    </field>
+</record>
+
+<record id="create_donation_stay_action" model="ir.actions.act_window">
+    <field name="name">Creation of Donation for a Guest Stay</field>
+    <field name="res_model">donation.stay.create</field>
+    <field name="view_mode">form</field>
+    <field name="target">new</field>
+</record>
+
+
+</odoo>
diff --git a/donation_stay/wizard/res_config_settings.py b/donation_stay/wizard/res_config_settings.py
new file mode 100644
index 00000000..e022d1d6
--- /dev/null
+++ b/donation_stay/wizard/res_config_settings.py
@@ -0,0 +1,16 @@
+# Copyright 2021 Akretion France (http://www.akretion.com/)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from odoo import fields, models
+
+
+class ResConfigSettings(models.TransientModel):
+    _inherit = "res.config.settings"
+
+    donation_stay_product_id = fields.Many2one(
+        related="company_id.donation_stay_product_id", readonly=False
+    )
+    donation_stay_campaign_id = fields.Many2one(
+        related="company_id.donation_stay_campaign_id", readonly=False
+    )
diff --git a/donation_stay/wizard/res_config_settings.xml b/donation_stay/wizard/res_config_settings.xml
new file mode 100644
index 00000000..a4a717c3
--- /dev/null
+++ b/donation_stay/wizard/res_config_settings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2021 Akretion France (http://www.akretion.com/)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+
+<record id="res_config_settings_view_form" model="ir.ui.view">
+    <field name="name">donation_stay.res.config.settings.form</field>
+    <field name="model">res.config.settings</field>
+    <field name="inherit_id" ref="stay.res_config_settings_view_form" />
+    <field name="arch" type="xml">
+        <div data-key="stay" position="inside">
+            <h2>Donation for a Stay</h2>
+            <div class='row mt16 o_settings_container' name="stay_setting_container">
+                <div class='col-12 col-lg-12 o_setting_box' id="stay_setting">
+                    <div class="o_setting_left_pane" />
+                    <div class="o_setting_right_pane">
+                        <div class="row">
+                            <label for="donation_stay_product_id" class="col-md-3" />
+                            <field name="donation_stay_product_id" />
+                        </div>
+                        <div class="row" id="donation_stay_campaign_id">
+                            <label for="donation_stay_campaign_id" class="col-md-3" />
+                            <field name="donation_stay_campaign_id" />
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </field>
+</record>
+
+
+</odoo>
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 00000000..0f02ce9b
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+# generated from manifests external_dependencies
+xlsxwriter
diff --git a/setup/donation_stay/odoo/addons/donation_stay b/setup/donation_stay/odoo/addons/donation_stay
new file mode 120000
index 00000000..e03e006f
--- /dev/null
+++ b/setup/donation_stay/odoo/addons/donation_stay
@@ -0,0 +1,1 @@
+../../../../donation_stay
\ No newline at end of file
diff --git a/setup/donation_stay/setup.py b/setup/donation_stay/setup.py
new file mode 100644
index 00000000..28c57bb6
--- /dev/null
+++ b/setup/donation_stay/setup.py
@@ -0,0 +1,6 @@
+import setuptools
+
+setuptools.setup(
+    setup_requires=['setuptools-odoo'],
+    odoo_addon=True,
+)
diff --git a/setup/stay/odoo/addons/stay b/setup/stay/odoo/addons/stay
new file mode 120000
index 00000000..58c2be6f
--- /dev/null
+++ b/setup/stay/odoo/addons/stay
@@ -0,0 +1,1 @@
+../../../../stay
\ No newline at end of file
diff --git a/setup/stay/setup.py b/setup/stay/setup.py
new file mode 100644
index 00000000..28c57bb6
--- /dev/null
+++ b/setup/stay/setup.py
@@ -0,0 +1,6 @@
+import setuptools
+
+setuptools.setup(
+    setup_requires=['setuptools-odoo'],
+    odoo_addon=True,
+)
diff --git a/setup/stay_report_py3o/odoo/addons/stay_report_py3o b/setup/stay_report_py3o/odoo/addons/stay_report_py3o
new file mode 120000
index 00000000..c011005e
--- /dev/null
+++ b/setup/stay_report_py3o/odoo/addons/stay_report_py3o
@@ -0,0 +1,1 @@
+../../../../stay_report_py3o
\ No newline at end of file
diff --git a/setup/stay_report_py3o/setup.py b/setup/stay_report_py3o/setup.py
new file mode 100644
index 00000000..28c57bb6
--- /dev/null
+++ b/setup/stay_report_py3o/setup.py
@@ -0,0 +1,6 @@
+import setuptools
+
+setuptools.setup(
+    setup_requires=['setuptools-odoo'],
+    odoo_addon=True,
+)
diff --git a/stay/README.rst b/stay/README.rst
new file mode 100644
index 00000000..90b1e766
--- /dev/null
+++ b/stay/README.rst
@@ -0,0 +1,1 @@
+generated from readme subdir
diff --git a/stay/__init__.py b/stay/__init__.py
new file mode 100644
index 00000000..48d99043
--- /dev/null
+++ b/stay/__init__.py
@@ -0,0 +1,3 @@
+from . import models
+from . import controllers
+from . import wizard
diff --git a/stay/__manifest__.py b/stay/__manifest__.py
new file mode 100644
index 00000000..1d40f192
--- /dev/null
+++ b/stay/__manifest__.py
@@ -0,0 +1,42 @@
+# Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+# Copyright 2014-2021 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# @author: Brother Bernard <informatique@barroux.org>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+    "name": "Stay",
+    "version": "14.0.1.0.0",
+    "category": "Lodging",
+    "license": "AGPL-3",
+    "summary": "Simple management of stays and meals",
+    "author": "Barroux Abbey, Akretion, Odoo Community Association (OCA)",
+    "maintainers": ["alexis-via"],
+    "website": "https://github.com/OCA/vertical-abbey",
+    "depends": ["mail", "web_timeline"],
+    "external_dependencies": {"python": ["xlsxwriter"]},
+    "data": [
+        "security/stay_security.xml",
+        "views/stay_menu.xml",
+        "wizard/res_config_settings_view.xml",
+        "wizard/stay_journal_print_view.xml",
+        "wizard/stay_toclean_print_view.xml",
+        "wizard/stay_stay_xlsx_view.xml",
+        "wizard/stay_multi_duplicate_view.xml",
+        "wizard/stay_line_mass_update_view.xml",
+        "wizard/stay_line_reset_view.xml",
+        "wizard/stay_room_mass_assign_view.xml",
+        "views/stay.xml",
+        "views/stay_iframe.xml",
+        "data/sequence.xml",
+        "security/ir.model.access.csv",
+        "report/report.xml",
+        "report/report_stay_journal.xml",
+        "views/res_partner.xml",
+        "data/cron.xml",
+        "data/mail_template.xml",
+    ],
+    "demo": ["demo/stay_demo.xml"],
+    "application": True,
+    "installable": True,
+}
diff --git a/stay/controllers/__init__.py b/stay/controllers/__init__.py
new file mode 100644
index 00000000..12a7e529
--- /dev/null
+++ b/stay/controllers/__init__.py
@@ -0,0 +1,1 @@
+from . import main
diff --git a/stay/controllers/main.py b/stay/controllers/main.py
new file mode 100644
index 00000000..f63edf7c
--- /dev/null
+++ b/stay/controllers/main.py
@@ -0,0 +1,64 @@
+# Copyright 2022 Akretion France (http://www.akretion.com/)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# @author: Matthieu Dubois <dubois.matthieu@tutanota.com>
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from odoo import http
+from odoo.http import request
+
+
+class StayController(http.Controller):
+
+    # To make it work, you need to set db_name and dbfilter in your odoo server
+    # config file
+    # Don't forget to also set proxy_mode = True
+    @http.route("/stay/new", type="http", auth="public", website=True, csrf=False)
+    def stay_new(self, **kwargs):
+        res = request.render("stay.stay_form_iframe", {})
+        return res
+
+    @http.route(
+        "/stay/saved",
+        type="http",
+        methods=["POST"],
+        auth="public",
+        website=True,
+        csrf=False,
+    )
+    def stay_saved(self, **kwargs):
+        partner_name = kwargs.get("partner_name")
+        if kwargs.get("title"):
+            title2label = {
+                "mister": "M.",
+                "madam": "Mme",
+                "miss": "Mlle",
+            }
+            partner_name = "%s %s" % (title2label.get(kwargs["title"]), partner_name)
+        partner = request.env["res.partner"].search(
+            [("email", "=ilike", kwargs.get("email"))]
+        )
+        partner_id = partner and partner.id or False
+        notes = f"{kwargs.get('notes')}\n{kwargs.get('mobile')}\n{kwargs.get('email')}"
+        stay = (
+            request.env["stay.stay"]
+            .sudo()
+            .create(
+                {
+                    "guest_qty": kwargs.get("guest_qty"),
+                    "partner_name": partner_name,
+                    "partner_id": partner_id,
+                    "arrival_date": kwargs.get("arrival_date"),
+                    "arrival_time": kwargs.get("arrival_time"),
+                    "departure_date": kwargs.get("departure_date"),
+                    "departure_time": kwargs.get("departure_time"),
+                    "notes": notes,
+                }
+            )
+        )
+        vals = {
+            "stay": stay,
+            "main_object": stay,
+        }
+        res = request.render("stay.stay_saved_iframe", vals)
+        # TODO add mail confirmation
+        return res
diff --git a/stay/data/cron.xml b/stay/data/cron.xml
new file mode 100644
index 00000000..fe5eda39
--- /dev/null
+++ b/stay/data/cron.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2020-2022 Akretion France (http://www.akretion.com/)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo noupdate="1">
+
+
+<record id="stay_arrival_notify_cron" model="ir.cron">
+    <field name="name">Stay: notify arrivals</field>
+    <field name="user_id" ref="base.user_root" />
+    <field name="interval_number">1</field>
+    <field name="interval_type">days</field>
+    <field name="numbercall">-1</field>
+    <field name="model_id" ref="model_stay_group" />
+    <field name="state">code</field>
+    <field name="code">model._stay_notify()</field>
+</record>
+
+<record id="stay_state_update_cron" model="ir.cron">
+    <field name="name">Stay: update state</field>
+    <field name="user_id" ref="base.user_root" />
+    <field name="interval_number">1</field>
+    <field name="interval_type">days</field>
+    <field name="numbercall">-1</field>
+    <field name="model_id" ref="model_stay_stay" />
+    <field name="state">code</field>
+    <field name="code">model._cron_stay_state_update()</field>
+</record>
+
+
+</odoo>
diff --git a/stay/data/mail_template.xml b/stay/data/mail_template.xml
new file mode 100644
index 00000000..488e0c92
--- /dev/null
+++ b/stay/data/mail_template.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2020-2021 Akretion France (http://www.akretion.com/)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo noupdate="1">
+
+
+<record id="stay_notify" model="mail.template">
+    <field name="name">Stay: Notify arrivals</field>
+    <field name="model_id" ref="stay.model_stay_group" />
+    <field name="email_from">${ctx.get('email_from')}</field>
+    <field name="email_to">${ctx.get('email_to_list')}</field>
+    <field name="auto_delete" eval="False" />
+    <field
+            name="subject"
+        >${object.name} - Arrivals of ${format_date(ctx.get('date'))}</field>
+    <field name="body_html" type="html">
+<div style="margin: 0px; padding: 0px;">
+    <p style="margin: 0px; padding: 0px; font-size: 13px;">
+        <table
+                        style="border-spacing: 0; border-collapse: collapse; width: 100%; text-align: center;"
+                    >
+            <tr>
+                <th style="padding: 5px; border: 1px solid black;">Guest Name</th>
+                <th style="padding: 5px; border: 1px solid black;">Guest Qty</th>
+                <th style="padding: 5px; border: 1px solid black;">Arrival Time</th>
+                <th style="padding: 5px; border: 1px solid black;">Rooms</th>
+                <th style="padding: 5px; border: 1px solid black;">Departure Date</th>
+            </tr>
+            % for o in ctx.get('stay_list'):
+            <tr>
+                <td
+                                style="padding: 5px; border: 1px solid black; text-align: left;"
+                            >${o['partner_name']}</td>
+                <td
+                                style="padding: 5px; border: 1px solid black;"
+                            >${o['guest_qty']}</td>
+                <td
+                                style="padding: 5px; border: 1px solid black;"
+                            >${o['arrival_time']}</td>
+                <td style="padding: 5px; border: 1px solid black;">${o['rooms']}</td>
+                <td
+                                style="padding: 5px; border: 1px solid black;"
+                            >${format_date(o['departure_date'])} (${o._fields['departure_time'].convert_to_export(o.departure_time, o)})</td>
+            </tr>
+            % endfor
+        </table>
+    </p>
+</div>
+    </field>
+</record>
+
+
+</odoo>
diff --git a/stay/data/sequence.xml b/stay/data/sequence.xml
new file mode 100644
index 00000000..c608ac84
--- /dev/null
+++ b/stay/data/sequence.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2021 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo noupdate="1">
+
+<record id="stay_seq" model="ir.sequence">
+    <field name="name">Stay</field>
+    <field name="code">stay.stay</field>
+    <field name="prefix">H</field>
+    <field name="padding">4</field>
+    <field name="company_id" eval="False" />
+</record>
+
+</odoo>
diff --git a/stay/demo/stay_demo.xml b/stay/demo/stay_demo.xml
new file mode 100644
index 00000000..bb1e7b4a
--- /dev/null
+++ b/stay/demo/stay_demo.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2021 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo noupdate="1">
+
+<record id="refectory_monastique" model="stay.refectory">
+    <field name="name">Réfectoire monastique</field>
+    <field name="code">REF</field>
+    <field name="capacity">48</field>
+</record>
+
+<record id="refectory_ste_francoise" model="stay.refectory">
+    <field name="name">Salle Sainte Françoise Romaine</field>
+    <field name="code">SFR</field>
+    <field name="capacity">16</field>
+</record>
+
+<record id="refectory_st_bernard" model="stay.refectory">
+    <field name="name">Salle Saint Bernard</field>
+    <field name="code">BER</field>
+    <field name="capacity">12</field>
+</record>
+
+<record id="group1" model="stay.group">
+    <field name="name">Hôtellerie monastère</field>
+    <field name="default_refectory_id" ref="refectory_monastique" />
+</record>
+
+<record id="group2" model="stay.group">
+    <field name="name">Hôtellerie familles</field>
+    <field name="default_refectory_id" ref="refectory_ste_francoise" />
+</record>
+
+<record id="room_st_cure_ars" model="stay.room">
+    <field name="name">St Curé d'Ars</field>
+    <field name="code">211</field>
+    <field name="bed_qty">1</field>
+    <field name="group_id" ref="group1" />
+</record>
+
+<record id="room_st_jean_eudes" model="stay.room">
+    <field name="name">St Jean Eudes</field>
+    <field name="code">213</field>
+    <field name="bed_qty">1</field>
+    <field name="group_id" ref="group1" />
+</record>
+
+<record id="room_st_bruno" model="stay.room">
+    <field name="name">St Bruno</field>
+    <field name="code">214</field>
+    <field name="bed_qty">1</field>
+    <field name="group_id" ref="group1" />
+</record>
+
+<record id="room_st_elie" model="stay.room">
+    <field name="name">St Elie</field>
+    <field name="code">215</field>
+    <field name="bed_qty">1</field>
+    <field name="group_id" ref="group1" />
+</record>
+
+<record id="room_dortoir" model="stay.room">
+    <field name="name">Dortoir</field>
+    <field name="code">DOR</field>
+    <field name="bed_qty">12</field>
+    <field name="group_id" ref="group1" />
+</record>
+
+<record id="st_benoit_house" model="stay.room">
+    <field name="name">Maison St Benoît</field>
+    <field name="code">BEN</field>
+    <field name="bed_qty">5</field>
+    <field name="group_id" ref="group2" />
+</record>
+
+<record id="stay1" model="stay.stay">
+    <field name="partner_name">Martin Payet</field>
+    <field name="guest_qty">1</field>
+    <field name="arrival_date" eval="time.strftime('%Y-%m-01')" />
+    <field name="arrival_time">afternoon</field>
+    <field name="departure_date" eval="time.strftime('%Y-%m-05')" />
+    <field name="departure_time">morning</field>
+    <field name="group_id" ref="group1" />
+    <field name="state">confirm</field>
+</record>
+
+<record id="stay1_room_assign" model="stay.room.assign">
+    <field name="stay_id" ref="stay1" />
+    <field name="room_id" ref="room_st_elie" />
+    <field name="guest_qty">1</field>
+</record>
+
+<record id="stay2" model="stay.stay">
+    <field name="partner_id" ref="base.res_partner_address_2" />
+    <field name="partner_name">Joseph Walters</field>
+    <field name="guest_qty">1</field>
+    <field name="arrival_date" eval="time.strftime('%Y-%m-01')" />
+    <field name="arrival_time">morning</field>
+    <field name="departure_date" eval="time.strftime('%Y-%m-06')" />
+    <field name="departure_time">evening</field>
+    <field name="group_id" ref="group1" />
+    <field name="state">confirm</field>
+</record>
+
+<record id="stay2_room_assign" model="stay.room.assign">
+    <field name="stay_id" ref="stay2" />
+    <field name="room_id" ref="room_st_cure_ars" />
+    <field name="guest_qty">1</field>
+</record>
+
+<record id="stay3" model="stay.stay">
+    <field name="partner_id" ref="base.res_partner_address_7" />
+    <field name="partner_name">Richard Ellis</field>
+    <field name="guest_qty">1</field>
+    <field name="arrival_date" eval="time.strftime('%Y-%m-03')" />
+    <field name="arrival_time">morning</field>
+    <field name="departure_date" eval="time.strftime('%Y-%m-12')" />
+    <field name="departure_time">evening</field>
+    <field name="group_id" ref="group1" />
+    <field name="state">confirm</field>
+</record>
+
+<record id="stay3_room_assign" model="stay.room.assign">
+    <field name="stay_id" ref="stay3" />
+    <field name="room_id" ref="room_st_jean_eudes" />
+    <field name="guest_qty">1</field>
+</record>
+
+<record id="stay4" model="stay.stay">
+    <field name="partner_name">Famille Martin</field>
+    <field name="guest_qty">5</field>
+    <field name="arrival_date" eval="time.strftime('%Y-%m-01')" />
+    <field name="arrival_time">afternoon</field>
+    <field name="departure_date" eval="time.strftime('%Y-%m-05')" />
+    <field name="departure_time">morning</field>
+    <field name="no_meals" eval="True" />
+    <field name="group_id" ref="group2" />
+    <field name="state">confirm</field>
+</record>
+
+<record id="stay4_room_assign" model="stay.room.assign">
+    <field name="stay_id" ref="stay4" />
+    <field name="room_id" ref="st_benoit_house" />
+    <field name="guest_qty">5</field>
+</record>
+
+<record id="stay5" model="stay.stay">
+    <field name="partner_name">Dr Santé</field>
+    <field name="guest_qty">1</field>
+    <field name="arrival_date" eval="time.strftime('%Y-%m-01')" />
+    <field name="arrival_time">afternoon</field>
+    <field name="departure_date" eval="time.strftime('%Y-%m-05')" />
+    <field name="departure_time">unknown</field>
+    <field name="group_id" ref="group2" />
+    <field name="state">draft</field>
+</record>
+
+<record id="base.main_company" model="res.company">
+    <field name="default_refectory_id" ref="refectory_monastique" />
+</record>
+
+<record id="base.user_demo" model="res.users">
+    <field name="groups_id" eval="[(4, ref('group_stay_user'))]" />
+</record>
+
+</odoo>
diff --git a/stay/i18n/fr.po b/stay/i18n/fr.po
new file mode 100644
index 00000000..4c6bd67e
--- /dev/null
+++ b/stay/i18n/fr.po
@@ -0,0 +1,1735 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# 	* stay
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-07-01 15:25+0000\n"
+"PO-Revision-Date: 2022-07-01 15:25+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_res_partner__stay_count
+#: model:ir.model.fields,field_description:stay.field_res_users__stay_count
+msgid "# of Stays"
+msgstr "Nombre de séjours"
+
+#. module: stay
+#: model:mail.template,subject:stay.stay_notify
+msgid "${object.name} - Arrivals of ${format_date(ctx.get('date'))}"
+msgstr "${object.name} - Arrivées du ${format_date(ctx.get('date'))}"
+
+#. module: stay
+#: model:ir.actions.report,print_report_name:stay.report_stay_toclean
+msgid "'rooms_to_clean-%s' % str(object.create_date)[:10]"
+msgstr ""
+
+#. module: stay
+#: model:ir.actions.report,print_report_name:stay.report_stay_journal_arrival
+msgid "'stay_arrival-%s' % object.date"
+msgstr ""
+
+#. module: stay
+#: model:ir.actions.report,print_report_name:stay.report_stay_journal_print
+msgid "'stay_journal-%s' % object.date"
+msgstr ""
+
+#. module: stay
+#: model:ir.actions.report,print_report_name:stay.report_stay_journal_meal
+msgid "'stay_meal-%s' % object.date"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.report_stayjournalprint_document
+msgid "<b>Sub-totals:</b>"
+msgstr "<b>Sous-totaux :</b>"
+
+#. module: stay
+#: model:mail.template,body_html:stay.stay_notify
+msgid ""
+"<div style=\"margin: 0px; padding: 0px;\">\n"
+"    <p style=\"margin: 0px; padding: 0px; font-size: 13px;\">\n"
+"        <table style=\"border-spacing: 0; border-collapse: collapse; width: 100%; text-align: center;\">\n"
+"            <tr>\n"
+"                <th style=\"padding: 5px; border: 1px solid black;\">Guest Name</th>\n"
+"                <th style=\"padding: 5px; border: 1px solid black;\">Guest Qty</th>\n"
+"                <th style=\"padding: 5px; border: 1px solid black;\">Arrival Time</th>\n"
+"                <th style=\"padding: 5px; border: 1px solid black;\">Rooms</th>\n"
+"                <th style=\"padding: 5px; border: 1px solid black;\">Departure Date</th>\n"
+"            </tr>\n"
+"            % for o in ctx.get('stay_list'):\n"
+"            <tr>\n"
+"                <td style=\"padding: 5px; border: 1px solid black; text-align: left;\">${o['partner_name']}</td>\n"
+"                <td style=\"padding: 5px; border: 1px solid black;\">${o['guest_qty']}</td>\n"
+"                <td style=\"padding: 5px; border: 1px solid black;\">${o['arrival_time']}</td>\n"
+"                <td style=\"padding: 5px; border: 1px solid black;\">${o['rooms']}</td>\n"
+"                <td style=\"padding: 5px; border: 1px solid black;\">${format_date(o['departure_date'])} (${o._fields['departure_time'].convert_to_export(o.departure_time, o)})</td>\n"
+"            </tr>\n"
+"            % endfor\n"
+"        </table>\n"
+"    </p>\n"
+"</div>\n"
+"    "
+msgstr ""
+
+#. module: stay
+#: model:ir.model.constraint,message:stay.constraint_stay_group_name_company_uniq
+msgid "A group with this name already exists in this company."
+msgstr "Un groupe avec ce nom existe déjà dans cette société."
+
+#. module: stay
+#: model:ir.model.constraint,message:stay.constraint_stay_refectory_company_code_uniq
+msgid "A refectory with this code already exists in this company."
+msgstr "Un réfectoire avec ce code existe déjà dans cette société."
+
+#. module: stay
+#: model:ir.model.constraint,message:stay.constraint_stay_room_company_code_uniq
+msgid "A room with this code already exists in this company."
+msgstr "Une chambre avec ce code existe déjà dans cette société."
+
+#. module: stay
+#: code:addons/stay/wizard/stay_multi_duplicate.py:0
+#, python-format
+msgid "A stay already exists for guest '%s' with arrival date %s (stay %s)."
+msgstr ""
+"Un séjour existe déjà pour l'hote '%s' avec comme date d'arrivée '%s' "
+"(séjour '%s')"
+
+#. module: stay
+#: model:ir.model.constraint,message:stay.constraint_stay_stay_name_company_uniq
+msgid "A stay with this number already exists for this company."
+msgstr "Un séjour avec ce numéro existe déjà dans cette société."
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_needaction
+msgid "Action Needed"
+msgstr "Action requise"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__active
+#: model:ir.model.fields,field_description:stay.field_stay_room__active
+msgid "Active"
+msgstr "Actif"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__activity_ids
+msgid "Activities"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__activity_exception_decoration
+msgid "Activity Exception Decoration"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__activity_state
+msgid "Activity State"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__activity_type_icon
+msgid "Activity Type Icon"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Additional Notes/your motivations"
+msgstr ""
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "Af"
+msgstr "A.m."
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__arrival_time__afternoon
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__departure_time__afternoon
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Afternoon"
+msgstr "Après-midi"
+
+#. module: stay
+#: code:addons/stay/wizard/stay_stay_xlsx.py:0
+#, python-format
+msgid "All"
+msgstr "Tous"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room__allow_simultaneous
+msgid "Allow simultaneous"
+msgstr "Autoriser simultané"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_mass_update_form
+msgid "Apply Changes"
+msgstr "Modifier"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_refectory_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_refectory_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_search
+msgid "Archived"
+msgstr "Archivé"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form
+msgid "Are you sure you want to cancel this stay?"
+msgstr "Êtes-vous sûr de vouloir annuler ce séjour ?"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.report_stayjournalprint_document
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Arrival"
+msgstr "Arrivée"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__arrival_date
+#: model:ir.model.fields,field_description:stay.field_stay_stay__arrival_date
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_assign_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Arrival Date"
+msgstr "Date d'arrivée"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+#: model_terms:ir.ui.view,arch_db:stay.stay_saved_iframe
+msgid "Arrival Date :"
+msgstr "Date d'arrivée"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__arrival_datetime
+#: model:ir.model.fields,field_description:stay.field_stay_stay__arrival_datetime
+msgid "Arrival Date and Time"
+msgstr "Date et heure d'arrivée"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__arrival_note
+msgid "Arrival Note"
+msgstr "Note d'arrivée"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__arrival_time
+#: model:ir.model.fields,field_description:stay.field_stay_stay__arrival_time
+msgid "Arrival Time"
+msgstr "Heure d'arrivée"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_saved_iframe
+msgid "Arrival Time :"
+msgstr "Heure d'arrivée"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "Arrival date (%s) cannot be after departure date (%s)!"
+msgstr ""
+"La date d'arrivée (%s) ne peut pas être postérieure à la date de départ (%s)"
+" !"
+
+#. module: stay
+#: model:ir.actions.report,name:stay.report_stay_journal_arrival
+msgid "Arrival list"
+msgstr "Liste des arrivées"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "Arrival time cannot be set to unknownif the stay is confirmed!"
+msgstr ""
+"Avant de confirmer un séjour, il est impératif de mettre une heure d'arrivée"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_journal_print__report_type__arrival
+msgid "Arrivals"
+msgstr "Arrivées"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_assign_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Arrivals and Departures on"
+msgstr "Arrivées et départs du"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_assign_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Arrivals/Departures Today"
+msgstr "Arrivées/départs du jour"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_assign_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Arrivals/Departures Tomorrow"
+msgstr "Arrivées/départs demain"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__assign_status
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Assign Status"
+msgstr "Statut d'attribution"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__assign_status__assigned
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Assigned"
+msgstr "Attribué"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_attachment_count
+msgid "Attachment Count"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form
+msgid "Back to Draft"
+msgstr "Remettre en brouillon"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line__bed_night_qty
+msgid "Bed Nights"
+msgstr "Nuités"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Book your Stay"
+msgstr "Réserver votre séjour!"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line__breakfast_qty
+msgid "Breakfast"
+msgstr "Petit déjeuner"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.report_stayjournalprint_document
+msgid "Breakfasts"
+msgstr "Petits déjeuners"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "CONSTRUCTION"
+msgstr "EN TRAVAUX"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_journal_print_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_mass_update_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_reset
+#: model_terms:ir.ui.view,arch_db:stay.stay_multi_duplicate_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_stay_xlsx_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_toclean_print_form
+msgid "Cancel"
+msgstr "Annuler"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__state__cancel
+msgid "Cancelled"
+msgstr "Annulé"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__capacity
+msgid "Capacity"
+msgstr "Capacité"
+
+#. module: stay
+#: code:addons/stay/wizard/stay_stay_xlsx.py:0
+#, python-format
+msgid "Celebration"
+msgstr "Fête"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_search
+msgid "Clean"
+msgstr "Nettoyé"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__code
+#: model:ir.model.fields,field_description:stay.field_stay_room__code
+msgid "Code"
+msgstr ""
+
+#. module: stay
+#: model:ir.model,name:stay.model_res_company
+msgid "Companies"
+msgstr "Sociétés"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_group__company_id
+#: model:ir.model.fields,field_description:stay.field_stay_journal_print__company_id
+#: model:ir.model.fields,field_description:stay.field_stay_line__company_id
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__company_id
+#: model:ir.model.fields,field_description:stay.field_stay_room__company_id
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__company_id
+#: model:ir.model.fields,field_description:stay.field_stay_stay__company_id
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__company_id
+#: model:ir.model.fields,field_description:stay.field_stay_toclean_print__company_id
+msgid "Company"
+msgstr "Société"
+
+#. module: stay
+#: model:ir.model,name:stay.model_res_config_settings
+msgid "Config Settings"
+msgstr "res.config.settings"
+
+#. module: stay
+#: model:ir.ui.menu,name:stay.stay_configuration
+msgid "Configuration"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form
+msgid "Confirm"
+msgstr "Confirmer"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_multi_duplicate__create_state__confirm
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__state__confirm
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Confirmed"
+msgstr "Confirmé"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid ""
+"Conflict in room %s: with stay '%s', we would have a total of %d guests on "
+"%s whereas that room only has %d beds."
+msgstr ""
+"Conflit dans la chambre %s : avec le séjour '%s', il y aurait un total de %d"
+" hôtes le %s alors que cette chambre ne contient que %d lits."
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_construction_action
+#: model:ir.model.fields,field_description:stay.field_stay_stay__construction
+#: model:ir.ui.menu,name:stay.stay_construction_menu
+msgid "Construction"
+msgstr "En travaux"
+
+#. module: stay
+#: model:ir.model,name:stay.model_res_partner
+msgid "Contact"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__create_state
+msgid "Create State"
+msgstr "Statut"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_date_label__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_group__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_journal_print__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_line__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_line_reset__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_room__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_stay__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__create_uid
+#: model:ir.model.fields,field_description:stay.field_stay_toclean_print__create_uid
+msgid "Created by"
+msgstr "Créé par"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_date_label__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_group__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_journal_print__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_line__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_line_reset__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_room__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_stay__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__create_date
+#: model:ir.model.fields,field_description:stay.field_stay_toclean_print__create_date
+msgid "Created on"
+msgstr "Créé le"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__state__current
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Current"
+msgstr "En cours"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_search
+msgid "Current and Future Lines"
+msgstr "Lignes actuelles et futures"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_assign_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Current and Future Stays"
+msgstr "Séjours actuels et futurs"
+
+#. module: stay
+#: code:addons/stay/wizard/stay_stay_xlsx.py:0
+#: model:ir.model.fields,field_description:stay.field_stay_date_label__date
+#: model:ir.model.fields,field_description:stay.field_stay_journal_print__date
+#: model:ir.model.fields,field_description:stay.field_stay_line__date
+#: model_terms:ir.ui.view,arch_db:stay.stay_date_label_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_search
+#, python-format
+msgid "Date"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_journal_print__date_label
+#: model_terms:ir.ui.view,arch_db:stay.stay_date_label_form
+msgid "Date Label"
+msgstr "Libellé de date"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_date_label_calendar
+#: model_terms:ir.ui.view,arch_db:stay.stay_date_label_tree
+msgid "Date Labels"
+msgstr "Libellés de date"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.dates_selection_error
+msgid "Dates selection Error"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_res_company__default_refectory_id
+#: model:ir.model.fields,field_description:stay.field_res_config_settings__stay_default_refectory_id
+#: model:ir.model.fields,field_description:stay.field_stay_group__default_refectory_id
+msgid "Default Refectory"
+msgstr "Réfectoire par défaut"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.report_stayjournalprint_document
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Departure"
+msgstr "Départ"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__departure_date
+#: model:ir.model.fields,field_description:stay.field_stay_stay__departure_date
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_assign_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Departure Date"
+msgstr "Date de départ"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+#: model_terms:ir.ui.view,arch_db:stay.stay_saved_iframe
+msgid "Departure Date :"
+msgstr "Date de fin"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__departure_datetime
+#: model:ir.model.fields,field_description:stay.field_stay_stay__departure_datetime
+msgid "Departure Date and Time"
+msgstr "Date et heure de départ"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__departure_note
+msgid "Departure Note"
+msgstr "Note de départ"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__departure_time
+#: model:ir.model.fields,field_description:stay.field_stay_stay__departure_time
+msgid "Departure Time"
+msgstr "Heure de départ"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_saved_iframe
+msgid "Departure Time :"
+msgstr "Date de fin"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "Departure Time cannot be set to unknown if the stay is confirmed."
+msgstr ""
+"Avant de confirmer un séjour, merci de sélectionner une heure de départ "
+"(pour l'instant, celle-ci est inconnue.)"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line__dinner_qty
+#: model_terms:ir.ui.view,arch_db:stay.report_stayjournalprint_document
+msgid "Dinners"
+msgstr "Dîners"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_res_company__display_name
+#: model:ir.model.fields,field_description:stay.field_res_config_settings__display_name
+#: model:ir.model.fields,field_description:stay.field_res_partner__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_date_label__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_group__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_journal_print__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_line__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_line_reset__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_room__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_stay__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__display_name
+#: model:ir.model.fields,field_description:stay.field_stay_toclean_print__display_name
+msgid "Display Name"
+msgstr "Nom à afficher"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_multi_duplicate__create_state__draft
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__state__draft
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Draft"
+msgstr "Brouillon"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.dates_selection_error
+msgid ""
+"Either the arrival date you've chosen is past, or the arrival date you've "
+"selected is after your departure date!"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__end_date
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__end_date
+msgid "End Date"
+msgstr "Date de fin"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__assign_status__error
+msgid "Error"
+msgstr "Erreur"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "Ev"
+msgstr "Sr"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__arrival_time__evening
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__departure_time__evening
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Evening"
+msgstr "Soir"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__file_xlsx
+msgid "File Xlsx"
+msgstr "Fichier Xlsx"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__filename
+msgid "Filename"
+msgstr "Nom de fichier"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__state__done
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Finished"
+msgstr "Terminé"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_follower_ids
+msgid "Followers"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_channel_ids
+msgid "Followers (Channels)"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_partner_ids
+msgid "Followers (Partners)"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_stay__activity_type_icon
+msgid "Font awesome icon e.g. fa-tasks"
+msgstr ""
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid ""
+"For a stay without night, the departure time can only be afternoon or "
+"evening."
+msgstr ""
+"Pour un séjour sans nuité, l'heure de départ peut seulement être après-midi "
+"ou soirée."
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid ""
+"For a stay without night, when the departure time is afternoon, the arrival "
+"time must be morning."
+msgstr ""
+"Pour un séjour sans nuité, quand l'heure de départ est 'Après-midi', l'heure"
+" d'arrivée doit être 'Matin'"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid ""
+"For a stay without night, when the departure time is evening, the arrival "
+"time must be morning or afternoon."
+msgstr ""
+"Pour un séjour sans nuité, quand l'heure de départ est 'Soirée', l'heure "
+"d'arrivée doit être 'Matin' ou 'Après-midi'."
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__frequency
+msgid "Frequency"
+msgstr "Fréquence"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_journal_print__report_type__general
+msgid "General"
+msgstr "Général"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_multi_duplicate_form
+msgid "Generate Stays"
+msgstr "Génerer les séjours"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line__group_id
+#: model:ir.model.fields,field_description:stay.field_stay_room__group_id
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__group_id
+#: model:ir.model.fields,field_description:stay.field_stay_stay__group_id
+#: model_terms:ir.ui.view,arch_db:stay.stay_group_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_assign_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Group"
+msgstr "Groupe"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_assign_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Group By"
+msgstr "Grouper par"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__group_id_integer
+msgid "Group ID"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_group__name
+msgid "Group Name"
+msgstr "Nom du groupe"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_group_action
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__group_ids
+#: model:ir.ui.menu,name:stay.stay_group_menu
+#: model_terms:ir.ui.view,arch_db:stay.stay_group_tree
+msgid "Groups"
+msgstr "Groupes"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line__partner_id
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__partner_id
+#: model:ir.model.fields,field_description:stay.field_stay_stay__partner_id
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_search
+msgid "Guest"
+msgstr "Hôte"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.report_stayjournalprint_document
+msgid "Guest List"
+msgstr "Liste d'hôtes"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_assign_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Guest Name"
+msgstr "Nom de l'hôte"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Guest Name or Stay Number"
+msgstr "Nom de l'hote ou id du séjour"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line__partner_name
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__partner_name
+#: model:ir.model.fields,field_description:stay.field_stay_stay__partner_name
+msgid "Guest Names"
+msgstr "Noms des hôtes"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__guest_qty_to_assign
+msgid "Guest Qty To Assign"
+msgstr "Nombre d'hôtes à assigner"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__guest_qty
+#: model:ir.model.fields,field_description:stay.field_stay_stay__guest_qty
+msgid "Guest Quantity"
+msgstr "Nombre d'hôtes"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_stay
+msgid "Guest Stay"
+msgstr "Séjour de l'hôte"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_tree
+msgid "Guest has Left"
+msgstr "L'hôte est parti"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "Guest has left before the end of his stay."
+msgstr "L'hôte est parti avant la fin de son séjour."
+
+#. module: stay
+#: model:ir.ui.menu,name:stay.partners
+#: model_terms:ir.ui.view,arch_db:stay.report_stayjournalprint_document
+msgid "Guests"
+msgstr "Hôtes"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_res_company__id
+#: model:ir.model.fields,field_description:stay.field_res_config_settings__id
+#: model:ir.model.fields,field_description:stay.field_res_partner__id
+#: model:ir.model.fields,field_description:stay.field_stay_date_label__id
+#: model:ir.model.fields,field_description:stay.field_stay_group__id
+#: model:ir.model.fields,field_description:stay.field_stay_journal_print__id
+#: model:ir.model.fields,field_description:stay.field_stay_line__id
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__id
+#: model:ir.model.fields,field_description:stay.field_stay_line_reset__id
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__id
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__id
+#: model:ir.model.fields,field_description:stay.field_stay_room__id
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__id
+#: model:ir.model.fields,field_description:stay.field_stay_stay__id
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__id
+#: model:ir.model.fields,field_description:stay.field_stay_toclean_print__id
+msgid "ID"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__activity_exception_icon
+msgid "Icon"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_stay__activity_exception_icon
+msgid "Icon to indicate an exception activity."
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_stay__message_needaction
+#: model:ir.model.fields,help:stay.field_stay_stay__message_unread
+msgid "If checked, new messages require your attention."
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_stay__message_has_error
+msgid "If checked, some messages have a delivery error."
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_line__partner_id
+#: model:ir.model.fields,help:stay.field_stay_room_assign__partner_id
+#: model:ir.model.fields,help:stay.field_stay_stay__partner_id
+msgid "If guest is anonymous, leave this field empty."
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_group__user_id
+#: model:ir.model.fields,field_description:stay.field_stay_line__user_id
+#: model:ir.model.fields,field_description:stay.field_stay_room__user_id
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__user_id
+#: model:ir.model.fields,field_description:stay.field_stay_stay__user_id
+msgid "In Charge"
+msgstr "En charge"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_is_follower
+msgid "Is Follower"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__keep_notes
+msgid "Keep Notes?"
+msgstr "Conserver les notes"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__keep_assignments
+msgid "Keep assignments?"
+msgstr "Conserver l'attribution des chambres?"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_date_label__name
+msgid "Label"
+msgstr "Libellé"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_res_company____last_update
+#: model:ir.model.fields,field_description:stay.field_res_config_settings____last_update
+#: model:ir.model.fields,field_description:stay.field_res_partner____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_date_label____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_group____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_journal_print____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_line____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_line_reset____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_refectory____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_room____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_stay____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx____last_update
+#: model:ir.model.fields,field_description:stay.field_stay_toclean_print____last_update
+msgid "Last Modified on"
+msgstr "Dernière modification le"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_date_label__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_group__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_journal_print__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_line__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_line_reset__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_room__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_stay__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__write_uid
+#: model:ir.model.fields,field_description:stay.field_stay_toclean_print__write_uid
+msgid "Last Updated by"
+msgstr "Dernière modification par"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_date_label__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_group__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_journal_print__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_line__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_line_reset__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_room__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_stay__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__write_date
+#: model:ir.model.fields,field_description:stay.field_stay_toclean_print__write_date
+msgid "Last Updated on"
+msgstr "Dernière modification le"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line__lunch_qty
+#: model_terms:ir.ui.view,arch_db:stay.report_stayjournalprint_document
+msgid "Lunches"
+msgstr "Déjeuners"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Madam"
+msgstr "Madame"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_main_attachment_id
+msgid "Main Attachment"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_res_config_settings__group_stay_breakfast
+#: model:res.groups,name:stay.group_stay_breakfast
+msgid "Manage Breakfast"
+msgstr "Gestion du petit déjeuner"
+
+#. module: stay
+#: model:ir.module.category,description:stay.module_category_stay
+msgid "Manage stays (lunch, diner, night, etc...)"
+msgstr "Gestion des séjours (déjeuners, dîners, nuités, etc...)"
+
+#. module: stay
+#: model:res.groups,name:stay.group_stay_manager
+msgid "Manager"
+msgstr "Responsable"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_tree
+msgid "Mark as Cleaned"
+msgstr "Ménage fait"
+
+#. module: stay
+#: model:ir.actions.report,name:stay.report_stay_journal_meal
+msgid "Meal plan"
+msgstr "Rapport repas"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_journal_print__report_type__meal
+msgid "Meals"
+msgstr "Repas"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_has_error
+msgid "Message Delivery error"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_ids
+msgid "Messages"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Miss"
+msgstr "Mademoiselle"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "Missing refectory for guest '%s' on %s."
+msgstr "Réfectoire manquant pour l'hôte '%s' le %s."
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Mister"
+msgstr "Monsieur"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "Mo"
+msgstr "Ma"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__arrival_time__morning
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__departure_time__morning
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Morning"
+msgstr "Matin"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_multi_duplicate_action
+msgid "Multi Duplicate"
+msgstr "Dupliquer plusieurs fois"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_multi_duplicate
+msgid "Multi Stay Duplicate Wizard"
+msgstr "Assistant pour Dupliquer Plusieurs Fois un Séjour"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__my_activity_date_deadline
+msgid "My Activity Deadline"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_assign_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "My Rooms"
+msgstr "Mes chambres"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__name
+#: model:ir.model.fields,field_description:stay.field_stay_room__name
+msgid "Name"
+msgstr "Nom"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Name and Surname"
+msgstr "Nom et prénoms"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__refectory_id
+msgid "New Refectory"
+msgstr "Nouveau réfectoire"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__activity_date_deadline
+msgid "Next Activity Deadline"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__activity_summary
+msgid "Next Activity Summary"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__activity_type_id
+msgid "Next Activity Type"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.report_stayjournalprint_document
+msgid "Nights"
+msgstr "Nuités"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__no_bed_night
+msgid "No Bed Nights"
+msgstr "Pas de nuités"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__no_breakfast
+msgid "No Breakfasts"
+msgstr "Pas de petits déjeuners"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__no_dinner
+msgid "No Dinners"
+msgstr "Pas de dîners"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__no_lunch
+msgid "No Lunches"
+msgstr "Pas de déjeuners"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__no_meals
+msgid "No Meals"
+msgstr "Pas de repas"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__assign_status__no_night
+msgid "No Nights"
+msgstr "Pas de nuités"
+
+#. module: stay
+#: code:addons/stay/wizard/stay_journal_print.py:0
+#, python-format
+msgid "No arrival on %s."
+msgstr "Aucune arrivée le %s"
+
+#. module: stay
+#: code:addons/stay/wizard/stay_journal_print.py:0
+#, python-format
+msgid "No departure on %s."
+msgstr "Aucun départ le %s"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room__notes
+#: model:ir.model.fields,field_description:stay.field_stay_stay__notes
+msgid "Notes"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_needaction_counter
+msgid "Number of Actions"
+msgstr "Nombre d'actions"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Number of Guests"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room__bed_qty
+msgid "Number of beds"
+msgstr "Nombre de lits"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_has_error_counter
+msgid "Number of errors"
+msgstr "Nombre d'erreurs"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Number of guests"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_stay__message_needaction_counter
+msgid "Number of messages which requires an action"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_stay__message_has_error_counter
+msgid "Number of messages with delivery error"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_stay__message_unread_counter
+msgid "Number of unread messages"
+msgstr ""
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_date_label_action
+#: model:ir.ui.menu,name:stay.stay_date_label_menu
+msgid "Ordo"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__assign_status__partial
+msgid "Partial"
+msgstr "Partiel"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_toclean_print_form
+msgid "Print"
+msgstr "Imprimer"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_journal_print_action
+#: model:ir.ui.menu,name:stay.stay_journal_print_menu
+#: model_terms:ir.ui.view,arch_db:stay.stay_journal_print_form
+msgid "Print Journal"
+msgstr "Impression du journal"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_stay_xlsx
+msgid "Print Stay Global view"
+msgstr "Impression de la vue globale des séjours"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_journal_print_form
+msgid "Print Stay Journal"
+msgstr "Impression du journal des séjours"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_stay_xlsx_form
+msgid "Print Stay XLSX"
+msgstr "Impression séjours XLSX"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_stay_xlsx_action
+#: model:ir.ui.menu,name:stay.stay_stay_xlsx_menu
+msgid "Print Stays"
+msgstr "Rapport séjours"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_toclean_print_form
+msgid "Print the <b>To Clean</b> report."
+msgstr "Imprimer le <b>rapport de ménage</b>."
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_journal_print
+msgid "Print the Stay Lines"
+msgstr "Impression des lignes de séjour"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_toclean_print
+msgid "Print to clean report"
+msgstr "Imprimer le rapport ménage"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_refectory_action
+#: model:ir.ui.menu,name:stay.stay_refectory_menu
+#: model_terms:ir.ui.view,arch_db:stay.stay_refectory_tree
+msgid "Refectories"
+msgstr "Réfectoires"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_refectory
+#: model:ir.model.fields,field_description:stay.field_stay_line__refectory_id
+#: model:ir.model.fields,field_description:stay.field_stay_stay__refectory_id
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_refectory_form
+msgid "Refectory"
+msgstr "Réfectoire"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_journal_print__report_type
+msgid "Report Type"
+msgstr "Type de rapport"
+
+#. module: stay
+#: model:ir.ui.menu,name:stay.stay_report_menu
+msgid "Reports"
+msgstr "Rapports"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_line_reset_action
+msgid "Reset All Stay Lines"
+msgstr "Réinitialiser les lignes de repas."
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_reset
+msgid "Reset Stay Lines to Default Values"
+msgstr "Réinitialiser les lignes de repas aux valeurs par défaut"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_reset
+msgid "Reset to Default Values"
+msgstr "Réinitialiser aux valeurs par défaut"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_group_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_assign_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_search
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "Responsible"
+msgstr "Responsable"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__activity_user_id
+msgid "Responsible User"
+msgstr "Utilisateur responsable"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.dates_selection_error
+msgid "Return to form"
+msgstr "Retourner au formulaire"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_room
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__room_id
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_form
+msgid "Room"
+msgstr "Chambre"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "Room %s only has %d bed capacity, not %d!"
+msgstr "La chambre %s a seulement une capacité de %d lits, pas %d !"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_room_assign_action
+#: model:ir.model.fields,field_description:stay.field_stay_stay__room_assign_ids
+#: model:ir.ui.menu,name:stay.stay_room_assign_menu
+msgid "Room Assignments"
+msgstr "Attributions des chambres"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_room_assign
+msgid "Room assignments"
+msgstr "Attributions des chambres"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_room_action
+#: model:ir.model.fields,field_description:stay.field_stay_group__room_ids
+#: model:ir.model.fields,field_description:stay.field_stay_line__rooms_display_name
+#: model:ir.model.fields,field_description:stay.field_stay_stay__rooms_display_name
+#: model:ir.ui.menu,name:stay.stay_room_menu
+#: model_terms:ir.ui.view,arch_db:stay.report_stayjournalprint_document
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_tree
+#: model_terms:ir.ui.view,arch_db:stay.stay_tree
+msgid "Rooms"
+msgstr "Chambres"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_room_to_clean_action
+#: model:ir.ui.menu,name:stay.stay_room_to_clean_menu
+msgid "Rooms to Clean"
+msgstr "Chambres à nettoyer"
+
+#. module: stay
+#: model:ir.actions.report,name:stay.report_stay_toclean
+msgid "Rooms to clean"
+msgstr "Chambres à nettoyer"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_group__sequence
+#: model:ir.model.fields,field_description:stay.field_stay_refectory__sequence
+#: model:ir.model.fields,field_description:stay.field_stay_room__sequence
+msgid "Sequence"
+msgstr "Séquence"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_settings_action
+#: model:ir.ui.menu,name:stay.stay_settings_menu
+msgid "Settings"
+msgstr "Configuration"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_stay_xlsx_form
+msgid "Show"
+msgstr "Afficher"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form
+msgid "Special stay to mark rooms as unavailable due to construction works."
+msgstr ""
+"Séjour spécial pour rendre des chambres indisponibles à cause de travaux"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__start_date
+#: model:ir.model.fields,field_description:stay.field_stay_stay_xlsx__start_date
+msgid "Start Date"
+msgstr "Date de début"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__state
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "State"
+msgstr "État"
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_stay__activity_state
+msgid ""
+"Status based on activities\n"
+"Overdue: Due date is already passed\n"
+"Today: Activity date is today\n"
+"Planned: Future activities."
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_line__stay_id
+#: model:ir.model.fields,field_description:stay.field_stay_line_mass_update__stay_id
+#: model:ir.model.fields,field_description:stay.field_stay_line_reset__stay_id
+#: model:ir.model.fields,field_description:stay.field_stay_multi_duplicate__stay_id
+#: model:ir.model.fields,field_description:stay.field_stay_room_assign__stay_id
+#: model:ir.module.category,name:stay.module_category_stay
+#: model_terms:ir.ui.view,arch_db:stay.report_stayjournalprint_document
+#: model_terms:ir.ui.view,arch_db:stay.stay_form
+msgid "Stay"
+msgstr "Séjour"
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid ""
+"Stay '%s' has %d guest(s), but its room assignment has a total of %d "
+"guest(s)."
+msgstr ""
+"Le séjour '%s' a %d hôtes, mais des chambres ont été attribuées pour un total de %d hôte(s)."
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid ""
+"Stay '%s' is linked to group '%s', but the room '%s' is linked to group "
+"'%s'."
+msgstr ""
+"Le séjour '%s' est lié au groupe '%s', mais la chambre '%s' est liée au "
+"groupe '%s'."
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "Stay '%s' is not in 'Current' state."
+msgstr "Le séjour '%s' n'est pas à l'état 'En cours'."
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_date_label
+msgid "Stay Date Label"
+msgstr "Libellé de date de séjour"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_group
+msgid "Stay Group"
+msgstr "Groupe de séjour"
+
+#. module: stay
+#: model:ir.actions.report,name:stay.report_stay_journal_print
+#: model:ir.model,name:stay.model_stay_line
+msgid "Stay Journal"
+msgstr "Journal des séjours"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_form
+msgid "Stay Line"
+msgstr "Ligne de séjour"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_line_action
+#: model:ir.model.fields,field_description:stay.field_stay_stay__line_ids
+#: model:ir.ui.menu,name:stay.stay_line_menu
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_graph
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_pivot
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_tree
+msgid "Stay Lines"
+msgstr "Lignes de séjour"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_multi_duplicate_form
+msgid "Stay Multi Duplicate"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__name
+msgid "Stay Number"
+msgstr "Numéro du séjour"
+
+#. module: stay
+#: model:ir.actions.server,name:stay.stay_arrival_notify_cron_ir_actions_server
+#: model:ir.cron,cron_name:stay.stay_arrival_notify_cron
+#: model:ir.cron,name:stay.stay_arrival_notify_cron
+msgid "Stay: notify arrivals"
+msgstr "Séjours : notification des arrivées"
+
+#. module: stay
+#: model:ir.actions.server,name:stay.stay_state_update_cron_ir_actions_server
+#: model:ir.cron,cron_name:stay.stay_state_update_cron
+#: model:ir.cron,name:stay.stay_state_update_cron
+msgid "Stay: update state"
+msgstr "Séjour: mettre à jour l'état"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_action
+#: model:ir.model.fields,field_description:stay.field_res_partner__stay_ids
+#: model:ir.model.fields,field_description:stay.field_res_users__stay_ids
+#: model:ir.ui.menu,name:stay.stay_menu
+#: model:ir.ui.menu,name:stay.stay_sub_menu
+#: model:ir.ui.menu,name:stay.stay_top_menu
+#: model_terms:ir.ui.view,arch_db:stay.res_config_settings_view_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_calendar
+#: model_terms:ir.ui.view,arch_db:stay.stay_graph
+#: model_terms:ir.ui.view,arch_db:stay.stay_pivot
+#: model_terms:ir.ui.view,arch_db:stay.view_partner_form
+msgid "Stays"
+msgstr "Séjours"
+
+#. module: stay
+#: code:addons/stay/wizard/stay_stay_xlsx.py:0
+#, python-format
+msgid "Stays - %s"
+msgstr "Séjours - %s"
+
+#. module: stay
+#: code:addons/stay/wizard/stay_multi_duplicate.py:0
+#, python-format
+msgid "The end date (%s) must be after the start_date (%s)!"
+msgstr "La date de fin ne peut pas etre avant la date de début!"
+
+#. module: stay
+#: model:ir.model.constraint,message:stay.constraint_stay_room_assign_guest_qty_positive
+#: model:ir.model.constraint,message:stay.constraint_stay_stay_guest_qty_positive
+msgid "The guest quantity must be positive."
+msgstr "Le nombre d'hôtes doit être positif."
+
+#. module: stay
+#: model:ir.model.constraint,message:stay.constraint_stay_line_bed_night_qty_positive
+msgid "The number of bed nights must be positive or null."
+msgstr "Le nombre de nuités doit être positif ou nul."
+
+#. module: stay
+#: model:ir.model.constraint,message:stay.constraint_stay_room_bed_qty_positive
+msgid "The number of beds must be positive."
+msgstr "Le nombre de lits doit être positif."
+
+#. module: stay
+#: model:ir.model.constraint,message:stay.constraint_stay_line_dinner_qty_positive
+msgid "The number of dinners must be positive or null."
+msgstr "Le nombre de dîners doit être positif ou nul."
+
+#. module: stay
+#: model:ir.model.constraint,message:stay.constraint_stay_line_lunch_qty_positive
+msgid "The number of lunches must be positive or null."
+msgstr "Le nombre de déjeuners doit être positif ou nul."
+
+#. module: stay
+#: code:addons/stay/wizard/stay_multi_duplicate.py:0
+#, python-format
+msgid "The start date %s is in the past!"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_stay__no_meals
+msgid ""
+"The stay lines generated from this stay will not have lunchs nor dinners by "
+"default."
+msgstr ""
+"Les lignes de séjour générées pour ce séjour n'auront pas de déjeuners ni de"
+" dîners par défaut"
+
+#. module: stay
+#: code:addons/stay/wizard/stay_journal_print.py:0
+#, python-format
+msgid "There are no stays on %s in company %s."
+msgstr "Il n'y a aucun séjour le %s dans la société %s."
+
+#. module: stay
+#: model:ir.model.constraint,message:stay.constraint_stay_date_label_date_uniq
+msgid "This date already exists."
+msgstr "Cette date existe déjà."
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_room__allow_simultaneous
+msgid ""
+"This option applies for rooms where bed quantity > 1. You should enable this"
+" option if you allow to have several stays at the same time in the room."
+msgstr ""
+"Cette option s'applique pour les chambres où le nombe de lits est > 1. Vous "
+"devez activer cette option si vous autorisez d'avoir plusieurs séjours en "
+"même temps dans cette chambre."
+
+#. module: stay
+#: model:ir.model.constraint,message:stay.constraint_stay_room_assign_stay_room_unique
+msgid "This room has already been used in this stay."
+msgstr "Cette chambre a déjà été utilisée pour ce séjour."
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid ""
+"This stay conflicts with stay %s of '%s' from %s %s to %s %s in room %s."
+msgstr ""
+"Ce séjour entre en conflit avec le séjour %s de '%s' du %s %s au %s %s dans "
+"la chambre %s."
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Title:"
+msgstr "Titre"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_search
+msgid "To Assign"
+msgstr "A attribuer"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_room__to_clean
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_form
+#: model_terms:ir.ui.view,arch_db:stay.stay_room_search
+msgid "To Clean"
+msgstr "A nettoyer"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_toclean_print_action
+#: model:ir.ui.menu,name:stay.stay_toclean_print_menu
+#: model_terms:ir.ui.view,arch_db:stay.stay_toclean_print_form
+msgid "To Clean Report"
+msgstr "Rapport ménage"
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_stay__activity_exception_decoration
+msgid "Type of the exception activity on record."
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__arrival_time__unknown
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__departure_time__unknown
+msgid "Unknown"
+msgstr "Inconnue"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_unread
+msgid "Unread Messages"
+msgstr ""
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_stay__message_unread_counter
+msgid "Unread Messages Counter"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form
+msgid "Update All Lines"
+msgstr "Modifier toutes les lignes"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_line_mass_update_form
+msgid "Update All Stay Lines"
+msgstr "Modifier toutes les lignes"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_line_mass_update_action
+msgid "Update all lines"
+msgstr "Modifier toutes les lignes"
+
+#. module: stay
+#: model:res.groups,name:stay.group_stay_user
+msgid "User"
+msgstr "Utilisateur"
+
+#. module: stay
+#: model:ir.model.fields,field_description:stay.field_stay_group__notify_user_ids
+msgid "Users Notified by E-mail"
+msgstr ""
+
+#. module: stay
+#: model:res.groups,name:stay.group_stay_viewer
+msgid "Viewer"
+msgstr "Lecture seule"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_stay__assign_status__none
+msgid "Waiting Assignation"
+msgstr "En attente d'attribution"
+
+#. module: stay
+#: model:ir.model.fields.selection,name:stay.selection__stay_multi_duplicate__frequency__weekly
+msgid "Weekly"
+msgstr "Chaque semaine"
+
+#. module: stay
+#: model:ir.model.fields,help:stay.field_stay_room__to_clean
+msgid ""
+"When the field has a value, it means the room must be cleaned (when a stay "
+"is terminated, this field is auto-set with the stay description). When the "
+"room is cleaned, the field is emptied."
+msgstr ""
+
+#. module: stay
+#: code:addons/stay/models/stay.py:0
+#, python-format
+msgid "You cannot delete stay '%s': you must cancel it first."
+msgstr ""
+"Vous ne pouvez pas supprimer le séjour '%s' : vous devez d'abord l'annuler."
+
+#. module: stay
+#: code:addons/stay/wizard/stay_line_mass_update.py:0
+#, python-format
+msgid ""
+"You must check at least one option! You didn't check any... To reset to "
+"default setttings, please use the appropriate wizard if installed."
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "Your Name and Surname"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_saved_iframe
+msgid "Your stay application was assigned number:"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "email"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "mobile"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "mobile phone number"
+msgstr ""
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_saved_iframe
+msgid "number of guests :"
+msgstr ""
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_line_mass_update
+msgid "wizard to mass update lines"
+msgstr "Assistant pout modifier toutes les lignes de repas."
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_line_reset
+msgid "wizard to reset all lines to default values"
+msgstr "Assistant pour reinitialiser toutes les lignes aux valeurs par défaut"
+
+#. module: stay
+#: model_terms:ir.ui.view,arch_db:stay.stay_form_iframe
+msgid "your email adress"
+msgstr ""
diff --git a/stay/i18n/zh_CN.po b/stay/i18n/zh_CN.po
new file mode 100644
index 00000000..2f3f7e2b
--- /dev/null
+++ b/stay/i18n/zh_CN.po
@@ -0,0 +1,519 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# 	* stay
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 8.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-03-28 12:33+0000\n"
+"PO-Revision-Date: 2015-08-11 21:07+0800\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: \n"
+"Language: zh_CN\n"
+"X-Generator: Poedit 1.7.6\n"
+
+#. module: stay
+#: sql_constraint:stay.refectory:0
+msgid "A refectory with this code already exists."
+msgstr "此餐厅编号已存在。"
+
+#. module: stay
+#: sql_constraint:stay.room:0
+msgid "A room with this code already exists."
+msgstr "此房号已存在。"
+
+#. module: stay
+#: sql_constraint:stay.stay:0
+msgid "A stay with this number already exists for this company."
+msgstr "系统中存在对应该公司的住宿编号。"
+
+#. module: stay
+#: field:stay.refectory,active:0 field:stay.room,active:0
+msgid "Active"
+msgstr "可用"
+
+#. module: stay
+#: selection:stay.stay,arrival_time:0 selection:stay.stay,departure_time:0
+msgid "Afternoon"
+msgstr "下午"
+
+#. module: stay
+#: view:stay.stay:stay.stay_search field:stay.stay,arrival_date:0
+#: view:website:stay.report_stay_journal
+msgid "Arrival Date"
+msgstr "到达日期"
+
+#. module: stay
+#: field:stay.stay,arrival_time:0
+msgid "Arrival Time"
+msgstr "到达时间"
+
+#. module: stay
+#: code:addons/stay/stay.py:93
+#, python-format
+msgid "Arrival date (%s) must be earlier than departure date (%s)"
+msgstr "到达日期 (%s) 必须早于离开日期 (%s)"
+
+#. module: stay
+#: field:stay.line,bed_night_qty:0
+msgid "Bed Nights"
+msgstr "夜宿"
+
+#. module: stay
+#: view:stay.journal.generate:stay.stay_journal_generate_form
+#: view:stay.journal.print:stay.stay_journal_print_form
+msgid "Cancel"
+msgstr "取消"
+
+#. module: stay
+#: field:stay.refectory,capacity:0
+msgid "Capacity"
+msgstr "桌数"
+
+#. module: stay
+#: field:stay.refectory,code:0 field:stay.room,code:0
+msgid "Code"
+msgstr "编号"
+
+#. module: stay
+#: model:ir.model,name:stay.model_res_company
+msgid "Companies"
+msgstr "公司"
+
+#. module: stay
+#: field:stay.line,company_id:0 field:stay.stay,company_id:0
+msgid "Company"
+msgstr "单位"
+
+#. module: stay
+#: model:ir.ui.menu,name:stay.stay_configuration
+msgid "Configuration"
+msgstr "配置"
+
+#. module: stay
+#: field:stay.journal.generate,create_uid:0
+#: field:stay.journal.print,create_uid:0 field:stay.line,create_uid:0
+#: field:stay.refectory,create_uid:0 field:stay.room,create_uid:0
+#: field:stay.stay,create_uid:0
+msgid "Created by"
+msgstr "创建者"
+
+#. module: stay
+#: field:stay.journal.generate,create_date:0
+#: field:stay.journal.print,create_date:0 field:stay.line,create_date:0
+#: field:stay.refectory,create_date:0 field:stay.room,create_date:0
+#: field:stay.stay,create_date:0
+msgid "Created on"
+msgstr "创建于"
+
+#. module: stay
+#: field:stay.journal.generate,date:0 field:stay.journal.print,date:0
+#: view:stay.line:stay.stay_line_search field:stay.line,date:0
+msgid "Date"
+msgstr "日期"
+
+#. module: stay
+#: help:stay.stay,message_last_post:0
+msgid "Date of the last message posted on the record."
+msgstr "记录上最后一条消息的日期。"
+
+#. module: stay
+#: field:res.company,default_refectory_id:0
+msgid "Default Refectory"
+msgstr "默认餐厅"
+
+#. module: stay
+#: field:stay.stay,departure_date:0 view:website:stay.report_stay_journal
+msgid "Departure Date"
+msgstr "离开日期"
+
+#. module: stay
+#: field:stay.stay,departure_time:0
+msgid "Departure Time"
+msgstr "离开时间"
+
+#. module: stay
+#: field:stay.line,dinner_qty:0 view:website:stay.report_stay_journal
+msgid "Dinners"
+msgstr "晚餐"
+
+#. module: stay
+#: field:stay.refectory,display_name:0 field:stay.room,display_name:0
+msgid "Display Name"
+msgstr "显示名称"
+
+#. module: stay
+#: selection:stay.stay,arrival_time:0 selection:stay.stay,departure_time:0
+msgid "Evening"
+msgstr "晚上"
+
+#. module: stay
+#: field:stay.stay,message_follower_ids:0
+msgid "Followers"
+msgstr "随行人员"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_journal_generate_action
+#: model:ir.ui.menu,name:stay.stay_journal_generate_menu
+#: view:stay.journal.generate:stay.stay_journal_generate_form
+msgid "Generate Journal"
+msgstr "生成账本"
+
+#. module: stay
+#: view:stay.journal.generate:stay.stay_journal_generate_form
+msgid "Generate Stay Journal"
+msgstr "生成住宿账本"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_journal_generate
+msgid "Generate the Stay Lines"
+msgstr "生成住宿明细"
+
+#. module: stay
+#: view:stay.line:stay.stay_line_search view:stay.stay:stay.stay_search
+msgid "Group By"
+msgstr "按分组"
+
+#. module: stay
+#: field:stay.line,partner_id:0 field:stay.stay,partner_id:0
+#: view:website:stay.report_stay_journal
+msgid "Guest"
+msgstr "客户"
+
+#. module: stay
+#: view:website:stay.report_stay_journal
+msgid "Guest List"
+msgstr "客户列表"
+
+#. module: stay
+#: field:stay.line,partner_name:0 view:stay.stay:stay.stay_search
+#: field:stay.stay,partner_name:0
+msgid "Guest Name"
+msgstr "客户姓名"
+
+#. module: stay
+#: field:stay.stay,guest_qty:0
+msgid "Guest Quantity"
+msgstr "客户数量"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_stay
+msgid "Guest Stay"
+msgstr "客户住宿"
+
+#. module: stay
+#: model:ir.ui.menu,name:stay.partners
+msgid "Guests"
+msgstr "客户"
+
+#. module: stay
+#: help:stay.stay,message_summary:0
+msgid "Holds the Chatter summary (number of messages, ...). This summary is directly in html format in order to be inserted in kanban views."
+msgstr "总结：唠叨几句吧（此处省略若干字数...）这里可用HTML的格式直插到看板视图里。"
+
+#. module: stay
+#: field:report.stay.report_stay_journal,id:0 field:stay.journal.generate,id:0
+#: field:stay.journal.print,id:0 field:stay.line,id:0
+#: field:stay.refectory,id:0 field:stay.room,id:0 field:stay.stay,id:0
+msgid "ID"
+msgstr "ID"
+
+#. module: stay
+#: help:stay.room,no_meals:0
+msgid "If active, the stays linked to this room will have the same option active by default."
+msgstr "如果激活的话，默认情况下，该房间将有相同的选项。"
+
+#. module: stay
+#: help:stay.stay,message_unread:0
+msgid "If checked new messages require your attention."
+msgstr "如您需要实时反馈新消息您得关注它。"
+
+#. module: stay
+#: help:stay.line,partner_id:0 help:stay.stay,partner_id:0
+msgid "If guest is anonymous, leave this field empty."
+msgstr "若客户匿名，则留空此栏位。"
+
+#. module: stay
+#: field:stay.stay,message_is_follower:0
+msgid "Is a Follower"
+msgstr "该员为随行人员"
+
+#. module: stay
+#: field:stay.stay,message_last_post:0
+msgid "Last Message Date"
+msgstr "末条消息日期"
+
+#. module: stay
+#: field:stay.journal.generate,write_uid:0
+#: field:stay.journal.print,write_uid:0 field:stay.line,write_uid:0
+#: field:stay.refectory,write_uid:0 field:stay.room,write_uid:0
+#: field:stay.stay,write_uid:0
+msgid "Last Updated by"
+msgstr "最后更新于"
+
+#. module: stay
+#: field:stay.journal.generate,write_date:0
+#: field:stay.journal.print,write_date:0 field:stay.line,write_date:0
+#: field:stay.refectory,write_date:0 field:stay.room,write_date:0
+#: field:stay.stay,write_date:0
+msgid "Last Updated on"
+msgstr "最后更新于"
+
+#. module: stay
+#: field:stay.line,lunch_qty:0 view:website:stay.report_stay_journal
+msgid "Lunches"
+msgstr "午餐"
+
+#. module: stay
+#: model:ir.module.category,description:stay.module_category_stay
+msgid "Manage stays (lunch, diner, night, etc...)"
+msgstr "客栈管理(午餐, 晚餐, 夜宿, 等...)"
+
+#. module: stay
+#: model:res.groups,name:stay.group_stay_manager
+msgid "Manager"
+msgstr "经理"
+
+#. module: stay
+#: field:stay.stay,message_ids:0
+msgid "Messages"
+msgstr "消息"
+
+#. module: stay
+#: help:stay.stay,message_ids:0
+msgid "Messages and communication history"
+msgstr "通信历史记录"
+
+#. module: stay
+#: code:addons/stay/wizard/stay_journal_generate.py:88
+#, python-format
+msgid "Missing default refectory on the company '%s'."
+msgstr "未发现此公司默认设定的餐厅 '%s'。"
+
+#. module: stay
+#: code:addons/stay/stay.py:206
+#, python-format
+msgid "Missing refectory for guest '%s' on %s."
+msgstr "未发现客人'%s' 在 %s 的餐厅。"
+
+#. module: stay
+#: selection:stay.stay,arrival_time:0 selection:stay.stay,departure_time:0
+msgid "Morning"
+msgstr "早上"
+
+#. module: stay
+#: field:stay.refectory,name:0 field:stay.room,name:0
+msgid "Name"
+msgstr "名称"
+
+#. module: stay
+#: view:website:stay.report_stay_journal
+msgid "Nights"
+msgstr "晚上"
+
+#. module: stay
+#: field:stay.room,no_meals:0 field:stay.stay,no_meals:0
+msgid "No Meals"
+msgstr "无餐"
+
+#. module: stay
+#: code:addons/stay/wizard/stay_journal_generate.py:119
+#: code:addons/stay/wizard/stay_journal_print.py:53
+#, python-format
+msgid "No stay for this date."
+msgstr "当日无住宿。"
+
+#. module: stay
+#: field:stay.room,bed_qty:0
+msgid "Number of beds"
+msgstr "床数"
+
+#. module: stay
+#: model:ir.model,name:stay.model_res_partner
+#: view:stay.line:stay.stay_line_search
+msgid "Partner"
+msgstr "合作伙伴"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_journal_print_action
+#: model:ir.ui.menu,name:stay.stay_journal_print_menu
+#: view:stay.journal.print:stay.stay_journal_print_form
+msgid "Print Journal"
+msgstr "打印账本"
+
+#. module: stay
+#: view:stay.journal.print:stay.stay_journal_print_form
+msgid "Print Stay Journal"
+msgstr "打印住宿账本"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_journal_print
+msgid "Print the Stay Lines"
+msgstr "打印住宿明细"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_refectory_action
+#: model:ir.ui.menu,name:stay.stay_refectory_menu
+#: view:stay.refectory:stay.stay_refectory_tree
+msgid "Refectories"
+msgstr "餐厅"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_refectory
+#: view:stay.line:stay.stay_line_search field:stay.line,refectory_id:0
+#: view:stay.refectory:stay.stay_refectory_form
+msgid "Refectory"
+msgstr "餐厅"
+
+#. module: stay
+#: model:ir.model,name:stay.model_stay_room field:stay.line,room_id:0
+#: view:stay.room:stay.stay_room_form field:stay.stay,room_id:0
+#: view:website:stay.report_stay_journal
+msgid "Room"
+msgstr "房间"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_room_action
+#: model:ir.ui.menu,name:stay.stay_room_menu
+#: view:stay.room:stay.stay_room_tree
+msgid "Rooms"
+msgstr "房间"
+
+#. module: stay
+#: view:stay.refectory:stay.stay_refectory_search
+msgid "Search Refectories"
+msgstr "搜索餐厅"
+
+#. module: stay
+#: view:stay.room:stay.stay_room_search
+msgid "Search Rooms"
+msgstr "搜索房间"
+
+#. module: stay
+#: view:stay.line:stay.stay_line_search
+msgid "Search Stay Lines"
+msgstr "搜索住宿明细"
+
+#. module: stay
+#: view:stay.stay:stay.stay_search
+msgid "Search Stays"
+msgstr "搜索住宿"
+
+#. module: stay
+#: model:ir.module.category,name:stay.module_category_stay
+#: view:res.company:stay.view_company_form field:stay.line,stay_id:0
+#: view:stay.stay:stay.stay_form view:stay.stay:stay.stay_tree
+msgid "Stay"
+msgstr "住宿"
+
+#. module: stay
+#: model:ir.actions.report.xml,name:stay.action_report_stay_journal
+#: model:ir.model,name:stay.model_stay_line
+msgid "Stay Journal"
+msgstr "住宿账本"
+
+#. module: stay
+#: view:stay.line:stay.stay_line_form
+msgid "Stay Line"
+msgstr "住宿明细"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.stay_line_action
+#: model:ir.ui.menu,name:stay.stay_line_menu
+#: view:stay.line:stay.stay_line_graph view:stay.line:stay.stay_line_tree
+#: field:stay.stay,line_ids:0
+msgid "Stay Lines"
+msgstr "住宿明细"
+
+#. module: stay
+#: view:website:stay.report_stay_journal
+msgid "Stay Nr"
+msgstr "住宿编号"
+
+#. module: stay
+#: field:stay.stay,name:0
+msgid "Stay Number"
+msgstr "住宿编号"
+
+#. module: stay
+#: model:ir.actions.act_window,name:stay.partner_stay_action
+#: model:ir.actions.act_window,name:stay.stay_action
+#: model:ir.ui.menu,name:stay.stay_menu
+#: model:ir.ui.menu,name:stay.stay_sub_menu
+#: model:ir.ui.menu,name:stay.stay_top_menu
+#: view:res.partner:stay.view_partner_form field:res.partner,stay_ids:0
+#: view:stay.stay:stay.stay_graph
+msgid "Stays"
+msgstr "住宿"
+
+#. module: stay
+#: view:website:stay.report_stay_journal
+msgid "Sub-totals:"
+msgstr "小计："
+
+#. module: stay
+#: field:stay.stay,message_summary:0
+msgid "Summary"
+msgstr "总结"
+
+#. module: stay
+#: code:addons/stay/stay.py:85
+#, python-format
+msgid "TO WRITE"
+msgstr "写入"
+
+#. module: stay
+#: sql_constraint:stay.line:0
+msgid "The number of bed nights must be positive or null"
+msgstr "夜宿数值必须为正数或null。"
+
+#. module: stay
+#: sql_constraint:stay.line:0
+msgid "The number of dinners must be positive or null"
+msgstr "晚餐数值必须为正数或null。"
+
+#. module: stay
+#: sql_constraint:stay.line:0
+msgid "The number of lunches must be positive or null"
+msgstr "午餐数值必须为正数或null。"
+
+#. module: stay
+#: code:addons/stay/stay.py:218
+#, python-format
+msgid "The room '%s' is booked or all beds of the room are booked"
+msgstr "此房间 '%s' 已预订或房间暂无床位。"
+
+#. module: stay
+#: help:stay.stay,no_meals:0
+msgid "The stay lines generated from this stay will not have lunchs nor dinners by default."
+msgstr "从这里生成的住宿清单明细默认不含午餐晚餐在内。"
+
+#. module: stay
+#: view:stay.line:stay.stay_line_tree
+msgid "Total Bed Nights"
+msgstr "夜宿总计"
+
+#. module: stay
+#: view:stay.line:stay.stay_line_tree
+msgid "Total Dinners"
+msgstr "晚餐总计"
+
+#. module: stay
+#: view:stay.line:stay.stay_line_tree
+msgid "Total Lunches"
+msgstr "午餐总计"
+
+#. module: stay
+#: field:stay.stay,message_unread:0
+msgid "Unread Messages"
+msgstr "未读信息"
+
+#. module: stay
+#: model:res.groups,name:stay.group_stay_user
+msgid "User"
+msgstr "用户"
diff --git a/stay/models/__init__.py b/stay/models/__init__.py
new file mode 100644
index 00000000..eb63613c
--- /dev/null
+++ b/stay/models/__init__.py
@@ -0,0 +1,3 @@
+from . import stay
+from . import res_company
+from . import res_partner
diff --git a/stay/models/res_company.py b/stay/models/res_company.py
new file mode 100644
index 00000000..d042382b
--- /dev/null
+++ b/stay/models/res_company.py
@@ -0,0 +1,18 @@
+# Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+# Copyright 2014-2021 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# @author: Brother Bernard <informatique@barroux.org>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class ResCompany(models.Model):
+    _inherit = "res.company"
+
+    default_refectory_id = fields.Many2one(
+        "stay.refectory",
+        string="Default Refectory",
+        ondelete="restrict",
+        check_company=True,
+    )
diff --git a/stay/models/res_partner.py b/stay/models/res_partner.py
new file mode 100644
index 00000000..34722393
--- /dev/null
+++ b/stay/models/res_partner.py
@@ -0,0 +1,28 @@
+# Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+# Copyright 2014-2021 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# @author: Brother Bernard <informatique@barroux.org>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import api, fields, models
+
+
+class ResPartner(models.Model):
+    _inherit = "res.partner"
+
+    @api.depends("stay_ids.partner_id")
+    def _compute_stay_count(self):
+        rg_res = self.env["stay.stay"].read_group(
+            [("partner_id", "in", self.ids)], ["partner_id"], ["partner_id"]
+        )
+        mapped_data = {x["partner_id"][0]: x["partner_id_count"] for x in rg_res}
+        for partner in self:
+            partner.stay_count = mapped_data.get(partner.id, 0)
+
+    stay_ids = fields.One2many("stay.stay", "partner_id", string="Stays")
+    stay_count = fields.Integer(
+        compute="_compute_stay_count",
+        string="# of Stays",
+        readonly=True,
+        compute_sudo=True,
+    )
diff --git a/stay/models/stay.py b/stay/models/stay.py
new file mode 100644
index 00000000..1eb7753a
--- /dev/null
+++ b/stay/models/stay.py
@@ -0,0 +1,1257 @@
+# Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+# Copyright 2014-2021 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# @author: Brother Bernard <informatique@barroux.org>
+# @author: Brother Irénée
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+import logging
+from collections import defaultdict
+from datetime import datetime
+from textwrap import shorten
+
+import pytz
+from dateutil.relativedelta import relativedelta
+
+from odoo import SUPERUSER_ID, _, api, fields, models
+from odoo.exceptions import UserError, ValidationError
+from odoo.osv import expression
+from odoo.tools.misc import format_date
+
+logger = logging.getLogger(__name__)
+
+TIMEDICT = {
+    "morning": "09:00",
+    "afternoon": "15:00",
+    "evening": "20:00",
+    "unknown": "08:00",
+}
+TIME2CODE = {
+    "morning": _("Mo"),
+    "afternoon": _("Af"),
+    "evening": _("Ev"),
+}
+
+
+class StayStay(models.Model):
+    _name = "stay.stay"
+    _description = "Guest Stay"
+    _order = "arrival_date desc"
+    _inherit = ["mail.thread", "mail.activity.mixin"]
+    _check_company_auto = True
+
+    name = fields.Char(string="Stay Number", default="/", copy=False)
+    company_id = fields.Many2one(
+        "res.company",
+        string="Company",
+        required=True,
+        default=lambda self: self.env.company,
+        readonly=True,
+        states={"draft": [("readonly", False)]},
+    )
+    partner_id = fields.Many2one(
+        "res.partner",
+        string="Guest",
+        ondelete="restrict",
+        help="If guest is anonymous, leave this field empty.",
+    )
+    partner_name = fields.Text("Guest Names", required=True, tracking=True)
+    guest_qty = fields.Integer(string="Guest Quantity", default=1, tracking=True)
+    arrival_date = fields.Date(
+        string="Arrival Date", required=True, tracking=True, index=True
+    )
+    arrival_time = fields.Selection(
+        [
+            ("morning", "Morning"),
+            ("afternoon", "Afternoon"),
+            ("evening", "Evening"),
+            ("unknown", "Unknown"),
+        ],
+        string="Arrival Time",
+        required=True,
+        tracking=True,
+    )
+    arrival_datetime = fields.Datetime(
+        compute="_compute_arrival_datetime",
+        inverse="_inverse_arrival_datetime",
+        store=True,
+        string="Arrival Date and Time",
+    )
+    arrival_note = fields.Char(string="Arrival Note")
+    departure_date = fields.Date(
+        string="Departure Date", required=True, tracking=True, index=True
+    )
+    departure_time = fields.Selection(
+        [
+            ("morning", "Morning"),
+            ("afternoon", "Afternoon"),
+            ("evening", "Evening"),
+            ("unknown", "Unknown"),
+        ],
+        string="Departure Time",
+        required=True,
+        tracking=True,
+    )
+    departure_datetime = fields.Datetime(
+        compute="_compute_departure_datetime",
+        inverse="_inverse_departure_datetime",
+        store=True,
+        string="Departure Date and Time",
+    )
+    departure_note = fields.Char(string="Departure Note")
+    notes = fields.Text()
+    room_assign_ids = fields.One2many(
+        "stay.room.assign",
+        "stay_id",
+        string="Room Assignments",
+        states={"draft": [("readonly", True)], "cancel": [("readonly", True)]},
+        copy=True,
+    )
+    # Here, group_id is not a related of room, because we want to be able
+    # to first set the group and later set the room
+    group_id = fields.Many2one(
+        "stay.group",
+        string="Group",
+        tracking=True,
+        copy=False,
+        domain="[('company_id', '=', company_id)]",
+        ondelete="restrict",
+        check_company=True,
+    )
+    # to workaround the bug https://github.com/OCA/web/issues/1446
+    # in v12+, if this PR is merged https://github.com/OCA/web/issues/1446
+    # the we could use color_field
+    user_id = fields.Many2one(related="group_id.user_id", store=True)
+    line_ids = fields.One2many(
+        "stay.line",
+        "stay_id",
+        string="Stay Lines",
+        states={"draft": [("readonly", True)], "cancel": [("readonly", True)]},
+    )
+    refectory_id = fields.Many2one(
+        "stay.refectory",
+        string="Refectory",
+        check_company=True,
+        default=lambda self: self.env.company.default_refectory_id,
+    )
+    no_meals = fields.Boolean(
+        string="No Meals",
+        tracking=True,
+        help="The stay lines generated from this stay will not have "
+        "lunchs nor dinners by default.",
+    )
+    construction = fields.Boolean()
+    rooms_display_name = fields.Char(
+        compute="_compute_room_assignment", string="Rooms", store=True
+    )
+    assign_status = fields.Selection(
+        [
+            ("none", "Waiting Assignation"),
+            ("no_night", "No Nights"),
+            ("partial", "Partial"),
+            ("assigned", "Assigned"),
+            ("over-assigned", "Over Assigned"),
+            ("error", "Error"),
+        ],
+        string="Assign Status",
+        compute="_compute_room_assignment",
+        store=True,
+    )
+    guest_qty_to_assign = fields.Integer(compute="_compute_room_assignment", store=True)
+    state = fields.Selection(
+        [
+            ("draft", "Draft"),
+            ("confirm", "Confirmed"),
+            ("current", "Current"),
+            ("done", "Finished"),
+            ("cancel", "Cancelled"),
+        ],
+        readonly=True,
+        default="draft",
+        tracking=True,
+        copy=False,
+    )
+
+    _sql_constraints = [
+        (
+            "name_company_uniq",
+            "unique(name, company_id)",
+            "A stay with this number already exists for this company.",
+        ),
+        (
+            "guest_qty_positive",
+            "CHECK(guest_qty > 0)",
+            "The guest quantity must be positive.",
+        ),
+    ]
+
+    @api.depends(
+        "room_assign_ids.guest_qty",
+        "room_assign_ids.room_id",
+        "departure_date",
+        "arrival_date",
+        "guest_qty",
+        "state",
+    )
+    def _compute_room_assignment(self):
+        for stay in self:
+            guest_qty_to_assign = stay.guest_qty
+            room_codes = []
+            for assign in stay.room_assign_ids:
+                guest_qty_to_assign -= assign.guest_qty
+                room_codes.append(assign.room_id.code or assign.room_id.name)
+            if room_codes:
+                rooms_display_name = "-".join(room_codes)
+            else:
+                rooms_display_name = "\u2205"
+
+            if stay.state in ("draft", "cancel"):
+                assign_status = False
+            elif not guest_qty_to_assign:
+                assign_status = "assigned"
+            elif stay.arrival_date == stay.departure_date:
+                assign_status = "no_night"
+            elif guest_qty_to_assign == stay.guest_qty:
+                assign_status = "none"
+            elif guest_qty_to_assign > 0:
+                assign_status = "partial"
+            elif guest_qty_to_assign < 0:
+                assign_status = "over-assigned"
+            else:
+                assign_status = "error"
+            stay.assign_status = assign_status
+            stay.guest_qty_to_assign = guest_qty_to_assign
+            stay.rooms_display_name = rooms_display_name
+
+    @api.model
+    def create(self, vals):
+        if vals.get("name", "/") == "/":
+            vals["name"] = self.env["ir.sequence"].next_by_code("stay.stay")
+        return super().create(vals)
+
+    @api.model
+    def _convert_to_datetime_naive_utc(self, date, time_sel):
+        # Convert from local time to datetime naive UTC
+        datetime_str = "%s %s" % (date, TIMEDICT[time_sel])
+        datetime_naive = datetime.strptime(datetime_str, "%Y-%m-%d %H:%M")
+        admin_user = self.env["res.users"].browse(SUPERUSER_ID)
+        if admin_user.tz:
+            logger.debug(
+                "The timezone of admin user (ID %d) is %s", SUPERUSER_ID, admin_user.tz
+            )
+            admin_tz = pytz.timezone(admin_user.tz)
+        else:
+            logger.warning("The timezone of admin user (ID %d) is empty!", SUPERUSER_ID)
+            admin_tz = pytz.utc
+        datetime_aware_admin_tz = admin_tz.localize(datetime_naive)
+        datetime_aware_utc = datetime_aware_admin_tz.astimezone(pytz.utc)
+        datetime_naive_utc = datetime_aware_utc.replace(tzinfo=None)
+        return datetime_naive_utc
+
+    @api.model
+    def _convert_to_date_and_time_selection(self, date_naive_utc):
+        # Convert from datetime naive UTC to local time
+        date_aware_utc = pytz.utc.localize(date_naive_utc)
+        tz = pytz.timezone(self.env.user.tz)
+        date_aware_local = date_aware_utc.astimezone(tz)
+        if date_aware_local.hour < 12:
+            time_selection = "morning"
+        elif date_aware_local.hour < 18:
+            time_selection = "afternoon"
+        else:
+            time_selection = "evening"
+        return date_aware_local.date(), time_selection
+
+    @api.depends("arrival_date", "arrival_time")
+    def _compute_arrival_datetime(self):
+        for stay in self:
+            datetime_naive_utc = False
+            if (
+                stay.arrival_date
+                and stay.arrival_time
+                and stay.arrival_time != "unknown"
+            ):
+                datetime_naive_utc = self._convert_to_datetime_naive_utc(
+                    stay.arrival_date, stay.arrival_time
+                )
+            stay.arrival_datetime = datetime_naive_utc
+
+    @api.depends("departure_date", "departure_time")
+    def _compute_departure_datetime(self):
+        for stay in self:
+            datetime_naive_utc = False
+            if (
+                stay.departure_date
+                and stay.departure_time
+                and stay.departure_time != "unknown"
+            ):
+                datetime_naive_utc = self._convert_to_datetime_naive_utc(
+                    stay.departure_date, stay.departure_time
+                )
+            stay.departure_datetime = datetime_naive_utc
+
+    # Used for the calendar view
+    @api.onchange("departure_datetime")
+    def _inverse_departure_datetime(self):
+        for stay in self:
+            if stay.departure_datetime:
+                (
+                    departure_date,
+                    departure_time,
+                ) = self._convert_to_date_and_time_selection(stay.departure_datetime)
+                stay.departure_date = departure_date
+                self.departure_time = departure_time
+
+    @api.onchange("arrival_datetime")
+    def _inverse_arrival_datetime(self):
+        for stay in self:
+            if stay.arrival_datetime:
+                arrival_date, arrival_time = self._convert_to_date_and_time_selection(
+                    stay.arrival_datetime
+                )
+                stay.arrival_date = arrival_date
+                stay.arrival_time = arrival_time
+
+    @api.onchange("arrival_date")
+    def arrival_date_change(self):
+        if self.arrival_date and (
+            not self.departure_date or self.departure_date < self.arrival_date
+        ):
+            self.departure_date = self.arrival_date
+
+    @api.model
+    def default_get(self, fields_list):
+        res = super().default_get(fields_list)
+        if res.get("construction"):
+            res.update(
+                {
+                    "partner_name": _("CONSTRUCTION"),
+                    "arrival_time": "morning",
+                    "departure_time": "evening",
+                    "state": "confirm",
+                }
+            )
+        return res
+
+    @api.constrains(
+        "departure_date",
+        "departure_time",
+        "arrival_date",
+        "arrival_time",
+        "room_assign_ids",
+        "group_id",
+        "guest_qty",
+        "state",
+    )
+    def _check_stay(self):
+        for stay in self:
+            if stay.arrival_time == "unknown" and stay.state not in ("draft", "cancel"):
+                raise ValidationError(
+                    _(
+                        "Arrival time cannot be set to unknown"
+                        "if the stay is confirmed!"
+                    )
+                )
+            if stay.departure_time == "unknown" and stay.state not in (
+                "draft",
+                "cancel",
+            ):
+                raise ValidationError(
+                    _(
+                        "Departure Time cannot be set to unknown if the stay is "
+                        "confirmed."
+                    )
+                )
+            if stay.arrival_date > stay.departure_date:
+                raise ValidationError(
+                    _("Arrival date (%s) cannot be after " "departure date (%s)!")
+                    % (
+                        format_date(self.env, stay.arrival_date),
+                        format_date(self.env, stay.departure_date),
+                    )
+                )
+            if stay.arrival_date == stay.departure_date:
+                if stay.departure_time == "morning":
+                    raise ValidationError(
+                        _(
+                            "For a stay without night, the departure time "
+                            "can only be afternoon or evening."
+                        )
+                    )
+                elif (
+                    stay.departure_time == "afternoon"
+                    and stay.arrival_time != "morning"
+                ):
+                    raise ValidationError(
+                        _(
+                            "For a stay without night, when the departure time "
+                            "is afternoon, the arrival time must be morning."
+                        )
+                    )
+                elif stay.departure_time == "evening" and stay.arrival_time not in (
+                    "morning",
+                    "afternoon",
+                ):
+                    raise ValidationError(
+                        _(
+                            "For a stay without night, when the departure time "
+                            "is evening, the arrival time must be morning "
+                            "or afternoon."
+                        )
+                    )
+            if stay.room_assign_ids:
+                group2room = {}
+                # Only one loop on rooms, to improve perfs
+                for room_assign in stay.room_assign_ids:
+                    if room_assign.room_id.group_id:
+                        group2room[room_assign.room_id.group_id] = room_assign.room_id
+                if stay.group_id:
+                    for group, room in group2room.items():
+                        if group != stay.group_id:
+                            raise ValidationError(
+                                _(
+                                    "Stay '%s' is linked to group '%s', but the "
+                                    "room '%s' is linked to group '%s'."
+                                )
+                                % (
+                                    stay.display_name,
+                                    stay.group_id.display_name,
+                                    room.display_name,
+                                    group.display_name,
+                                )
+                            )
+
+    @api.depends("partner_name", "name", "rooms_display_name", "state")
+    def name_get(self):
+        res = []
+        state2label = dict(self.fields_get("state", "selection")["state"]["selection"])
+        for stay in self:
+            state = state2label.get(stay.state)
+            short_partner_name = shorten(stay.partner_name, 35)
+            if self._context.get("stay_name_get_partner_name"):
+                name = "%s, %s" % (short_partner_name, state)
+            elif self._context.get("stay_name_get_partner_name_qty"):
+                name = "%s (%d), %s" % (short_partner_name, stay.guest_qty, state)
+            elif self._context.get("stay_name_get_partner_name_qty_room"):
+                name = "%s (%d)" % (short_partner_name, stay.guest_qty)
+                if stay.rooms_display_name:
+                    name += " [%s]" % stay.rooms_display_name
+                name += ", %s" % state
+            else:
+                name = "%s, %s" % (stay.name, state)
+            res.append((stay.id, name))
+        return res
+
+    @api.onchange("partner_id")
+    def partner_id_change(self):
+        if self.partner_id:
+            partner = self.partner_id
+            partner_name = partner.name
+            if partner.title and not partner.is_company:
+                partner_lg = partner
+                if partner.lang:
+                    partner_lg = partner.with_context(lang=partner.lang)
+                title = partner_lg.title.shortcut or partner_lg.title.name
+                partner_name = "%s %s" % (title, partner_name)
+            self.partner_name = partner_name
+
+    @api.onchange("group_id")
+    def group_id_change(self):
+        if self.group_id and self.group_id.default_refectory_id:
+            self.refectory_id = self.group_id.default_refectory_id
+
+    def _prepare_stay_line(self, date):  # noqa: C901
+        self.ensure_one()
+        refectory_id = False
+        if self.refectory_id:
+            refectory_id = self.refectory_id.id
+        elif self.group_id and self.group_id.default_refectory_id:
+            refectory_id = self.group_id.default_refectory_id.id
+        elif self.company_id.default_refectory_id:
+            refectory_id = self.company_id.default_refectory_id.id
+        vals = {
+            "date": date,
+            "stay_id": self.id,
+            "partner_id": self.partner_id.id,
+            "partner_name": self.partner_name,
+            "refectory_id": refectory_id,
+            "company_id": self.company_id.id,
+            "breakfast_qty": 0,
+            "lunch_qty": 0,
+            "dinner_qty": 0,
+            "bed_night_qty": 0,
+        }
+        if date == self.arrival_date and date == self.departure_date:
+            if self.arrival_time == "morning":
+                # then departure_time is afternoon or evening
+                vals["lunch_qty"] = self.guest_qty
+                if self.departure_time == "evening":
+                    vals["dinner_qty"] = self.guest_qty
+            elif self.arrival_time == "afternoon":
+                # then departure_time is evening
+                vals["dinner_qty"] = self.guest_qty
+        elif date == self.arrival_date:
+            vals["bed_night_qty"] = self.guest_qty
+            if self.arrival_time == "morning":
+                vals["lunch_qty"] = self.guest_qty
+                vals["dinner_qty"] = self.guest_qty
+            elif self.arrival_time == "afternoon":
+                vals["dinner_qty"] = self.guest_qty
+        elif date == self.departure_date:
+            vals["breakfast_qty"] = self.guest_qty
+            if self.departure_time == "morning":
+                # When 'Manage breakfast' is not enable, we avoid to generate
+                # a stay line for the last day if they leave in the morning
+                if not self.env.user.has_group("stay.group_stay_breakfast"):
+                    return {}
+            elif self.departure_time == "afternoon":
+                vals["lunch_qty"] = self.guest_qty
+            elif self.departure_time == "evening":
+                vals["lunch_qty"] = self.guest_qty
+                vals["dinner_qty"] = self.guest_qty
+        else:
+            vals.update(
+                {
+                    "breakfast_qty": self.guest_qty,
+                    "lunch_qty": self.guest_qty,
+                    "dinner_qty": self.guest_qty,
+                    "bed_night_qty": self.guest_qty,
+                }
+            )
+        if self.no_meals:
+            vals.update(
+                {
+                    "breakfast_qty": 0,
+                    "lunch_qty": 0,
+                    "dinner_qty": 0,
+                    "refectory_id": False,
+                }
+            )
+        return vals
+
+    def _update_lines(self, previous_vals=None):
+        self.ensure_one()
+        if self.construction:
+            return
+
+        slo = self.env["stay.line"]
+        if previous_vals:
+            domain = [("stay_id", "=", self.id)]
+            if (
+                previous_vals["guest_qty"] == self.guest_qty
+                and previous_vals["no_meals"] == self.no_meals
+            ):
+                # delete dates out of scope
+                domain_dates = expression.OR(
+                    [
+                        [("date", "<", self.arrival_date)],
+                        [("date", ">", self.departure_date)],
+                    ]
+                )
+                # if arrival_date or time has changed, also delete old arrival line
+                if (
+                    previous_vals["arrival_date"] != self.arrival_date
+                    or previous_vals["arrival_time"] != self.arrival_time
+                ):
+                    # delete old and new arrival date
+                    domain_dates = expression.OR(
+                        [
+                            domain_dates,
+                            [("date", "=", self.arrival_date)],
+                            [("date", "=", previous_vals["arrival_date"])],
+                        ]
+                    )
+                # if departure_date has changed, also delete old departure line
+                if (
+                    previous_vals["departure_date"] != self.departure_date
+                    or previous_vals["departure_time"] != self.departure_time
+                ):
+                    domain_dates = expression.OR(
+                        [
+                            domain_dates,
+                            [("date", "=", self.departure_date)],
+                            [("date", "=", previous_vals["departure_date"])],
+                        ]
+                    )
+                domain = expression.AND([domain, domain_dates])
+            lines_to_delete = slo.search(domain)
+            lines_to_delete.unlink()
+
+        date = self.arrival_date
+        existing_dates = [line.date for line in self.line_ids]
+        while date <= self.departure_date:
+            if date not in existing_dates:
+                vals = self._prepare_stay_line(date)
+                if vals:
+                    slo.create(vals)
+            date += relativedelta(days=1)
+
+    def write(self, vals):
+        stay2previous_vals = {}
+        if not self._context.get("stay_no_auto_update"):
+            for stay in self:
+                if stay.line_ids:
+                    stay2previous_vals[stay.id] = {
+                        "arrival_date": stay.arrival_date,
+                        "arrival_time": stay.arrival_time,
+                        "departure_date": stay.departure_date,
+                        "departure_time": stay.departure_time,
+                        "guest_qty": stay.guest_qty,
+                        "no_meals": stay.no_meals,
+                    }
+        res = super().write(vals)
+        if not self._context.get("stay_no_auto_update"):
+            today = fields.Date.context_today(self)
+            for stay in self:
+                if stay.state not in ("draft", "cancel"):
+                    stay._update_lines(stay2previous_vals.get(stay.id))
+                    stay._update_state(today)
+        return res
+
+    def _prepare_to_clean_info(self):
+        self.ensure_one()
+        to_clean = "%s %s (%d)" % (
+            self.name,
+            shorten(self.partner_name, 35),
+            self.guest_qty,
+        )
+        return to_clean
+
+    def _set_to_clean(self):
+        for stay in self:
+            for aline in stay.room_assign_ids:
+                aline.room_id.write({"to_clean": stay._prepare_to_clean_info()})
+
+    def _update_state(self, today):
+        self.ensure_one()
+        if self.state in ("confirm", "current") and self.departure_date < today:
+            self.with_context(stay_no_auto_update=True).write({"state": "done"})
+            self._set_to_clean()
+        elif (
+            self.state == "confirm"
+            and self.arrival_date <= today
+            and self.departure_date >= today
+        ):
+            self.with_context(stay_no_auto_update=True).write({"state": "current"})
+        elif self.state in ("current", "done") and self.arrival_date > today:
+            self.with_context(stay_no_auto_update=True).write({"state": "confirm"})
+
+    # No need to call update_state() nor _update_lines() upon create
+    # because stays are always created as draft
+
+    def unlink(self):
+        for stay in self:
+            if stay.state not in ("draft", "cancel"):
+                raise UserError(
+                    _("You cannot delete stay '%s': you must cancel it first.")
+                    % stay.display_name
+                )
+        return super().unlink()
+
+    def draft2confirm(self):
+        self.ensure_one()
+        assert self.state == "draft"
+        assert not self.line_ids
+        self.write({"state": "confirm"})
+        # write() will generate the stay lines
+
+    def cancel(self):
+        self.ensure_one()
+        self.room_assign_ids.unlink()
+        self.line_ids.unlink()
+        self.with_context(stay_no_auto_update=True).write({"state": "cancel"})
+
+    def cancel2draft(self):
+        self.ensure_one()
+        assert self.state == "cancel"
+        self.room_assign_ids.unlink()
+        self.line_ids.unlink()
+        self.with_context(stay_no_auto_update=True).write({"state": "draft"})
+
+    def guest_has_left(self):
+        today = fields.Date.context_today(self)
+        for stay in self:
+            if stay.state != "current":
+                raise UserError(
+                    _("Stay '%s' is not in 'Current' state.") % stay.display_name
+                )
+            vals = {"state": "done"}
+            if stay.departure_date > today:
+                vals["departure_date"] = today
+                stay.message_post(body=_("Guest has left before the end of his stay."))
+            stay.write(vals)
+            stay._set_to_clean()
+
+    @api.model
+    def _cron_stay_state_update(self):
+        logger.info("Start Cron stay state update")
+        today_dt = fields.Date.context_today(self)
+        to_done = self.search(
+            [("state", "in", ("confirm", "current")), ("departure_date", "<", today_dt)]
+        )
+        to_done.with_context(stay_no_auto_update=True).write({"state": "done"})
+        to_done._set_to_clean()
+        to_current = self.search(
+            [
+                ("state", "=", "confirm"),
+                ("arrival_date", "<=", today_dt),
+                ("departure_date", ">=", today_dt),
+            ]
+        )
+        to_current.with_context(stay_no_auto_update=True).write({"state": "current"})
+        to_cancel = self.search(
+            [("state", "=", "draft"), ("departure_date", "<", today_dt)]
+        )
+        to_cancel.write({"state": "cancel"})
+        logger.info("End cron stay state update")
+
+
+class StayRoomAssign(models.Model):
+    _name = "stay.room.assign"
+    _description = "Room assignments"
+    _check_company_auto = True
+
+    stay_id = fields.Many2one("stay.stay", ondelete="cascade", index=True)
+    room_id = fields.Many2one(
+        "stay.room",
+        required=True,
+        ondelete="restrict",
+        index=True,
+        check_company=True,
+        domain="[('id', 'in', room_domain_ids)]",
+    )
+    room_domain_ids = fields.Many2many(
+        "stay.room", compute="_compute_room_domain_ids", string="Available Rooms"
+    )
+    guest_qty = fields.Integer(string="Guest Quantity", required=True)
+    # Related fields
+    group_id = fields.Many2one(related="room_id.group_id", store=True)
+    stay_group_id = fields.Many2one(
+        related="stay_id.group_id", store=True, string="Stay Group"
+    )
+    # The field group_id_integer is used for colors in timeline view
+    group_id_integer = fields.Integer(related="room_id.group_id.id", string="Group ID")
+    user_id = fields.Many2one(related="room_id.group_id.user_id", store=True)
+    arrival_date = fields.Date(related="stay_id.arrival_date", store=True)
+    arrival_time = fields.Selection(related="stay_id.arrival_time", store=True)
+    arrival_datetime = fields.Datetime(related="stay_id.arrival_datetime", store=True)
+    departure_date = fields.Date(related="stay_id.departure_date", store=True)
+    departure_time = fields.Selection(related="stay_id.departure_time", store=True)
+    departure_datetime = fields.Datetime(
+        related="stay_id.departure_datetime", store=True
+    )
+    partner_id = fields.Many2one(related="stay_id.partner_id", store=True)
+    partner_name = fields.Text(related="stay_id.partner_name", store=True)
+    company_id = fields.Many2one(related="stay_id.company_id", store=True)
+
+    _sql_constraints = [
+        (
+            "guest_qty_positive",
+            "CHECK(guest_qty > 0)",
+            "The guest quantity must be positive.",
+        ),
+        (
+            "stay_room_unique",
+            "unique(stay_id, room_id)",
+            "This room has already been used in this stay.",
+        ),
+    ]
+
+    @api.constrains("room_id", "guest_qty", "arrival_datetime", "departure_datetime")
+    def _check_room_assign(self):
+        for assign in self:
+            if assign.guest_qty > assign.room_id.bed_qty:
+                raise UserError(
+                    _("Room %s only has %d bed capacity, not %d!")
+                    % (
+                        assign.room_id.display_name,
+                        assign.room_id.bed_qty,
+                        assign.guest_qty,
+                    )
+                )
+            if assign.room_id:
+                if assign.room_id.bed_qty > 1 and assign.room_id.allow_simultaneous:
+                    assign._check_reservation_conflict_multi()
+                else:
+                    assign._check_reservation_conflict_single()
+
+    def _check_reservation_conflict_single(self):
+        self.ensure_one()
+        assert self.room_id
+        # No conflict IF :
+        # leaves before my arrival (or same day)
+        # OR arrivers after my departure (or same day)
+        # CONTRARY :
+        # leaves after my arrival
+        # AND arrives before my departure
+        conflict_assign = self.search(
+            [
+                ("id", "!=", self.id),
+                ("room_id", "=", self.room_id.id),
+                ("departure_datetime", ">=", self.arrival_datetime),
+                ("arrival_datetime", "<=", self.departure_datetime),
+            ],
+            limit=1,
+        )
+        if conflict_assign:
+            conflict_stay = conflict_assign.stay_id
+            raise ValidationError(
+                _(
+                    "This stay conflicts with stay %s of '%s' "
+                    "from %s %s to %s %s in room %s."
+                )
+                % (
+                    conflict_stay.name,
+                    conflict_stay.partner_name,
+                    format_date(self.env, conflict_stay.arrival_date),
+                    conflict_stay._fields["arrival_time"].convert_to_export(
+                        conflict_stay.arrival_time, conflict_stay
+                    ),
+                    format_date(self.env, conflict_stay.departure_date),
+                    conflict_stay._fields["departure_time"].convert_to_export(
+                        conflict_stay.departure_time, conflict_stay
+                    ),
+                    conflict_assign.room_id.display_name,
+                )
+            )
+
+    def _check_reservation_conflict_multi(self):
+        self.ensure_one()
+        assert self.room_id
+        guest_qty = self.guest_qty
+        bed_qty = self.room_id.bed_qty
+        assert bed_qty > 1
+        assert guest_qty <= bed_qty
+        assert self.arrival_date < self.departure_date
+        date = self.arrival_date
+        departure_date = self.departure_date
+        while date < departure_date:
+            rg_res = self.read_group(
+                [
+                    ("room_id", "=", self.room_id.id),
+                    ("arrival_date", "<=", date),
+                    ("departure_date", ">", date),
+                ],
+                ["guest_qty"],
+                [],
+            )
+            # The result includes the current stay
+            qty = rg_res and rg_res[0]["guest_qty"] or 0
+            if qty > bed_qty:
+                raise ValidationError(
+                    _(
+                        "Conflict in room %s: with stay '%s', we would have a total of "
+                        "%d guests on %s whereas that room only has %d beds."
+                    )
+                    % (
+                        self.room_id.display_name,
+                        self.stay_id.name,
+                        qty,
+                        format_date(self.env, date),
+                        bed_qty,
+                    )
+                )
+            date += relativedelta(days=1)
+
+    @api.depends(
+        "stay_id",
+        "stay_group_id",
+        "room_id",
+        "company_id",
+        "arrival_datetime",
+        "departure_datetime",
+    )
+    def _compute_room_domain_ids(self):
+        # Current implementation:
+        # we exlude ONLY single rooms and
+        # multi-bed-rooms with allow_simultaneous = False
+        # that are already occupied (we call them "potential_excl_rooms")
+        # For that, we must search on conflicting assignments linked to
+        # those rooms only
+        sro = self.env["stay.room"]
+        company_id2potential_excl_room_ids = defaultdict(list)
+        room_sr = sro.search_read([("allow_simultaneous", "=", False)], ["company_id"])
+        for room in room_sr:
+            company_id = room["company_id"][0]
+            company_id2potential_excl_room_ids[company_id].append(room["id"])
+
+        for assign in self:
+            company_id = assign.company_id.id or self.env.company.id
+            potential_excl_room_ids = company_id2potential_excl_room_ids.get(
+                company_id, []
+            )
+
+            conflict_domain = [
+                ("room_id", "in", potential_excl_room_ids),
+                ("departure_datetime", ">=", assign.arrival_datetime),
+                ("arrival_datetime", "<=", assign.departure_datetime),
+            ]
+            if assign._origin.id:
+                conflict_domain.append(("id", "!=", assign._origin.id))
+            conflict_assigns = self.search_read(conflict_domain, ["room_id"])
+            conflict_rooms = {x["room_id"][0]: True for x in conflict_assigns}
+
+            eligible_domain = [
+                ("company_id", "=", company_id),
+                ("id", "not in", list(conflict_rooms.keys())),
+            ]
+            if assign.stay_group_id:
+                eligible_domain += [
+                    ("group_id", "in", (False, assign.stay_group_id.id))
+                ]
+            eligible_rooms = sro.search(eligible_domain)
+            assign.room_domain_ids = eligible_rooms.ids
+
+    @api.depends("partner_name", "arrival_time", "departure_time", "room_id")
+    def name_get(self):
+        res = []
+        for assign in self:
+            name = "[%s] %s, %s, %d [%s]" % (
+                TIME2CODE[assign.arrival_time],
+                shorten(assign.partner_name, 20, placeholder="..."),
+                assign.room_id.code or assign.room_id.name,
+                assign.guest_qty,
+                TIME2CODE[assign.departure_time],
+            )
+            res.append((assign.id, name))
+        return res
+
+    @api.onchange("room_id")
+    def room_id_change(self):
+        if (
+            self.stay_id
+            and self.room_id
+            and self.room_id.bed_qty
+            and not self.guest_qty
+        ):
+            if self.stay_id.guest_qty_to_assign:
+                if self.stay_id.guest_qty_to_assign <= self.room_id.bed_qty:
+                    self.guest_qty = self.stay_id.guest_qty_to_assign
+                else:
+                    self.guest_qty = self.room_id.bed_qty
+
+
+class StayRefectory(models.Model):
+    _name = "stay.refectory"
+    _description = "Refectory"
+    _order = "sequence, id"
+    _rec_name = "display_name"
+
+    sequence = fields.Integer(default=10)
+    code = fields.Char(string="Code", size=10)
+    name = fields.Char(string="Name", required=True)
+    capacity = fields.Integer(string="Capacity")
+    active = fields.Boolean(default=True)
+    company_id = fields.Many2one(
+        "res.company",
+        string="Company",
+        ondelete="cascade",
+        required=True,
+        default=lambda self: self.env.company,
+    )
+
+    _sql_constraints = [
+        (
+            "company_code_uniq",
+            "unique(company_id, code)",
+            "A refectory with this code already exists in this company.",
+        )
+    ]
+
+    @api.depends("name", "code")
+    def name_get(self):
+        res = []
+        for ref in self:
+            name = ref.name
+            if ref.code:
+                name = "[%s] %s" % (ref.code, name)
+            res.append((ref.id, name))
+        return res
+
+    @api.model
+    def name_search(self, name="", args=None, operator="ilike", limit=100):
+        if args is None:
+            args = []
+        if name and operator == "ilike":
+            recs = self.search([("code", "=", name)] + args, limit=limit)
+            if recs:
+                return recs.name_get()
+        return super().name_search(name=name, args=args, operator=operator, limit=limit)
+
+
+class StayRoom(models.Model):
+    _name = "stay.room"
+    _description = "Room"
+    _order = "sequence, id"
+    _check_company_auto = True
+
+    code = fields.Char(string="Code", size=10, copy=False)
+    name = fields.Char(string="Name", required=True, copy=False)
+    company_id = fields.Many2one(
+        "res.company",
+        string="Company",
+        ondelete="cascade",
+        required=True,
+        default=lambda self: self.env.company,
+    )
+    sequence = fields.Integer(default=10)
+    group_id = fields.Many2one(
+        "stay.group",
+        string="Group",
+        check_company=True,
+        domain="[('company_id', '=', company_id)]",
+    )
+    user_id = fields.Many2one(related="group_id.user_id", store=True, readonly=True)
+    bed_qty = fields.Integer(string="Number of beds", default=1)
+    allow_simultaneous = fields.Boolean(
+        string="Allow simultaneous",
+        help="This option applies for rooms where bed quantity > 1. You "
+        "should enable this option if you allow to have several stays "
+        "at the same time in the room.",
+    )
+    active = fields.Boolean(default=True)
+    notes = fields.Text()
+    to_clean = fields.Char(
+        string="To Clean",
+        help="When the field has a value, it means the room must be cleaned "
+        "(when a stay is terminated, this field is auto-set with the "
+        "stay description). When the room is cleaned, the field is emptied.",
+    )
+
+    _sql_constraints = [
+        (
+            "company_code_uniq",
+            "unique(company_id, code)",
+            "A room with this code already exists in this company.",
+        ),
+        (
+            "bed_qty_positive",
+            "CHECK(bed_qty > 0)",
+            "The number of beds must be positive.",
+        ),
+    ]
+
+    @api.constrains("allow_simultaneous", "bed_qty")
+    def _check_room_config(self):
+        for room in self:
+            if room.allow_simultaneous and room.bed_qty <= 1:
+                raise ValidationError(
+                    _(
+                        "Room %s has the option Allow simultaneous, but this option "
+                        "is only for rooms with several beds."
+                    )
+                    % room.display_name
+                )
+
+    @api.onchange("allow_simultaneous", "bed_qty")
+    def room_config_change(self):
+        if self.allow_simultaneous and self.bed_qty <= 1:
+            self.allow_simultaneous = False
+
+    @api.depends("name", "code")
+    def name_get(self):
+        res = []
+        for room in self:
+            name = room.name
+            if room.code:
+                name = "[%s] %s" % (room.code, name)
+            res.append((room.id, name))
+        return res
+
+    @api.model
+    def name_search(self, name="", args=None, operator="ilike", limit=100):
+        if args is None:
+            args = []
+        if name and operator == "ilike":
+            recs = self.search([("code", "=", name)] + args, limit=limit)
+            if recs:
+                return recs.name_get()
+        return super().name_search(name=name, args=args, operator=operator, limit=limit)
+
+    def mark_as_cleaned(self):
+        self.write({"to_clean": False})
+
+
+class StayGroup(models.Model):
+    _name = "stay.group"
+    _description = "Stay Group"
+    _order = "sequence, id"
+    _check_company_auto = True
+
+    name = fields.Char(string="Group Name", required=True)
+    company_id = fields.Many2one(
+        "res.company",
+        string="Company",
+        ondelete="cascade",
+        required=True,
+        default=lambda self: self.env.company,
+    )
+    user_id = fields.Many2one("res.users", string="In Charge")
+    sequence = fields.Integer()
+    room_ids = fields.One2many("stay.room", "group_id", string="Rooms")
+    notify_user_ids = fields.Many2many("res.users", string="Users Notified by E-mail")
+    default_refectory_id = fields.Many2one(
+        "stay.refectory",
+        string="Default Refectory",
+        ondelete="restrict",
+        check_company=True,
+    )
+
+    _sql_constraints = [
+        (
+            "name_company_uniq",
+            "unique(name, company_id)",
+            "A group with this name already exists in this company.",
+        )
+    ]
+
+    @api.model
+    def _stay_notify(self):
+        logger.info("Start stay arrival notify cron")
+        today = fields.Date.context_today(self)
+        sso = self.env["stay.stay"]
+        fields_get_time = dict(
+            sso.fields_get("arrival_time", "selection")["arrival_time"]["selection"]
+        )
+        for group in self.search([("notify_user_ids", "!=", False)]):
+            stays = sso.search(
+                [
+                    ("arrival_date", "=", today),
+                    ("group_id", "=", group.id),
+                ],
+                order="partner_name",
+            )
+            if stays:
+                stay_list = []
+                for stay in stays:
+                    stay_list.append(
+                        {
+                            "partner_name": stay.partner_name,
+                            "guest_qty": stay.guest_qty,
+                            "arrival_time": fields_get_time[stay.arrival_time],
+                            "rooms": stay.rooms_display_name,
+                            "departure_date": stay.departure_date,
+                            "departure_time": fields_get_time[stay.departure_time],
+                        }
+                    )
+                email_to_list = ",".join(
+                    [u.email for u in group.notify_user_ids if u.email]
+                )
+                email_from = (
+                    self.company_id and self.company_id.email or self.env.user.email
+                )
+                self.env.ref("stay.stay_notify").with_context(
+                    stay_list=stay_list,
+                    date=today,
+                    email_to_list=email_to_list,
+                    email_from=email_from,
+                ).send_mail(group.id)
+                logger.info(
+                    "Stay notification mail sent for group %s", group.display_name
+                )
+            else:
+                logger.info("No arrivals on %s for group %s", today, group.display_name)
+        logger.info("End stay arrival notify cron")
+
+
+class StayLine(models.Model):
+    _name = "stay.line"
+    _description = "Stay Journal"
+    _rec_name = "partner_name"
+    _order = "date"
+    _check_company_auto = True
+
+    stay_id = fields.Many2one(
+        "stay.stay", string="Stay", check_company=True, ondelete="cascade"
+    )
+    company_id = fields.Many2one(
+        "res.company",
+        string="Company",
+        required=True,
+        default=lambda self: self.env.company,
+    )
+    date = fields.Date(
+        string="Date", required=True, default=fields.Date.context_today, index=True
+    )
+    breakfast_qty = fields.Integer(string="Breakfast")
+    lunch_qty = fields.Integer(string="Lunches")
+    dinner_qty = fields.Integer(string="Dinners")
+    bed_night_qty = fields.Integer(string="Bed Nights")
+    partner_id = fields.Many2one(
+        "res.partner",
+        string="Guest",
+        help="If guest is anonymous, leave this field empty.",
+    )
+    partner_name = fields.Text("Guest Names", required=True)
+    refectory_id = fields.Many2one(
+        "stay.refectory",
+        string="Refectory",
+        check_company=True,
+        default=lambda self: self.env.company.default_refectory_id,
+    )
+    rooms_display_name = fields.Char(related="stay_id.rooms_display_name", store=True)
+    group_id = fields.Many2one(related="stay_id.group_id", store=True)
+    user_id = fields.Many2one(related="stay_id.group_id.user_id", store=True)
+
+    @api.constrains("refectory_id", "breakfast_qty", "lunch_qty", "dinner_qty")
+    def _check_room_refectory(self):
+        for line in self:
+            if (
+                line.lunch_qty or line.dinner_qty or line.breakfast_qty
+            ) and not line.refectory_id:
+                raise ValidationError(
+                    _("Missing refectory for guest '%s' on %s.")
+                    % (line.partner_name, format_date(self.env, line.date))
+                )
+
+    _sql_constraints = [
+        (
+            "lunch_qty_positive",
+            "CHECK (lunch_qty >= 0)",
+            "The number of lunches must be positive or null.",
+        ),
+        (
+            "dinner_qty_positive",
+            "CHECK (dinner_qty >= 0)",
+            "The number of dinners must be positive or null.",
+        ),
+        (
+            "bed_night_qty_positive",
+            "CHECK (bed_night_qty >= 0)",
+            "The number of bed nights must be positive or null.",
+        ),
+    ]
+
+    @api.onchange("partner_id")
+    def partner_id_change(self):
+        if self.partner_id:
+            partner = self.partner_id
+            partner_name = partner.name
+            if partner.title and not partner.is_company:
+                partner_lg = partner
+                if partner.lang:
+                    partner_lg = partner.with_context(lang=partner.lang)
+                title = partner_lg.title.shortcut or partner_lg.title.name
+                partner_name = "%s %s" % (title, partner_name)
+            self.partner_name = partner_name
+
+
+class StayDateLabel(models.Model):
+    _name = "stay.date.label"
+    _description = "Stay Date Label"
+    _order = "date desc"
+
+    date = fields.Date(required=True, index=True)
+    name = fields.Char(string="Label")
+
+    _sql_constraints = [("date_uniq", "unique(date)", "This date already exists.")]
+
+    @api.model
+    def _get_date_label(self, date):
+        res = False
+        if date:
+            date_label = self.env["stay.date.label"].search(
+                [("date", "=", date)], limit=1
+            )
+            res = date_label and date_label.name or False
+        return res
diff --git a/stay/readme/CONFIGURE.rst b/stay/readme/CONFIGURE.rst
new file mode 100644
index 00000000..de7f5ede
--- /dev/null
+++ b/stay/readme/CONFIGURE.rst
@@ -0,0 +1,6 @@
+To configure this module, you need to:
+
+ * create the Rooms,
+ * create the Groups (optional),
+ * create the Refectories,
+ * configure the default Refectory on the general configuration page.
diff --git a/stay/readme/CONTRIBUTORS.rst b/stay/readme/CONTRIBUTORS.rst
new file mode 100644
index 00000000..5d02a968
--- /dev/null
+++ b/stay/readme/CONTRIBUTORS.rst
@@ -0,0 +1,3 @@
+* Brother Bernard <informatique - at - barroux.org>
+* Brother Irénée (Barroux Abbey)
+* Alexis de Lattre <alexis.delattre@akretion.com>
diff --git a/stay/readme/DESCRIPTION.rst b/stay/readme/DESCRIPTION.rst
new file mode 100644
index 00000000..96ca296b
--- /dev/null
+++ b/stay/readme/DESCRIPTION.rst
@@ -0,0 +1,3 @@
+This module manages stays ; it handles lunches, dinners and bed nights. It allows the booking of rooms and dormitories with capacity check.
+
+It has been initially developped by the Barroux Abbey (http://www.barroux.org) to manage the stays of the guests at the Abbey.
diff --git a/stay/readme/USAGE.rst b/stay/readme/USAGE.rst
new file mode 100644
index 00000000..29c61247
--- /dev/null
+++ b/stay/readme/USAGE.rst
@@ -0,0 +1,3 @@
+To use this module, go to the menu *Stays > Stays > Stays* and start to register the future stays.
+
+Every day, start the wizard *Stays > Stays > Generate Journal* to generate the stay lines for the next day. You can then print the stay report via the wizard *Stays > Reports > Print Journal* to have a printed paper that you can give to the cook for example.
diff --git a/stay/report/report.xml b/stay/report/report.xml
new file mode 100644
index 00000000..82593936
--- /dev/null
+++ b/stay/report/report.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2021 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+        <record id="report_stay_journal_print" model="ir.actions.report">
+                <field name="name">Stay Journal</field>
+    <field name="model">stay.journal.print</field>
+    <field name="report_type">qweb-pdf</field>
+            <field name="report_name">stay.report_stayjournalprint</field>
+            <field name="report_file">stay.report_stayjournalprint</field>
+                    <field
+            name="print_report_name"
+        >'stay_journal-%s' % object.date</field>
+            </record>
+
+    <record id="report_stay_toclean" model="ir.actions.report">
+                <field name="name">Rooms to clean</field>
+    <field name="model">stay.toclean.print</field>
+    <field name="report_type">qweb-pdf</field>
+            <field name="report_name">stay.report_staytoclean</field>
+            <field name="report_file">stay.report_staytoclean</field>
+                    <field
+            name="print_report_name"
+        >'rooms_to_clean-%s' % str(object.create_date)[:10]</field>
+            </record>
+
+    <record id="report_stay_journal_arrival" model="ir.actions.report">
+                <field name="name">Arrival list</field>
+    <field name="model">stay.journal.print</field>
+    <field name="report_type">qweb-pdf</field>
+            <field name="report_name">stay.report_stayjournalarrival</field>
+            <field name="report_file">stay.report_stayjournalarrival</field>
+                    <field
+            name="print_report_name"
+        >'stay_arrival-%s' % object.date</field>
+            </record>
+
+    <record id="report_stay_journal_meal" model="ir.actions.report">
+                <field name="name">Meal plan</field>
+    <field name="model">stay.journal.print</field>
+    <field name="report_type">qweb-pdf</field>
+            <field name="report_name">stay.report_stayjournalmeal</field>
+            <field name="report_file">stay.report_stayjournalmeal</field>
+                    <field name="print_report_name">'stay_meal-%s' % object.date</field>
+            </record>
+
+
+</odoo>
diff --git a/stay/report/report_stay_journal.xml b/stay/report/report_stay_journal.xml
new file mode 100644
index 00000000..d49cc968
--- /dev/null
+++ b/stay/report/report_stay_journal.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2021 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<template id="stay.report_stayjournalprint_document">
+
+<t t-call="web.internal_layout">
+<t t-set="doc" t-value="doc.with_context({'lang':user.partner_id.lang})" />
+
+<div class="page">
+
+    <div class="text-center">
+        <h2>Guest List <span t-field="doc.date" /></h2>
+        <t t-if="doc.date_label"><span t-field="doc.date_label" /></t>
+    </div>
+
+<t t-foreach="doc.get_report_by_refectory()" t-as="k">
+
+<div>
+    <h3><t t-esc="k[0].name" /></h3>
+
+    <table class="table table-condensed">
+    <thead>
+        <tr>
+            <th>Stay</th>
+            <th>Arrival</th>
+            <th>Departure</th>
+            <th>Guests</th>
+            <th>Rooms</th>
+            <th class="text-center" groups="stay.group_stay_breakfast">Breakfasts</th>
+            <th class="text-center">Lunches</th>
+            <th class="text-center">Dinners</th>
+            <th class="text-center">Nights</th>
+        </tr>
+    </thead>
+    <tbody>
+    <t t-foreach="k[1]['lines']" t-as="line">
+        <tr>
+            <td><span t-field="line.stay_id.name" /></td>
+            <td><span t-field="line.stay_id.arrival_date" /> <span
+                                                t-field="line.stay_id.arrival_time"
+                                            /></td>
+            <td><span t-field="line.stay_id.departure_date" /> <span
+                                                t-field="line.stay_id.departure_time"
+                                            /></td>
+            <td><p t-field="line.partner_name" /></td>
+            <td><span t-field="line.rooms_display_name" /></td>
+            <td class="text-center" groups="stay.group_stay_breakfast"><span
+                                                t-field="line.breakfast_qty"
+                                            /></td>
+            <td class="text-center"><span t-field="line.lunch_qty" /></td>
+            <td class="text-center"><span t-field="line.dinner_qty" /></td>
+            <td class="text-center"><span t-field="line.bed_night_qty" /></td>
+        </tr>
+    </t>
+        <tr>
+            <td />
+            <td />
+            <td />
+            <td />
+            <td><b>Sub-totals:</b></td>
+            <td class="text-center" groups="stay.group_stay_breakfast"><t
+                                            t-esc="k[1]['breakfast_subtotal']"
+                                        /></td>
+            <td class="text-center"><t t-esc="k[1]['lunch_subtotal']" /></td>
+            <td class="text-center"><t t-esc="k[1]['dinner_subtotal']" /></td>
+            <td class="text-center"><t t-esc="k[1]['bed_night_subtotal']" /></td>
+        </tr>
+    </tbody>
+</table>
+</div>
+
+</t>
+</div>
+
+</t>
+
+</template>
+
+<template id="report_stayjournalprint">
+    <t t-call="web.html_container">
+        <t t-foreach="docs" t-as="doc">
+            <t
+                    t-call="stay.report_stayjournalprint_document"
+                    t-lang="user.partner_id.lang"
+                />
+        </t>
+    </t>
+</template>
+
+</odoo>
diff --git a/stay/security/ir.model.access.csv b/stay/security/ir.model.access.csv
new file mode 100644
index 00000000..1e759543
--- /dev/null
+++ b/stay/security/ir.model.access.csv
@@ -0,0 +1,23 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_stay_refectory_manager,Full access on stay.refectory to Stay Manager,model_stay_refectory,group_stay_manager,1,1,1,1
+access_stay_refectory_user,Read access on stay.refectory to Stay Viewer,model_stay_refectory,group_stay_viewer,1,0,0,0
+access_stay_room_manager,Full access on stay.room to Stay Manager,model_stay_room,group_stay_manager,1,1,1,1
+access_stay_room_user,Read access on stay.room to Stay Viewer,model_stay_room,group_stay_viewer,1,0,0,0
+access_stay_group_manager,Full access on stay.group to Stay Manager,model_stay_group,group_stay_manager,1,1,1,1
+access_stay_group_user,Read access on stay.group to Stay Viewer,model_stay_group,group_stay_viewer,1,0,0,0
+access_stay_date_label_manager,Full access on stay.date.label to Stay Manager,model_stay_date_label,group_stay_manager,1,1,1,1
+access_stay_date_label_user,Read access on stay.date.label to everybody,model_stay_date_label,,1,0,0,0
+access_stay_stay_user,Full access on stay.stay to Stay User,model_stay_stay,group_stay_user,1,1,1,1
+access_stay_stay_employee,Read access on stay.stay to Employee,model_stay_stay,base.group_user,1,0,0,0
+access_stay_stay_viewer,Read access on stay.stay to Stay Viewer,model_stay_stay,group_stay_viewer,1,0,0,0
+access_stay_room_assign_user,Full access on stay.room.assign to Stay User,model_stay_room_assign,group_stay_user,1,1,1,1
+access_stay_room_assign_viewer,Read access on stay.room.assign to Stay Viewer,model_stay_room_assign,group_stay_viewer,1,0,0,0
+access_stay_line_user,Full access on stay.line to Stay User,model_stay_line,group_stay_user,1,1,1,1
+access_stay_line_viewer,Read access on stay.line to Stay Viewer,model_stay_line,group_stay_viewer,1,0,0,0
+access_stay_journal_print,Full access on stay.journal.print wizard,model_stay_journal_print,group_stay_user,1,1,1,1
+access_stay_toclean_print,Full access on stay.toclean.print wizard,model_stay_toclean_print,group_stay_user,1,1,1,1
+access_stay_multi_duplicate,Full access on stay.multi.duplicate wizard,model_stay_multi_duplicate,group_stay_user,1,1,1,1
+access_stay_line_mass_update,Full access on stay.line.mass.update wizard,model_stay_line_mass_update,group_stay_user,1,1,1,1
+access_stay_line_reset,Full access on stay.line.reset wizard,model_stay_line_reset,group_stay_user,1,1,1,1
+access_stay_stay_xlsx,Full access on stay.stay.xlsx wizard,model_stay_stay_xlsx,group_stay_user,1,1,1,1
+access_stay_room_mass_assign,Full access on stay.room.mass.assign wizard,model_stay_room_mass_assign,group_stay_user,1,1,1,1
diff --git a/stay/security/stay_security.xml b/stay/security/stay_security.xml
new file mode 100644
index 00000000..c7c8d57c
--- /dev/null
+++ b/stay/security/stay_security.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2021 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+<data noupdate="0">
+
+<record id="module_category_stay" model="ir.module.category">
+    <field name="name">Stay</field>
+    <field name="description">Manage stays (lunch, diner, night, etc...)</field>
+    <field name="sequence">50</field>
+</record>
+
+<record id="group_stay_viewer" model="res.groups">
+    <field name="name">Viewer</field>
+    <field name="category_id" ref="module_category_stay" />
+</record>
+
+<record id="group_stay_user" model="res.groups">
+    <field name="name">User</field>
+    <field name="category_id" ref="module_category_stay" />
+    <field name="implied_ids" eval="[(4, ref('group_stay_viewer'))]" />
+</record>
+
+<record id="group_stay_manager" model="res.groups">
+    <field name="name">Manager</field>
+    <field name="category_id" ref="module_category_stay" />
+    <field name="implied_ids" eval="[(4, ref('group_stay_user'))]" />
+    <field name="users" eval="[(4, ref('base.user_root'))]" />
+</record>
+
+<record id="group_stay_breakfast" model="res.groups">
+    <field name="name">Manage Breakfast</field>
+    <field name="category_id" ref="base.module_category_hidden" />
+</record>
+
+</data>
+
+<data noupdate="1">
+
+<record id="base.default_user" model="res.users">
+    <field name="groups_id" eval="[(4, ref('group_stay_user'))]" />
+</record>
+
+<record id="base.user_admin" model="res.users">
+    <field name="groups_id" eval="[(4, ref('group_stay_manager'))]" />
+</record>
+
+<record id="base.user_root" model="res.users">
+    <field name="groups_id" eval="[(4, ref('group_stay_manager'))]" />
+</record>
+
+<!-- Multi-company Rules -->
+<record id="stay_company_rule" model="ir.rule">
+    <field name="name">Stay Multi-company</field>
+    <field name="model_id" ref="model_stay_stay" />
+    <field name="domain_force">[('company_id', 'in', company_ids)]</field>
+</record>
+
+<record id="stay_line_company_rule" model="ir.rule">
+    <field name="name">Stay Line Multi-company</field>
+    <field name="model_id" ref="model_stay_line" />
+    <field name="domain_force">[('company_id', 'in', company_ids)]</field>
+</record>
+
+<record id="stay_refectory_company_rule" model="ir.rule">
+    <field name="name">Stay Refectory Multi-company</field>
+    <field name="model_id" ref="model_stay_refectory" />
+    <field name="domain_force">[('company_id', 'in', company_ids)]</field>
+</record>
+
+<record id="stay_room_company_rule" model="ir.rule">
+    <field name="name">Stay Room Multi-company</field>
+    <field name="model_id" ref="model_stay_room" />
+    <field name="domain_force">[('company_id', 'in', company_ids)]</field>
+</record>
+
+<record id="stay_group_company_rule" model="ir.rule">
+    <field name="name">Stay Group Multi-company</field>
+    <field name="model_id" ref="model_stay_group" />
+    <field name="domain_force">[('company_id', 'in', company_ids)]</field>
+</record>
+
+
+
+</data>
+</odoo>
diff --git a/stay/static/description/icon.png b/stay/static/description/icon.png
new file mode 100644
index 00000000..fe34cf0b
Binary files /dev/null and b/stay/static/description/icon.png differ
diff --git a/stay/static/src/css/stay_iframe_style.css b/stay/static/src/css/stay_iframe_style.css
new file mode 100644
index 00000000..806b3af4
--- /dev/null
+++ b/stay/static/src/css/stay_iframe_style.css
@@ -0,0 +1,57 @@
+* {
+    margin: 0;
+}
+
+header {
+    margin: 0;
+    background-color: #7c7bad;
+    border-bottom-color: #5f5e97;
+    color: white;
+    border-bottom: 2px solid;
+    padding-bottom: 16px;
+    padding-top: 8px;
+    position: relative;
+    margin-bottom: 20px;
+    padding-left: 5px;
+}
+
+input,
+label,
+textarea {
+    margin-bottom: 8px;
+    margin-left: 8px;
+}
+input ~ label {
+    margin-left: 5px;
+}
+input {
+    border: 1px solid #b9b9b9;
+}
+select {
+    margin-bottom: 8px;
+    margin-left: 4px;
+    background-color: transparent;
+    border: 1px solid #b9b9b9;
+}
+fieldset {
+    margin-bottom: 8px;
+}
+#submit {
+    background-color: #7c7bad;
+    border-color: #5f5e97;
+    color: white;
+    text-align: center;
+    text-decoration: none;
+    display: inline-block;
+    font-size: 16px;
+    padding: 7px 16px;
+    border-radius: 3px;
+    transition-duration: 0.4s;
+}
+
+#submit:hover {
+    background-color: white;
+    color: #5f5e97;
+    border-color: #7c7bad;
+    cursor: pointer;
+}
diff --git a/stay/views/res_partner.xml b/stay/views/res_partner.xml
new file mode 100644
index 00000000..9a6f6ad7
--- /dev/null
+++ b/stay/views/res_partner.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" ?>
+<!--
+  Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2021 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<record id="res_partner_stay_action" model="ir.actions.act_window">
+    <field name="name">Stays</field>
+    <field name="res_model">stay.stay</field>
+    <field name="view_mode">tree,form,calendar,graph,pivot</field>
+    <field name="domain"> [('construction', '=', False)]</field>
+    <field
+            name="context"
+        >{'stay_name_get_partner_name_qty': True, 'default_construction': False, 'search_default_partner_id': active_id}</field>
+</record>
+
+<record id="view_partner_form" model="ir.ui.view">
+    <field name="name">stay.button.res.partner.form</field>
+    <field name="model">res.partner</field>
+    <field name="inherit_id" ref="base.view_partner_form" />
+    <field name="groups_id" eval="[(4, ref('stay.group_stay_viewer'))]" />
+    <field name="arch" type="xml">
+        <xpath expr="//div[@name='button_box']" position="inside">
+            <button
+                    class="oe_stat_button"
+                    type="action"
+                    name="%(stay.res_partner_stay_action)d"
+                    icon="fa-coffee"
+                >
+                <field string="Stays" name="stay_count" widget="statinfo" />
+            </button>
+        </xpath>
+    </field>
+</record>
+
+</odoo>
diff --git a/stay/views/stay.xml b/stay/views/stay.xml
new file mode 100644
index 00000000..03f447fb
--- /dev/null
+++ b/stay/views/stay.xml
@@ -0,0 +1,1112 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2021 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  @author: Brother Bernard <informatique@barroux.org>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<record id="stay_form" model="ir.ui.view">
+    <field name="name">stay.form</field>
+    <field name="model">stay.stay</field>
+    <field name="arch" type="xml">
+        <form string="Stay">
+            <header>
+                <button
+                        name="draft2confirm"
+                        type="object"
+                        string="Confirm"
+                        states="draft"
+                        class="btn-primary"
+                    />
+                <button
+                        name="cancel2draft"
+                        type="object"
+                        string="Back to Draft"
+                        states="cancel"
+                    />
+                <button
+                        name="guest_has_left"
+                        type="object"
+                        string="Guest has Left"
+                        groups="stay.group_stay_user"
+                        states="current"
+                    />
+                <button
+                        name="%(stay_line_mass_update_action)d"
+                        type="action"
+                        string="Update All Lines"
+                        states="confirm,current"
+                    />
+
+                <button
+                        name="cancel"
+                        type="object"
+                        string="Cancel"
+                        states="draft,confirm,current,done"
+                        confirm="Are you sure you want to cancel this stay?"
+                    />
+                <field
+                        name="state"
+                        widget="statusbar"
+                        statusbar_visible="draft,confirm,current,done"
+                    />
+            </header>
+
+            <div
+                    class="alert alert-warning"
+                    role="alert"
+                    attrs="{'invisible': [('construction', '=', False)]}"
+                >
+                Special stay to mark rooms as unavailable due to construction works.
+            </div>
+
+            <sheet>
+                <div class="oe_title">
+                    <h1>
+                        <field name="name" readonly="1" />
+                    </h1>
+                </div>
+                <group name="main">
+                    <group name="left">
+                        <field name="company_id" groups="base.group_multi_company" />
+                        <field
+                                name="partner_id"
+                                attrs="{'invisible': [('construction', '=', True)]}"
+                            />
+                        <field name="partner_name" />
+                        <field name="guest_qty" />
+                        <field
+                                name="assign_status"
+                                states="confirm,current,done"
+                                decoration-success="assign_status in ('assigned', 'no_night')"
+                                decoration-danger="assign_status in ('over-assigned', 'error')"
+                                decoration-info="assign_status == 'none'"
+                                decoration-warning="assign_status == 'partial'"
+                                widget="badge"
+                            />
+                    </group>
+                    <group name="right">
+                        <field name="arrival_date" />
+                        <field name="arrival_time" />
+                        <field name="arrival_datetime" invisible="1" />
+                        <field name="arrival_note" />
+                        <field name="departure_date" />
+                        <field name="departure_time" />
+                        <field name="departure_datetime" invisible="1" />
+                        <field name="departure_note" />
+                        <field name="group_id" />
+                        <field
+                                name="no_meals"
+                                attrs="{'invisible': ['|', ('construction', '=', True), ('state', '!=', 'draft')]}"
+                            />
+                        <field name="construction" invisible="1" />
+                        <field
+                                name="refectory_id"
+                                attrs="{'invisible': ['|', '|', ('no_meals', '=', True), ('construction', '=', True), ('state', '!=', 'draft')]}"
+                            />
+                    </group>
+                </group>
+
+                <group name="rooms" states="confirm,current,done">
+                    <field name="room_assign_ids" nolabel="1">
+                        <tree editable="bottom">
+                            <field name="room_id" />
+                            <field name="guest_qty" />
+                            <field name="room_domain_ids" invisible="1" />
+                        </tree>
+                    </field>
+                </group>
+                <group
+                        name="lines"
+                        attrs="{'invisible': ['|', ('construction', '=', True), ('state', 'in', ('draft', 'cancel'))]}"
+                    >
+                    <field name="line_ids" nolabel="1" />
+                </group>
+                <group name="notes">
+                    <field name="notes" />
+                </group>
+            </sheet>
+            <div class="oe_chatter">
+                <field name="message_follower_ids" widget="mail_followers" />
+                <field name="activity_ids" widget="mail_activity" />
+                <field name="message_ids" widget="mail_thread" />
+            </div>
+        </form>
+    </field>
+</record>
+
+<record id="stay_tree" model="ir.ui.view">
+    <field name="name">stay.tree</field>
+    <field name="model">stay.stay</field>
+    <field name="arch" type="xml">
+        <tree decoration-muted="state == 'cancel'">
+            <header>  <!-- v14+ Use same action as in the Action menu -->
+                <button
+                        name="guest_has_left"
+                        type="object"
+                        string="Guest has Left"
+                        groups="stay.group_stay_user"
+                        states="current"
+                    />
+            </header>
+            <field name="name" />
+            <field name="group_id" optional="show" />
+            <field
+                    name="company_id"
+                    groups="base.group_multi_company"
+                    optional="hide"
+                />
+            <field name="partner_name" invisible="context.get('partner_view')" />
+            <field name="guest_qty" />
+            <field name="arrival_date" />
+            <field name="arrival_time" />
+            <field name="arrival_note" optional="show" />
+            <field name="departure_date" />
+            <field name="departure_time" />
+            <field name="departure_note" optional="show" />
+            <field name="refectory_id" optional="hide" />
+            <field name="rooms_display_name" string="Rooms" />
+            <field
+                    name="assign_status"
+                    decoration-success="assign_status in ('assigned', 'no_night')"
+                    decoration-danger="assign_status in ('over-assigned', 'error')"
+                    decoration-info="assign_status == 'none'"
+                    decoration-warning="assign_status == 'partial'"
+                    widget="badge"
+                />
+            <field
+                    name="state"
+                    decoration-info="state == 'draft'"
+                    decoration-success="state == 'confirm'"
+                    decoration-warning="state == 'current'"
+                    decoration-muted="state == 'cancel'"
+                    decoration-danger="state == 'done'"
+                    widget="badge"
+                />
+        </tree>
+    </field>
+</record>
+
+
+<record id="stay_search" model="ir.ui.view">
+    <field name="name">stay.search</field>
+    <field name="model">stay.stay</field>
+    <field name="arch" type="xml">
+        <search>
+            <field
+                    name="partner_name"
+                    filter_domain="['|', '|', ('partner_name', 'ilike', self), ('partner_id', 'ilike', self), ('name', 'ilike', self)]"
+                    string="Guest Name or Stay Number"
+                />
+            <field name="partner_id" />
+            <field name="group_id" />
+            <field
+                    name="departure_date"
+                    string="Arrivals and Departures on"
+                    filter_domain="['|', ('arrival_date', '=', self), ('departure_date', '=', self)]"
+                />
+            <separator />
+            <filter
+                    string="My Rooms"
+                    name="my_rooms"
+                    domain="[('user_id', '=', uid)]"
+                />
+            <separator />
+            <filter string="Draft" name="draft" domain="[('state', '=', 'draft')]" />
+            <filter
+                    string="Confirmed"
+                    name="confirm"
+                    domain="[('state', '=', 'confirm')]"
+                />
+            <filter
+                    string="Current"
+                    name="current"
+                    domain="[('state', '=', 'current')]"
+                />
+            <filter string="Finished" name="done" domain="[('state', '=', 'done')]" />
+            <filter string="Cancel" name="cancel" domain="[('state', '=', 'cancel')]" />
+            <separator />
+            <filter
+                    string="To Assign"
+                    name="to_assign"
+                    domain="[('assign_status', 'in', ('none', 'partial'))]"
+                />
+            <filter
+                    string="Assigned"
+                    name="assigned"
+                    domain="[('assign_status', '=', 'assigned')]"
+                />
+            <separator />
+            <filter
+                    string="Arrivals/Departures Today"
+                    name="in_out_today"
+                    domain="['|', ('arrival_date', '=', context_today().strftime('%Y-%m-%d')), ('departure_date', '=', context_today().strftime('%Y-%m-%d'))]"
+                />
+            <filter
+                    string="Arrivals/Departures Tomorrow"
+                    name="in_out_tomorrow"
+                    domain="['|', ('arrival_date', '=', (context_today() + datetime.timedelta(days=1)).strftime('%Y-%m-%d')), ('departure_date', '=', (context_today() + datetime.timedelta(days=1)).strftime('%Y-%m-%d'))]"
+                />
+            <filter
+                    string="Current and Future Stays"
+                    name="current_and_future"
+                    domain="[('state', 'in', ('draft', 'confirm', 'current'))]"
+                />
+            <separator />
+            <filter string="Arrival Date" name="arrival_date" date="arrival_date" />
+            <filter
+                    string="Departure Date"
+                    name="departure_date"
+                    date="departure_date"
+                />
+            <separator />
+            <group string="Group By" name="groupby">
+                <filter
+                        name="group_groupby"
+                        string="Group"
+                        context="{'group_by': 'group_id'}"
+                    />
+                <filter
+                        name="state_groupby"
+                        string="State"
+                        context="{'group_by': 'state'}"
+                    />
+                <filter
+                        name="user_groupby"
+                        string="Responsible"
+                        context="{'group_by': 'user_id'}"
+                    />
+                <filter
+                        name="partner_groupby"
+                        string="Guest Name"
+                        context="{'group_by': 'partner_name'}"
+                    />
+                <filter
+                        name="arrival_date_groupby"
+                        string="Arrival Date"
+                        context="{'group_by': 'arrival_date'}"
+                    />
+                <filter
+                        name="assign_status_groupby"
+                        string="Assign Status"
+                        context="{'group_by': 'assign_status'}"
+                    />
+            </group>
+        </search>
+    </field>
+</record>
+
+<record id="stay_graph" model="ir.ui.view">
+    <field name="name">stay.graph</field>
+    <field name="model">stay.stay</field>
+    <field name="arch" type="xml">
+        <graph string="Stays">
+            <field name="arrival_date" interval="month" />
+            <field name="guest_qty" type="measure" />
+        </graph>
+    </field>
+</record>
+
+<record id="stay_pivot" model="ir.ui.view">
+    <field name="name">stay.graph</field>
+    <field name="model">stay.stay</field>
+    <field name="arch" type="xml">
+        <pivot string="Stays">
+            <field name="arrival_date" interval="month" type="row" />
+            <field name="guest_qty" type="measure" />
+        </pivot>
+    </field>
+</record>
+
+<!-- arrival_datetime and departure_datetime are readonly, so, when you create a stay
+from the calendar view, the dates are not set -->
+<record id="stay_calendar" model="ir.ui.view">
+    <field name="name">stay.calendar</field>
+    <field name="model">stay.stay</field>
+    <field name="arch" type="xml">
+        <calendar
+                string="Stays"
+                color="group_id"
+                date_start="arrival_datetime"
+                date_stop="departure_datetime"
+                mode="month"
+                quick_add="false"
+            >
+            <field name="arrival_date" />
+            <field name="arrival_time" />
+            <field name="departure_date" />
+            <field name="departure_time" />
+            <field name="guest_qty" />
+            <field name="partner_name" />
+            <field name="rooms_display_name" />
+        </calendar>
+    </field>
+</record>
+
+<record id="stay_action" model="ir.actions.act_window">
+    <field name="name">Stays</field>
+    <field name="res_model">stay.stay</field>
+    <field name="view_mode">tree,form,calendar,graph,pivot</field>
+    <field name="domain"> [('construction', '=', False)]</field>
+    <field
+            name="context"
+        >{'search_default_current_and_future': True, 'stay_name_get_partner_name_qty': True, 'default_construction': False}</field>
+</record>
+
+<record id="stay_construction_action" model="ir.actions.act_window">
+    <field name="name">Construction</field>
+    <field name="res_model">stay.stay</field>
+    <field name="view_mode">tree,form,calendar,graph,pivot</field>
+    <field name="domain"> [('construction', '=', True)]</field>
+    <field
+            name="context"
+        >{'search_default_current_and_future': True, 'stay_name_get_partner_name_qty': True, 'default_construction': True}</field>
+</record>
+
+
+<menuitem id="stay_menu" action="stay_action" parent="stay_sub_menu" sequence="10" />
+
+<menuitem
+        id="stay_construction_menu"
+        action="stay_construction_action"
+        parent="stay_sub_menu"
+        sequence="100"
+    />
+
+<record id="stay_room_assign_form" model="ir.ui.view">
+    <field name="model">stay.room.assign</field>
+    <field name="arch" type="xml">
+        <form>
+            <group name="main">
+                <field
+                        name="stay_id"
+                        invisible="not context.get('stay_room_assign_main_view')"
+                        readonly="1"
+                    />
+                <field
+                        name="partner_name"
+                        invisible="not context.get('stay_room_assign_main_view')"
+                    />
+                <field
+                        name="arrival_date"
+                        invisible="not context.get('stay_room_assign_main_view')"
+                    />
+                <field
+                        name="arrival_time"
+                        invisible="not context.get('stay_room_assign_main_view')"
+                    />
+                <field
+                        name="departure_date"
+                        invisible="not context.get('stay_room_assign_main_view')"
+                    />
+                <field
+                        name="departure_time"
+                        invisible="not context.get('stay_room_assign_main_view')"
+                    />
+                <field name="room_id" />
+                <field name="guest_qty" />
+                <field name="room_domain_ids" invisible="1" />
+                <field name="stay_group_id" invisible="1" />
+                <field
+                        name="company_id"
+                        groups="base.group_multi_company"
+                        invisible="not context.get('stay_room_assign_main_view')"
+                    />
+            </group>
+        </form>
+    </field>
+</record>
+
+
+
+<record id="stay_room_assign_tree" model="ir.ui.view">
+    <field name="model">stay.room.assign</field>
+    <field name="arch" type="xml">
+        <tree create="0">
+            <field name="stay_id" />
+            <field name="arrival_date" />
+            <field name="arrival_time" optional="show" />
+            <field name="departure_date" />
+            <field name="departure_time" optional="show" />
+            <field name="room_id" />
+            <field name="guest_qty" sum="1" />
+            <field name="stay_group_id" invisible="1" />
+            <field
+                    name="company_id"
+                    groups="base.group_multi_company"
+                    optional="hide"
+                />
+        </tree>
+    </field>
+</record>
+
+<record id="stay_room_assign_calendar" model="ir.ui.view">
+    <field name="model">stay.room.assign</field>
+    <field name="arch" type="xml">
+        <calendar
+                color="room_id"
+                date_start="arrival_datetime"
+                date_stop="departure_datetime"
+                mode="month"
+            >
+            <field name="display_name" />
+        </calendar>
+    </field>
+</record>
+
+
+<record id="stay_room_assign_timeline" model="ir.ui.view">
+    <field name="name">stay.room.assign.timeline</field>
+    <field name="model">stay.room.assign</field>
+    <field name="arch" type="xml">
+        <timeline
+                date_start="arrival_datetime"
+                date_stop="departure_datetime"
+                default_group_by="room_id"
+                event_open_popup="true"
+                mode="week"
+                colors="#ec7063:group_id_integer == 1;#2ecb71:group_id_integer == 2;#f34242:group_id_integer == 3"
+                zoomKey="ctrlKey"
+            >
+        </timeline>
+    </field>
+</record>
+
+<record id="stay_room_assign_pivot" model="ir.ui.view">
+    <field name="model">stay.room.assign</field>
+    <field name="arch" type="xml">
+        <pivot>
+            <field name="arrival_date" interval="month" type="row" />
+            <field name="guest_qty" type="measure" />
+        </pivot>
+    </field>
+</record>
+
+<record id="stay_room_assign_search" model="ir.ui.view">
+    <field name="name">stay.room.assign.search</field>
+    <field name="model">stay.room.assign</field>
+    <field name="arch" type="xml">
+        <search>
+            <field name="partner_name" />
+            <field name="partner_id" />
+            <field name="group_id" />
+            <field name="room_id" />
+            <field
+                    name="departure_date"
+                    string="Arrivals and Departures on"
+                    filter_domain="['|', ('arrival_date', '=', self), ('departure_date', '=', self)]"
+                />
+            <separator />
+            <filter
+                    string="My Rooms"
+                    name="my_rooms"
+                    domain="[('user_id', '=', uid)]"
+                />
+            <separator />
+            <filter
+                    string="Arrivals/Departures Today"
+                    name="in_out_today"
+                    domain="['|', ('arrival_date', '=', context_today().strftime('%Y-%m-%d')), ('departure_date', '=', context_today().strftime('%Y-%m-%d'))]"
+                />
+            <filter
+                    string="Arrivals/Departures Tomorrow"
+                    name="in_out_tomorrow"
+                    domain="['|', ('arrival_date', '=', (context_today() + datetime.timedelta(days=1)).strftime('%Y-%m-%d')), ('departure_date', '=', (context_today() + datetime.timedelta(days=1)).strftime('%Y-%m-%d'))]"
+                />
+            <filter
+                    string="Current and Future Stays"
+                    name="current_and_future"
+                    domain="[('departure_date', '&gt;=', (context_today().strftime('%Y-%m-%d')))]"
+                />
+            <separator />
+            <filter string="Arrival Date" name="arrival_date" date="arrival_date" />
+            <filter
+                    string="Departure Date"
+                    name="departure_date"
+                    date="departure_date"
+                />
+            <separator />
+            <group string="Group By" name="groupby">
+                <filter
+                        name="group_groupby"
+                        string="Group"
+                        context="{'group_by': 'group_id'}"
+                    />
+                <filter
+                        name="user_groupby"
+                        string="Responsible"
+                        context="{'group_by': 'user_id'}"
+                    />
+                <filter
+                        name="partner_groupby"
+                        string="Guest Name"
+                        context="{'group_by': 'partner_name'}"
+                    />
+                <filter
+                        name="arrival_date_groupby"
+                        string="Arrival Date"
+                        context="{'group_by': 'arrival_date'}"
+                    />
+            </group>
+        </search>
+    </field>
+</record>
+
+
+
+<record id="stay_room_assign_action" model="ir.actions.act_window">
+    <field name="name">Room Assignments</field>
+    <field name="res_model">stay.room.assign</field>
+    <field name="view_mode">timeline,tree,calendar,pivot</field>
+    <!-- We don't put search_default_current_and_future: True on stay.room.assign
+        because we want to have all rooms in the timeline view -->
+    <field
+            name="context"
+        >{'stay_name_get_partner_name_qty': True, 'stay_room_assign_main_view': True}</field>
+</record>
+
+
+<menuitem
+        id="stay_room_assign_menu"
+        action="stay_room_assign_action"
+        parent="stay_sub_menu"
+        sequence="20"
+    />
+
+
+<record id="stay_refectory_form" model="ir.ui.view">
+    <field name="name">stay.refectory.form</field>
+    <field name="model">stay.refectory</field>
+    <field name="arch" type="xml">
+        <form string="Refectory">
+            <sheet>
+            <widget
+                        name="web_ribbon"
+                        title="Archived"
+                        bg_color="bg-danger"
+                        attrs="{'invisible': [('active', '=', True)]}"
+                    />
+            <group name="main">
+                <field name="name" />
+                <field name="code" />
+                <field name="company_id" groups="base.group_multi_company" />
+                <field name="capacity" />
+                <field name="active" invisible="1" />
+            </group>
+    </sheet>
+        </form>
+    </field>
+</record>
+
+<record id="stay_refectory_tree" model="ir.ui.view">
+    <field name="name">stay.refectory.tree</field>
+    <field name="model">stay.refectory</field>
+    <field name="arch" type="xml">
+        <tree string="Refectories">
+            <field name="sequence" widget="handle" />
+            <field name="name" />
+            <field name="code" optional="show" />
+            <field name="capacity" />
+            <field
+                    name="company_id"
+                    groups="base.group_multi_company"
+                    optional="show"
+                />
+        </tree>
+    </field>
+</record>
+
+<record id="stay_refectory_search" model="ir.ui.view">
+    <field name="name">stay.refectory.search</field>
+    <field name="model">stay.refectory</field>
+    <field name="arch" type="xml">
+        <search>
+            <field
+                    name="name"
+                    filter_domain="['|', ('name', 'ilike', self), ('code', 'ilike', self)]"
+                />
+            <filter
+                    string="Archived"
+                    name="inactive"
+                    domain="[('active', '=', False)]"
+                />
+        </search>
+    </field>
+</record>
+
+<record id="stay_refectory_action" model="ir.actions.act_window">
+    <field name="name">Refectories</field>
+    <field name="res_model">stay.refectory</field>
+    <field name="view_mode">tree,form</field>
+</record>
+
+<menuitem
+        id="stay_refectory_menu"
+        action="stay_refectory_action"
+        parent="stay_configuration"
+        sequence="40"
+    />
+
+
+<record id="stay_room_form" model="ir.ui.view">
+    <field name="name">stay.room.form</field>
+    <field name="model">stay.room</field>
+    <field name="arch" type="xml">
+        <form string="Room">
+            <header>
+                <button
+                        name="mark_as_cleaned"
+                        type="object"
+                        string="Mark as Cleaned"
+                        attrs="{'invisible': [('to_clean', '=', False)]}"
+                        class="btn-primary"
+                    />
+        </header>
+            <sheet>
+            <widget
+                        name="web_ribbon"
+                        title="To Clean"
+                        bg_color="bg-danger"
+                        attrs="{'invisible': [('to_clean', '=', False)]}"
+                    />
+            <widget
+                        name="web_ribbon"
+                        title="Clean"
+                        bg_color="bg-success"
+                        attrs="{'invisible': [('to_clean', '!=', False)]}"
+                    />
+            <widget
+                        name="web_ribbon"
+                        title="Archived"
+                        bg_color="bg-danger"
+                        attrs="{'invisible': [('active', '=', True)]}"
+                    />
+            <group name="main">
+                <field name="name" />
+                <field name="code" />
+                <field name="company_id" groups="base.group_multi_company" />
+                <field name="group_id" />
+                <field name="bed_qty" />
+                <field
+                            name="allow_simultaneous"
+                            attrs="{'invisible': [('bed_qty', '=', 1)]}"
+                        />
+                <field name="to_clean" />
+                <field name="notes" />
+                <field name="active" invisible="1" />
+            </group>
+        </sheet>
+        </form>
+    </field>
+</record>
+
+<record id="stay_room_tree" model="ir.ui.view">
+    <field name="name">stay.room.tree</field>
+    <field name="model">stay.room</field>
+    <field name="arch" type="xml">
+        <tree string="Rooms">
+            <header>
+                <button name="mark_as_cleaned" type="object" string="Mark as Cleaned" />
+            </header>
+            <field name="sequence" widget="handle" />
+            <field name="name" />
+            <field name="code" optional="show" />
+            <field name="group_id" optional="show" />
+            <field name="bed_qty" />
+            <field name="to_clean" />
+            <field
+                    name="company_id"
+                    groups="base.group_multi_company"
+                    optional="show"
+                />
+        </tree>
+    </field>
+</record>
+
+<record id="stay_room_search" model="ir.ui.view">
+    <field name="name">stay.room.search</field>
+    <field name="model">stay.room</field>
+    <field name="arch" type="xml">
+        <search>
+            <field
+                    name="name"
+                    filter_domain="['|', ('name', 'ilike', self), ('code', 'ilike', self)]"
+                />
+            <field name="group_id" />
+            <separator />
+            <filter
+                    name="my_rooms"
+                    string="My Rooms"
+                    domain="[('user_id', '=', uid)]"
+                />
+            <separator />
+            <filter
+                    name="to_clean"
+                    string="To Clean"
+                    domain="[('to_clean', '!=', False)]"
+                />
+            <filter name="clean" string="Clean" domain="[('to_clean', '=', False)]" />
+            <separator />
+            <filter
+                    string="Archived"
+                    name="inactive"
+                    domain="[('active', '=', False)]"
+                />
+            <group name="groupby">
+                <filter
+                        name="group_groupby"
+                        string="Group"
+                        context="{'group_by': 'group_id'}"
+                    />
+                <filter
+                        name="user_groupby"
+                        string="Responsible"
+                        context="{'group_by': 'user_id'}"
+                    />
+            </group>
+        </search>
+    </field>
+</record>
+
+<record id="stay_room_action" model="ir.actions.act_window">
+    <field name="name">Rooms</field>
+    <field name="res_model">stay.room</field>
+    <field name="view_mode">tree,form</field>
+</record>
+
+<record id="stay_room_to_clean_action" model="ir.actions.act_window">
+    <field name="name">Rooms to Clean</field>
+    <field name="res_model">stay.room</field>
+    <field name="view_mode">tree,form</field>
+    <field name="domain">[('to_clean', '!=', False)]</field>
+</record>
+
+<menuitem
+        id="stay_room_menu"
+        action="stay_room_action"
+        parent="stay_configuration"
+        sequence="30"
+    />
+
+<menuitem
+        id="stay_room_to_clean_menu"
+        action="stay_room_to_clean_action"
+        parent="stay_sub_menu"
+        sequence="40"
+    />
+
+<record id="stay_group_form" model="ir.ui.view">
+    <field name="name">stay.group.form</field>
+    <field name="model">stay.group</field>
+    <field name="arch" type="xml">
+            <form string="Group">
+            <sheet>
+            <group name="main">
+                <field name="name" />
+                <field name="company_id" groups="base.group_multi_company" />
+                <field name="default_refectory_id" />
+                <field name="user_id" />
+                <field name="notify_user_ids" widget="many2many_tags" />
+            </group>
+    </sheet>
+        </form>
+    </field>
+</record>
+
+<record id="stay_group_tree" model="ir.ui.view">
+    <field name="name">stay.group.tree</field>
+    <field name="model">stay.group</field>
+    <field name="arch" type="xml">
+        <tree string="Groups">
+            <field name="sequence" widget="handle" />
+            <field name="name" />
+            <field name="default_refectory_id" optional="show" />
+            <field name="user_id" />
+            <field
+                    name="company_id"
+                    groups="base.group_multi_company"
+                    optional="show"
+                />
+        </tree>
+    </field>
+</record>
+
+<record id="stay_group_search" model="ir.ui.view">
+    <field name="name">stay.group.search</field>
+    <field name="model">stay.group</field>
+    <field name="arch" type="xml">
+        <search>
+            <field
+                    name="name"
+                    filter_domain="['|', ('name', 'ilike', self), ('user_id', 'ilike', self)]"
+                />
+            <group name="groupby">
+                <filter
+                        name="user_groupby"
+                        string="Responsible"
+                        context="{'group_by': 'user_id'}"
+                    />
+            </group>
+        </search>
+    </field>
+</record>
+
+<record id="stay_group_action" model="ir.actions.act_window">
+    <field name="name">Groups</field>
+    <field name="res_model">stay.group</field>
+    <field name="view_mode">tree,form</field>
+</record>
+
+<menuitem
+        id="stay_group_menu"
+        action="stay_group_action"
+        parent="stay_configuration"
+        sequence="20"
+    />
+
+
+<record id="stay_line_form" model="ir.ui.view">
+    <field name="name">stay.line.form</field>
+    <field name="model">stay.line</field>
+    <field name="arch" type="xml">
+        <form string="Stay Line">
+            <group name="main">
+                <field name="date" />
+                <field
+                        name="stay_id"
+                        invisible="not context.get('stay_line_main_view')"
+                    />
+                <field name="rooms_display_name" />
+                <field name="partner_id" />
+                <field name="partner_name" />
+                <field name="breakfast_qty" groups="stay.group_stay_breakfast" />
+                <field name="lunch_qty" />
+                <field name="dinner_qty" />
+                <field name="bed_night_qty" />
+                <field name="refectory_id" />
+                <field name="group_id" />
+                <field name="user_id" />
+                <field name="company_id" groups="base.group_multi_company" />
+            </group>
+        </form>
+    </field>
+</record>
+
+<record id="stay_line_tree" model="ir.ui.view">
+    <field name="name">stay.line.tree</field>
+    <field name="model">stay.line</field>
+    <field name="arch" type="xml">
+        <tree string="Stay Lines" editable="bottom">
+            <field name="stay_id" invisible="not context.get('stay_line_main_view')" />
+            <field name="date" />
+            <field
+                    name="partner_id"
+                    invisible="not context.get('stay_line_main_view')"
+                />
+            <field
+                    name="partner_name"
+                    invisible="not context.get('stay_line_main_view')"
+                />
+            <field
+                    name="breakfast_qty"
+                    sum="1"
+                    optional="show"
+                    groups="stay.group_stay_breakfast"
+                />
+            <field name="lunch_qty" sum="1" />
+            <field name="dinner_qty" sum="1" />
+            <field name="bed_night_qty" sum="1" />
+            <field name="refectory_id" optional="show" />
+            <field
+                    name="rooms_display_name"
+                    invisible="not context.get('stay_line_main_view')"
+                    optional="show"
+                />
+            <field
+                    name="company_id"
+                    groups="base.group_multi_company"
+                    optional="hide"
+                />
+        </tree>
+    </field>
+</record>
+
+<record id="stay_line_search" model="ir.ui.view">
+    <field name="name">stay.line.search</field>
+    <field name="model">stay.line</field>
+    <field name="arch" type="xml">
+        <search>
+            <field name="date" />
+            <field name="partner_name" />
+            <field name="group_id" />
+            <separator />
+            <filter string="Date" name="date" date="date" />
+            <separator />
+            <filter
+                    string="Current and Future Lines"
+                    name="current_and_future"
+                    domain="[('date', '&gt;=', (context_today().strftime('%Y-%m-%d')))]"
+                />
+            <separator />
+            <filter
+                    name="my_rooms"
+                    string="My Rooms"
+                    domain="[('user_id', '=', uid)]"
+                />
+            <separator />
+            <group string="Group By" name="groupby">
+                <filter
+                        name="group_groupby"
+                        string="Group"
+                        context="{'group_by': 'group_id'}"
+                    />
+                <filter
+                        name="user_groupby"
+                        string="Responsible"
+                        context="{'group_by': 'user_id'}"
+                    />
+                <filter
+                        name="date_groupby"
+                        string="Date"
+                        context="{'group_by': 'date'}"
+                    />
+                <filter
+                        name="refectory_id"
+                        string="Refectory"
+                        context="{'group_by': 'refectory_id'}"
+                    />
+                <filter
+                        name="partner_name"
+                        string="Guest"
+                        context="{'group_by': 'partner_name'}"
+                    />
+            </group>
+        </search>
+    </field>
+</record>
+
+<record id="stay_line_graph" model="ir.ui.view">
+    <field name="name">stay.line.graph</field>
+    <field name="model">stay.line</field>
+    <field name="arch" type="xml">
+        <graph string="Stay Lines">
+            <field name="date" interval="month" />
+            <field name="lunch_qty" type="measure" />
+            <field name="dinner_qty" type="measure" />
+            <field name="bed_night_qty" type="measure" />
+        </graph>
+    </field>
+</record>
+
+<record id="stay_line_pivot" model="ir.ui.view">
+    <field name="name">stay.line.pivot</field>
+    <field name="model">stay.line</field>
+    <field name="arch" type="xml">
+        <pivot string="Stay Lines">
+            <field name="date" interval="month" type="row" />
+            <field name="lunch_qty" type="measure" />
+            <field name="dinner_qty" type="measure" />
+            <field name="bed_night_qty" type="measure" />
+        </pivot>
+    </field>
+</record>
+
+
+<record id="stay_line_action" model="ir.actions.act_window">
+    <field name="name">Stay Lines</field>
+    <field name="res_model">stay.line</field>
+    <field name="view_mode">tree,form,graph,pivot</field>
+    <field
+            name="context"
+        >{'stay_line_main_view': True, 'search_default_current_and_future': True}</field>
+</record>
+
+<menuitem
+        id="stay_line_menu"
+        action="stay_line_action"
+        parent="stay_sub_menu"
+        sequence="30"
+    />
+
+<menuitem
+        id="partners"
+        action="base.action_partner_form"
+        parent="stay_sub_menu"
+        sequence="50"
+        name="Guests"
+    />
+
+
+<record id="stay_date_label_form" model="ir.ui.view">
+    <field name="name">stay.date.label.form</field>
+    <field name="model">stay.date.label</field>
+    <field name="arch" type="xml">
+        <form string="Date Label">
+            <group name="main">
+                <field name="date" />
+                <field name="name" />
+            </group>
+        </form>
+    </field>
+</record>
+
+<record id="stay_date_label_tree" model="ir.ui.view">
+    <field name="name">stay.date.label.tree</field>
+    <field name="model">stay.date.label</field>
+    <field name="arch" type="xml">
+        <tree string="Date Labels">
+            <field name="date" />
+            <field name="name" />
+        </tree>
+    </field>
+</record>
+
+<record id="stay_date_label_calendar" model="ir.ui.view">
+    <field name="name">stay.date.label.calendar</field>
+    <field name="model">stay.date.label</field>
+    <field name="arch" type="xml">
+        <calendar string="Date Labels" date_start="date" date_stop="date" mode="month">
+            <field name="name" />
+        </calendar>
+    </field>
+</record>
+
+<record id="stay_date_label_search" model="ir.ui.view">
+    <field name="name">stay.date.label.search</field>
+    <field name="model">stay.date.label</field>
+    <field name="arch" type="xml">
+        <search>
+            <field name="name" />
+            <field name="date" />
+            <separator />
+            <filter string="Date" name="date" date="date" />
+            <group name="groupby">
+                <filter
+                        name="date_groupby"
+                        string="Date"
+                        context="{'group_by': 'date'}"
+                    />
+            </group>
+        </search>
+    </field>
+</record>
+
+<record id="stay_date_label_action" model="ir.actions.act_window">
+    <field name="name">Ordo</field>
+    <field name="res_model">stay.date.label</field>
+    <field name="view_mode">tree,form,calendar</field>
+</record>
+
+<menuitem
+        id="stay_date_label_menu"
+        action="stay_date_label_action"
+        parent="stay_configuration"
+        sequence="50"
+    />
+
+
+
+</odoo>
diff --git a/stay/views/stay_iframe.xml b/stay/views/stay_iframe.xml
new file mode 100644
index 00000000..7d1b9b55
--- /dev/null
+++ b/stay/views/stay_iframe.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<odoo>
+
+<template id="stay_form_iframe" name="Stay form">
+    <xpath expr="//head" position="inside">
+        <link rel='stylesheet' href="./static/src/css/stay_iframe_style.css" />
+    </xpath>
+    <header> <h2>Book your Stay</h2> </header>
+    <div class="wrap">
+        <form action="/stay/saved" method="post">
+
+            <div>
+                <input
+                        id="partner_name"
+                        type="text"
+                        name="partner_name"
+                        required="1"
+                        placeholder="Name and Surname"
+                        alt="Your Name and Surname"
+                    />
+            </div>
+
+            <div>
+                <input
+                        id="email"
+                        type="text"
+                        name="email"
+                        required="1"
+                        placeholder="email"
+                        alt="your email adress"
+                    />
+            </div>
+
+            <div>
+                <input
+                        id="mobile"
+                        type="tel"
+                        name="mobile"
+                        placeholder="mobile"
+                        required="1"
+                        alt="mobile phone number"
+                    />
+            </div>
+            <label for="title">Title:</label>
+            <select id="title" name="title">
+                <option value="madam">Madam</option>
+                <option value="mister">Mister</option>
+                <option value="miss">Miss</option>
+            </select>
+    <fieldset>
+        <legend>Arrival</legend>
+
+        <label for="arrival_date">Arrival Date :</label>
+        <input id="arrival_date" name="arrival_date" type="date" required="1" />
+        <br />
+        <input
+                        type="radio"
+                        class="morning"
+                        name="arrival_time"
+                        value="morning"
+                        checked="1"
+                    />
+        <label for="morning">Morning</label>
+        <br />
+        <input type="radio" class="afternoon" name="arrival_time" value="afternoon" />
+        <label for="afternoon">Afternoon</label>
+        <br />
+        <input type="radio" class="evening" name="arrival_time" value="evening" />
+        <label for="evening">Evening</label>
+    </fieldset>
+
+    <fieldset>
+        <legend>Departure</legend>
+        <label for="departure_date">Departure Date :</label>
+        <input id="departure_date" name="departure_date" type="date" required="1" />
+        <br />
+        <input
+                        type="radio"
+                        class="morning"
+                        name="departure_time"
+                        value="morning"
+                        checked="1"
+                    />
+        <label for="morning">Morning</label>
+        <br />
+        <input type="radio" class="afternoon" name="departure_time" value="afternoon" />
+        <label for="afternoon">Afternoon</label>
+        <br />
+        <input type="radio" class="evening" name="departure_time" value="evening" />
+        <label for="evening">Evening</label>
+
+  </fieldset>
+  <div>
+  <label for="guest_qty">Number of guests</label>
+  <input
+                        id="guest_qty"
+                        name="guest_qty"
+                        type="number"
+                        min="1"
+                        max="50"
+                        value="1"
+                        placeholder="Number of Guests"
+                        required="1"
+                    />
+  </div>
+  <div>
+  <textarea
+                        id="notes"
+                        name="notes"
+                        rows="6"
+                        cols="50"
+                        placeholder="Additional Notes/your motivations"
+                    />
+  </div>
+    <input type="submit" value="Submit" id="submit" />
+                </form>
+    </div>
+</template>
+
+<template id="stay_saved_iframe" name="Stay Saved">
+        <div class="wrap">
+             <section>
+                <div class="container">
+                    <div class="mt32">
+                        <div>
+                                <h1>Your stay application was assigned number: <span
+                                    t-field="stay.name"
+                                /></h1>
+                            <ul>
+                                    <li>Arrival Date :
+                                    <span t-field="stay.arrival_date" /></li>
+                            <li>Arrival Time : <span t-field="stay.arrival_time" /></li>
+                            <li>Departure Date : <span
+                                        t-field="stay.departure_date"
+                                    /></li>
+                            <li>Departure Time : <span
+                                        t-field="stay.departure_time"
+                                    /></li>
+                            <li>number of guests : <span
+                                        t-field="stay.guest_qty"
+                                    /></li>
+                    </ul>
+                        </div>
+                    </div>
+                </div>
+            </section>
+        </div>
+</template>
+
+<template id="dates_selection_error" name="Dates Selection Error">
+    <h1>Dates selection Error</h1>
+    <p
+        >Either the arrival date you've chosen is past, or the arrival date you've selected is after your departure date!</p>
+    <a href="./new">Return to form</a>
+</template>
+</odoo>
diff --git a/stay/views/stay_menu.xml b/stay/views/stay_menu.xml
new file mode 100644
index 00000000..0e368f01
--- /dev/null
+++ b/stay/views/stay_menu.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2014-2022 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2022 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  @author: Brother Bernard <informatique@barroux.org>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+
+<menuitem
+        id="stay_top_menu"
+        sequence="5"
+        name="Stays"
+        groups="group_stay_viewer"
+        web_icon="stay,static/description/icon.png"
+    />
+
+<menuitem id="stay_sub_menu" sequence="10" name="Stays" parent="stay_top_menu" />
+
+<menuitem id="stay_report_menu" sequence="20" name="Reports" parent="stay_top_menu" />
+
+<menuitem
+        id="stay_configuration"
+        sequence="50"
+        name="Configuration"
+        parent="stay_top_menu"
+        groups="group_stay_manager"
+    />
+
+</odoo>
diff --git a/stay/wizard/__init__.py b/stay/wizard/__init__.py
new file mode 100644
index 00000000..6c66afef
--- /dev/null
+++ b/stay/wizard/__init__.py
@@ -0,0 +1,8 @@
+from . import res_config_settings
+from . import stay_journal_print
+from . import stay_toclean_print
+from . import stay_stay_xlsx
+from . import stay_multi_duplicate
+from . import stay_line_mass_update
+from . import stay_line_reset
+from . import stay_room_mass_assign
diff --git a/stay/wizard/res_config_settings.py b/stay/wizard/res_config_settings.py
new file mode 100644
index 00000000..2506e16c
--- /dev/null
+++ b/stay/wizard/res_config_settings.py
@@ -0,0 +1,18 @@
+# Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+# Copyright 2014-2021 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# @author: Brother Bernard <informatique@barroux.org>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class ResConfigSettings(models.TransientModel):
+    _inherit = "res.config.settings"
+
+    stay_default_refectory_id = fields.Many2one(
+        related="company_id.default_refectory_id", readonly=False
+    )
+    group_stay_breakfast = fields.Boolean(
+        string="Manage Breakfast", implied_group="stay.group_stay_breakfast"
+    )
diff --git a/stay/wizard/res_config_settings_view.xml b/stay/wizard/res_config_settings_view.xml
new file mode 100644
index 00000000..78839fef
--- /dev/null
+++ b/stay/wizard/res_config_settings_view.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2021 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<record id="res_config_settings_view_form" model="ir.ui.view">
+    <field name="model">res.config.settings</field>
+    <field name="inherit_id" ref="base.res_config_settings_view_form" />
+    <field name="arch" type="xml">
+        <xpath expr="//div[hasclass('settings')]" position="inside">
+            <div
+                    class="app_settings_block"
+                    data-string="Stays"
+                    string="Stays"
+                    data-key="stay"
+                    groups="stay.group_stay_manager"
+                >
+                <h2>Stays</h2>
+                <div
+                        class='row mt16 o_settings_container'
+                        name="stay_setting_container"
+                    >
+                    <div class='col-12 col-lg-12 o_setting_box' id="stay_setting">
+                        <div class="o_setting_left_pane" />
+                        <div class="o_setting_right_pane">
+                            <div class="row">
+                                <label
+                                        for="stay_default_refectory_id"
+                                        class="col-md-3"
+                                    />
+                                <field name="stay_default_refectory_id" />
+                            </div>
+                            <div class="row">
+                                <label for="group_stay_breakfast" class="col-md-3" />
+                                <field name="group_stay_breakfast" />
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </xpath>
+    </field>
+</record>
+
+<record id="stay_settings_action" model="ir.actions.act_window">
+    <field name="name">Settings</field>
+    <field name="res_model">res.config.settings</field>
+    <field name="view_mode">form</field>
+    <field name="target">inline</field>
+    <field name="context">{'module' : 'stay', 'bin_size': False}</field>
+</record>
+
+<menuitem
+        id="stay_settings_menu"
+        parent="stay_configuration"
+        sequence="10"
+        action="stay_settings_action"
+        groups="base.group_system"
+    />
+
+</odoo>
diff --git a/stay/wizard/stay_journal_print.py b/stay/wizard/stay_journal_print.py
new file mode 100644
index 00000000..8c9a383b
--- /dev/null
+++ b/stay/wizard/stay_journal_print.py
@@ -0,0 +1,202 @@
+# Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+# Copyright 2014-2021 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# @author: Brother Bernard <informatique@barroux.org>
+# @author: Brother Irénée
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from datetime import datetime
+
+from babel.dates import (
+    format_date as babel_format_date,
+    format_datetime as babel_format_datetime,
+)
+from dateutil.relativedelta import relativedelta
+
+from odoo import _, api, fields, models
+from odoo.exceptions import UserError
+from odoo.tools.misc import format_date
+
+
+class StayJournalPrint(models.TransientModel):
+    _name = "stay.journal.print"
+    _description = "Print the Stay Lines"
+    _rec_name = "date"
+
+    @api.model
+    def _default_date(self):
+        today_str = fields.Date.context_today(self)
+        today_dt = fields.Date.from_string(today_str)
+        return today_dt + relativedelta(days=1)
+
+    date = fields.Date(string="Date", required=True, default=_default_date)
+    date_label = fields.Char(compute="_compute_date_label")
+    company_id = fields.Many2one(
+        "res.company",
+        string="Company",
+        required=True,
+        default=lambda self: self.env.company,
+    )
+    report_type = fields.Selection(
+        [
+            ("general", "General"),
+            ("meal", "Meals"),
+            ("arrival", "Arrivals"),
+        ],
+        default="general",
+        required=True,
+    )
+
+    @api.depends("date")
+    def _compute_date_label(self):
+        for wiz in self:
+            res = self.env["stay.date.label"]._get_date_label(self.date)
+            wiz.date_label = res
+
+    def print_journal(self):
+        self.ensure_one()
+        if self.report_type == "general":
+            return self.print_journal_general()
+        elif self.report_type == "meal":
+            return self.print_journal_meal()
+        elif self.report_type == "arrival":
+            return self.print_journal_arrival()
+        return
+
+    def print_journal_general(self):
+        lines = self.env["stay.line"].search(
+            [
+                ("date", "=", self.date),
+                ("company_id", "=", self.company_id.id),
+            ]
+        )
+        if not lines:
+            raise UserError(
+                _("There are no stays on %s in company %s.")
+                % (format_date(self.env, self.date), self.company_id.display_name)
+            )
+        action = (
+            self.env.ref("stay.report_stay_journal_print")
+            .with_context({"discard_logo_check": True})
+            .report_action(self)
+        )
+        return action
+
+    def print_journal_meal(self):
+        action = (
+            self.env.ref("stay.report_stay_journal_meal")
+            .with_context({"discard_logo_check": True})
+            .report_action(self)
+        )
+        return action
+
+    def print_journal_arrival(self):
+        action = (
+            self.env.ref("stay.report_stay_journal_arrival")
+            .with_context({"discard_logo_check": True})
+            .report_action(self)
+        )
+        return action
+
+    def get_report_by_refectory(self):
+        """Method for the report (replace report parser)"""
+        lines = self.env["stay.line"].search(
+            [
+                ("date", "=", self.date),
+                ("company_id", "=", self.company_id.id),
+            ]
+        )
+        res = {}
+        # {refectory_obj1 : {
+        #       'lunch_subtotal': 2,
+        #       'dinner_subtotal': 4,
+        #       'bed_night_subtotal': 5,
+        #       'lines': [line1, line2, line3],
+        #       }
+        # }
+        for line in lines:
+            refectory = line.refectory_id
+            if refectory in res:
+                res[refectory]["breakfast_subtotal"] += line.breakfast_qty
+                res[refectory]["lunch_subtotal"] += line.lunch_qty
+                res[refectory]["dinner_subtotal"] += line.dinner_qty
+                res[refectory]["bed_night_subtotal"] += line.bed_night_qty
+                res[refectory]["lines"].append(line)
+            else:
+                res[refectory] = {
+                    "breakfast_subtotal": line.breakfast_qty,
+                    "lunch_subtotal": line.lunch_qty,
+                    "dinner_subtotal": line.dinner_qty,
+                    "bed_night_subtotal": line.bed_night_qty,
+                    "lines": [line],
+                }
+        # print "res=", res.items()
+        return res.items()
+
+    def _report_move_date(self, date, move_type, raise_if_none=False):
+        assert move_type in ("arrival", "departure")
+        assert date
+        sso = self.env["stay.stay"]
+        stays = sso.search(
+            [
+                (move_type + "_date", "=", date),
+                ("company_id", "=", self.company_id.id),
+                ("state", "not in", ("draft", "cancel")),
+            ]
+        )
+        if not stays and raise_if_none:
+            if move_type == "arrival":
+                raise UserError(_("No arrival on %s.") % format_date(self.env, date))
+            elif move_type == "departure":
+                raise UserError(_("No departure on %s.") % format_date(self.env, date))
+        res = (
+            stays.filtered(lambda x: x[move_type + "_time"] == "morning")
+            + stays.filtered(lambda x: x[move_type + "_time"] == "afternoon")
+            + stays.filtered(lambda x: x[move_type + "_time"] == "evening")
+        )
+        return res
+
+    def _report_nomove(self, date):
+        assert date
+        sso = self.env["stay.stay"]
+        stays = sso.search(
+            [
+                ("company_id", "=", self.company_id.id),
+                ("arrival_date", "<", date),
+                ("departure_date", ">", date),
+                ("state", "not in", ("draft", "cancel")),
+            ]
+        )
+        return stays
+
+    def report_general_data(self):
+        res = {}
+        day = self.date
+        self.env["stay.date.label"]._get_date_label(day)
+        res[day] = {
+            "date_label": babel_format_date(day, "full", locale="fr"),
+            "ordo": self.env["stay.date.label"]._get_date_label(day) or "",
+            "departure": self._report_move_date(day, "departure"),
+            "arrival": self._report_move_date(day, "arrival"),
+            "nomove": self._report_nomove(day),
+        }
+        nextday = day + relativedelta(days=1)
+        res[nextday] = {
+            "date_label": babel_format_date(nextday, locale="fr", format="full"),
+            "ordo": self.env["stay.date.label"]._get_date_label(nextday) or "",
+            "departure": self._report_move_date(nextday, "departure"),
+            "arrival": self._report_move_date(nextday, "arrival"),
+            "nomove": self._report_nomove(nextday),
+        }
+        return res
+
+    def report_arrival_data(self):
+        return self._report_move_date(self.date, "arrival", raise_if_none=True)
+
+    def report_date_formatted(self):
+        return babel_format_date(self.date, "full", locale=self.env.user.lang)
+
+    def report_edit_datetime(self):
+        now = fields.Datetime.context_timestamp(self, datetime.now())
+        res = babel_format_datetime(now, "d MMMM yyyy hh:mm", locale=self.env.user.lang)
+        return res
diff --git a/stay/wizard/stay_journal_print_view.xml b/stay/wizard/stay_journal_print_view.xml
new file mode 100644
index 00000000..a589e83c
--- /dev/null
+++ b/stay/wizard/stay_journal_print_view.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2014-2021 Barroux Abbey (www.barroux.org)
+  Copyright 2014-2021 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  @author: Brother Bernard <informatique@barroux.org>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<record id="stay_journal_print_form" model="ir.ui.view">
+    <field name="name">stay_journal_print.form</field>
+    <field name="model">stay.journal.print</field>
+    <field name="arch" type="xml">
+        <form string="Print Stay Journal">
+            <group name="main">
+                <field name="report_type" widget="radio" />
+                <field name="date" />
+                <field name="date_label" />
+                <field name="company_id" groups="base.group_multi_company" />
+            </group>
+            <footer>
+                <button
+                        type="object"
+                        name="print_journal"
+                        string="Print Journal"
+                        class="btn-primary"
+                    />
+                <button special="cancel" string="Cancel" />
+            </footer>
+        </form>
+    </field>
+</record>
+
+<record id="stay_journal_print_action" model="ir.actions.act_window">
+    <field name="name">Print Journal</field>
+    <field name="res_model">stay.journal.print</field>
+    <field name="view_mode">form</field>
+    <field name="target">new</field>
+</record>
+
+<menuitem
+        id="stay_journal_print_menu"
+        sequence="20"
+        action="stay_journal_print_action"
+        parent="stay_report_menu"
+    />
+
+
+</odoo>
diff --git a/stay/wizard/stay_line_mass_update.py b/stay/wizard/stay_line_mass_update.py
new file mode 100644
index 00000000..e97fadff
--- /dev/null
+++ b/stay/wizard/stay_line_mass_update.py
@@ -0,0 +1,60 @@
+# Copyright 2022 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# @author: Matthieu Dubois <dubois.matthieu@tutanota.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+
+from odoo import _, api, fields, models
+from odoo.exceptions import UserError
+
+
+class StayLineMassUpdate(models.TransientModel):
+    _name = "stay.line.mass.update"
+    _description = "wizard to mass update lines"
+
+    stay_id = fields.Many2one("stay.stay", required=True, readonly=True)
+    refectory_id = fields.Many2one("stay.refectory", string="New Refectory")
+    no_breakfast = fields.Boolean(string="No Breakfasts")
+    no_lunch = fields.Boolean(string="No Lunches")
+    no_dinner = fields.Boolean(string="No Dinners")
+    no_bed_night = fields.Boolean(string="No Bed Nights")
+
+    @api.model
+    def default_get(self, fields_list):
+        res = super().default_get(fields_list)
+        assert self._context.get("active_model") == "stay.stay"
+        res["stay_id"] = self._context.get("active_id")
+        return res
+
+    def _prepare_write_stay_line(self):
+        vals = {}
+        if self.no_breakfast:
+            vals["breakfast_qty"] = 0
+        if self.no_lunch:
+            vals["lunch_qty"] = 0
+        if self.no_dinner:
+            vals["dinner_qty"] = 0
+        if self.no_bed_night:
+            vals["bed_night_qty"] = 0
+        if self.refectory_id:
+            vals["refectory_id"] = self.refectory_id.id
+        return vals
+
+    def _prepare_write_stay(self):
+        vals = {}
+        if self.refectory_id:
+            vals["refectory_id"] = self.refectory_id.id
+        return vals
+
+    def apply(self):
+        vals = self._prepare_write_stay_line()
+        if not vals:
+            raise UserError(
+                _(
+                    "You must check at least one option! You didn't check any... "
+                    "To reset to default setttings, please use the appropriate "
+                    "wizard if installed."
+                )
+            )
+        self.stay_id.line_ids.write(vals)
+        self.stay_id.write(self._prepare_write_stay())
diff --git a/stay/wizard/stay_line_mass_update_view.xml b/stay/wizard/stay_line_mass_update_view.xml
new file mode 100644
index 00000000..96eb933e
--- /dev/null
+++ b/stay/wizard/stay_line_mass_update_view.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2022 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  @author: Matthieu Dubois <dubois.matthieu@tutanota.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<record id="stay_line_mass_update_form" model="ir.ui.view">
+    <field name="model">stay.line.mass.update</field>
+    <field name="arch" type="xml">
+        <form string="Update All Stay Lines">
+            <group name="main">
+                <field name="stay_id" />
+                <field name="no_breakfast" />
+                <field name="no_lunch" />
+                <field name="no_dinner" />
+                <field name="no_bed_night" />
+                <field name="refectory_id" />
+            </group>
+            <footer>
+                <button
+                        type="object"
+                        name="apply"
+                        string="Apply Changes"
+                        class="btn-primary"
+                    />
+                <button special="cancel" string="Cancel" />
+            </footer>
+        </form>
+    </field>
+</record>
+
+<record id="stay_line_mass_update_action" model="ir.actions.act_window">
+    <field name="name">Update all lines</field>
+    <field name="res_model">stay.line.mass.update</field>
+    <field name="view_mode">form</field>
+    <field name="target">new</field>
+</record>
+
+
+</odoo>
diff --git a/stay/wizard/stay_line_reset.py b/stay/wizard/stay_line_reset.py
new file mode 100644
index 00000000..0f8d30fc
--- /dev/null
+++ b/stay/wizard/stay_line_reset.py
@@ -0,0 +1,26 @@
+# Copyright 2022 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# @author: Matthieu Dubois <dubois.matthieu@tutanota.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+
+from odoo import api, fields, models
+
+
+class StayLineReset(models.TransientModel):
+    _name = "stay.line.reset"
+    _description = "wizard to reset all lines to default values"
+
+    stay_id = fields.Many2one("stay.stay", required=True, readonly=True)
+
+    @api.model
+    def default_get(self, fields_list):
+        res = super().default_get(fields_list)
+        assert self._context.get("active_model") == "stay.stay"
+        res["stay_id"] = self._context.get("active_id")
+        return res
+
+    def reset_lines(self):
+        self.ensure_one()
+        self.stay_id.line_ids.unlink()
+        self.stay_id._update_lines()
diff --git a/stay/wizard/stay_line_reset_view.xml b/stay/wizard/stay_line_reset_view.xml
new file mode 100644
index 00000000..b0bb4178
--- /dev/null
+++ b/stay/wizard/stay_line_reset_view.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2022 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  @author: Matthieu Dubois <dubois.matthieu@tutanota.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<record id="stay_line_reset" model="ir.ui.view">
+    <field name="model">stay.line.reset</field>
+    <field name="arch" type="xml">
+        <form string="Reset Stay Lines to Default Values">
+            <group name="main">
+                <field name="stay_id" />
+            </group>
+            <footer>
+                <button
+                        type="object"
+                        name="reset_lines"
+                        string="Reset to Default Values"
+                        class="btn-primary"
+                    />
+                <button special="cancel" string="Cancel" />
+            </footer>
+        </form>
+    </field>
+</record>
+
+<record id="stay_line_reset_action" model="ir.actions.act_window">
+    <field name="name">Reset All Stay Lines</field>
+    <field name="res_model">stay.line.reset</field>
+    <field name="view_mode">form</field>
+    <field name="target">new</field>
+    <field name="binding_model_id" ref="stay.model_stay_stay" />
+    <field name="binding_view_types">form</field>
+</record>
+
+
+</odoo>
diff --git a/stay/wizard/stay_multi_duplicate.py b/stay/wizard/stay_multi_duplicate.py
new file mode 100644
index 00000000..f9e9777f
--- /dev/null
+++ b/stay/wizard/stay_multi_duplicate.py
@@ -0,0 +1,108 @@
+# Copyright 2022 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# @author: Matthieu Dubois <dubois.matthieu@tutanota.com>
+# 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 UserError
+from odoo.tools.misc import format_date
+
+
+class StayMultiDuplicate(models.TransientModel):
+    _name = "stay.multi.duplicate"
+    _description = "Multi Stay Duplicate Wizard"
+
+    stay_id = fields.Many2one("stay.stay", required=True, readonly=True)
+    frequency = fields.Selection(
+        [("weekly", "Weekly")], required=True, default="weekly"
+    )
+    start_date = fields.Date(required=True, default=fields.Date.context_today)
+    end_date = fields.Date(required=True)
+    create_state = fields.Selection(
+        [
+            ("draft", "Draft"),
+            ("confirm", "Confirmed"),
+        ],
+        default="draft",
+        required=True,
+    )
+    keep_notes = fields.Boolean(string="Keep Notes?")
+    keep_assignments = fields.Boolean(string="Keep assignments?", default=True)
+
+    @api.model
+    def default_get(self, fields_list):
+        res = super().default_get(fields_list)
+        assert self._context.get("active_model") == "stay.stay"
+        res["stay_id"] = self._context.get("active_id")
+        return res
+
+    def _prepare_stay_copy(self, cur_arrival_date):
+        content = {
+            "arrival_date": cur_arrival_date,
+            "departure_date": cur_arrival_date
+            + (self.stay_id.departure_date - self.stay_id.arrival_date),
+        }
+        if self.keep_notes is False:
+            content["departure_note"] = False
+            content["arrival_note"] = False
+            content["notes"] = False
+
+        if not self.keep_assignments or self.create_state == "draft":
+            content["room_assign_ids"] = False
+
+        return content
+
+    def run(self):
+        self.ensure_one()
+        today = fields.Date.context_today(self)
+        if self.start_date < today:
+            raise UserError(
+                _("The start date %s is in the past!")
+                % (format_date(self.env, self.start_date))
+            )
+        if self.end_date <= self.start_date:
+            raise UserError(
+                _("The end date (%s) must be after the start_date (%s)!")
+                % (
+                    format_date(self.env, self.end_date),
+                    format_date(self.env, self.start_date),
+                )
+            )
+        freq2days = {
+            "weekly": 7,
+        }
+
+        new_stay_ids = []
+        cur_arrival_date = self.start_date
+
+        while cur_arrival_date <= self.end_date:
+            existing_stay = self.env["stay.stay"].search(
+                [
+                    ("company_id", "=", self.stay_id.company_id.id),
+                    ("partner_id", "=", self.stay_id.partner_id.id),
+                    ("arrival_date", "=", cur_arrival_date),
+                ],
+                limit=1,
+            )
+            if existing_stay:
+                raise UserError(
+                    _(
+                        "A stay already exists for guest '%s' with arrival date %s (stay %s)."
+                    )
+                    % (
+                        self.stay_id.partner_id.display_name,
+                        format_date(self.env, cur_arrival_date),
+                        existing_stay.name,
+                    )
+                )
+            new_stay = self.stay_id.copy(self._prepare_stay_copy(cur_arrival_date))
+            if self.create_state == "confirm":
+                new_stay.draft2confirm()
+            new_stay_ids.append(new_stay.id)
+            cur_arrival_date += timedelta(days=freq2days[self.frequency])
+
+        action = self.env["ir.actions.actions"]._for_xml_id("stay.stay_action")
+        action["domain"] = [("id", "in", new_stay_ids)]
+        return action
diff --git a/stay/wizard/stay_multi_duplicate_view.xml b/stay/wizard/stay_multi_duplicate_view.xml
new file mode 100644
index 00000000..18adf1ca
--- /dev/null
+++ b/stay/wizard/stay_multi_duplicate_view.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2022 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  @author: Matthieu Dubois <dubois.matthieu@tutanota.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<record id="stay_multi_duplicate_form" model="ir.ui.view">
+    <field name="model">stay.multi.duplicate</field>
+    <field name="arch" type="xml">
+        <form string="Stay Multi Duplicate">
+            <group name="main">
+                <field name="stay_id" />
+                <field name="frequency" />
+                <field name="start_date" />
+                <field name="end_date" />
+                <field name="create_state" widget="radio" />
+                <field
+                        name="keep_assignments"
+                        attrs="{'invisible': [('create_state', '=', 'draft')]}"
+                    />
+                <field name="keep_notes" />
+            </group>
+            <footer>
+                <button
+                        type="object"
+                        name="run"
+                        string="Generate Stays"
+                        class="btn-primary"
+                    />
+                <button special="cancel" string="Cancel" />
+            </footer>
+        </form>
+    </field>
+</record>
+
+<record id="stay_multi_duplicate_action" model="ir.actions.act_window">
+    <field name="name">Multi Duplicate</field>
+    <field name="res_model">stay.multi.duplicate</field>
+    <field name="view_mode">form</field>
+    <field name="target">new</field>
+    <field name="binding_model_id" ref="stay.model_stay_stay" />
+    <field name="binding_view_types">form</field>
+</record>
+
+
+</odoo>
diff --git a/stay/wizard/stay_room_mass_assign.py b/stay/wizard/stay_room_mass_assign.py
new file mode 100644
index 00000000..906ca211
--- /dev/null
+++ b/stay/wizard/stay_room_mass_assign.py
@@ -0,0 +1,52 @@
+# Copyright 2022 Akretion France (http://www.akretion.com/)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from odoo import _, api, fields, models
+from odoo.exceptions import UserError
+
+
+class StayRoomMassAssign(models.TransientModel):
+    _name = "stay.room.mass.assign"
+    _description = "Mass Assignation of Stay Rooms"
+
+    @api.model
+    def default_get(self, fields_list):
+        res = super().default_get(fields_list)
+        assert self._context.get("active_model") == "stay.stay"
+        stay = self.env["stay.stay"].browse(self._context.get("active_id"))
+        if stay.state not in ("confirm", "current"):
+            raise UserError(
+                _("Stay '%s' is not in Confirmed nor Current state.")
+                % stay.display_name
+            )
+        res["stay_id"] = self._context.get("active_id")
+        return res
+
+    stay_id = fields.Many2one("stay.stay", readonly=True)
+    company_id = fields.Many2one(related="stay_id.company_id")
+    group_id = fields.Many2one(related="stay_id.group_id")
+    room_ids = fields.Many2many(
+        "stay.room",
+        string="Rooms",
+        required=True,
+        domain="[('company_id', '=', company_id), ('group_id', 'in', (False, group_id))]",
+    )
+
+    def _prepare_room_assign(self, room):
+        return {
+            "room_id": room.id,
+            "guest_qty": room.bed_qty,
+            "stay_id": self.stay_id.id,
+        }
+
+    def run(self):
+        self.ensure_one()
+        existing_rooms = {}
+        for line in self.stay_id.room_assign_ids:
+            existing_rooms[line.room_id.id] = True
+        vals = []
+        for room in self.room_ids:
+            if room.id not in existing_rooms:
+                vals.append(self._prepare_room_assign(room))
+        self.env["stay.room.assign"].create(vals)
diff --git a/stay/wizard/stay_room_mass_assign_view.xml b/stay/wizard/stay_room_mass_assign_view.xml
new file mode 100644
index 00000000..01ca71a5
--- /dev/null
+++ b/stay/wizard/stay_room_mass_assign_view.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2022 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<record id="stay_room_mass_assign_form" model="ir.ui.view">
+    <field name="model">stay.room.mass.assign</field>
+    <field name="arch" type="xml">
+        <form string="Stay Room Mass Assign">
+            <group name="main">
+                <field name="stay_id" />
+                <field name="company_id" invisible="1" />
+                <field name="group_id" />
+                <field name="room_ids" />
+            </group>
+            <footer>
+                <button
+                        type="object"
+                        name="run"
+                        string="Add Rooms"
+                        class="btn-primary"
+                    />
+                <button special="cancel" string="Cancel" />
+            </footer>
+        </form>
+    </field>
+</record>
+
+<record id="stay_room_mass_assign_action" model="ir.actions.act_window">
+    <field name="name">Mass Assign</field>
+    <field name="res_model">stay.room.mass.assign</field>
+    <field name="view_mode">form</field>
+    <field name="target">new</field>
+    <field name="binding_model_id" ref="stay.model_stay_stay" />
+    <field name="binding_view_types">form</field>
+</record>
+
+
+</odoo>
diff --git a/stay/wizard/stay_stay_xlsx.py b/stay/wizard/stay_stay_xlsx.py
new file mode 100644
index 00000000..c6c88d13
--- /dev/null
+++ b/stay/wizard/stay_stay_xlsx.py
@@ -0,0 +1,214 @@
+# Copyright 2020-2021 Akretion France (https://www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+import base64
+import logging
+from io import BytesIO
+
+from dateutil.relativedelta import relativedelta
+
+from odoo import _, api, fields, models
+
+_logger = logging.getLogger(__name__)
+
+try:
+    import xlsxwriter
+except ImportError:
+    _logger.debug("Can not import xlsxwriter`.")
+
+
+class StayStayXlsx(models.TransientModel):
+    _name = "stay.stay.xlsx"
+    _description = "Print Stay Global view"
+
+    @api.model
+    def default_get(self, fields_list):
+        res = super().default_get(fields_list)
+        company_id = self.env.company.id
+        today_dt = fields.Date.context_today(self)
+        end_date_dt = today_dt + relativedelta(months=6, days=-1)
+        groups = self.env["stay.group"].search(
+            [
+                ("user_id", "=", self.env.user.id),
+                ("company_id", "=", company_id),
+            ]
+        )
+        if not groups:
+            groups = self.env["stay.group"].search([("company_id", "=", company_id)])
+        res.update(
+            {
+                "start_date": today_dt,
+                "end_date": end_date_dt,
+                "group_ids": groups and groups.ids or [],
+                "company_id": company_id,
+            }
+        )
+        return res
+
+    company_id = fields.Many2one("res.company", string="Company", required=True)
+    start_date = fields.Date(string="Start Date", required=True)
+    end_date = fields.Date(string="End Date", required=True)
+    group_ids = fields.Many2many(
+        "stay.group", string="Groups", domain="[('company_id', '=', company_id)]"
+    )
+    file_xlsx = fields.Binary(readonly=True)
+    filename = fields.Char(readonly=True)
+
+    def prepare_tab(self):
+        res = {}
+        if not self.group_ids:
+            # take everything
+            res[_("All")] = self.env["stay.room"].search(
+                [("company_id", "=", self.company_id.id)]
+            )
+        else:
+            for group in self.group_ids:
+                res[group.name] = group.room_ids
+        return res
+
+    def run(self):
+        self.ensure_one()
+        srao = self.env["stay.room.assign"]
+        start_date_dt = self.start_date
+        end_date_dt = self.end_date
+        #        start_date_dt = fields.Date.from_string(start_date)
+        #        end_date_dt = fields.Date.from_string(end_date)
+        date_labels = self.env["stay.date.label"].search_read(
+            [
+                ("date", ">=", self.start_date),
+                ("date", "<=", self.end_date),
+                ("name", "!=", False),
+            ],
+            ["date", "name"],
+        )
+        date2label = {}
+        for date_label in date_labels:
+            date2label[date_label["date"]] = date_label["name"]
+        file_data = BytesIO()
+        workbook = xlsxwriter.Workbook(file_data)
+        for group_name, rooms in self.prepare_tab().items():
+            room2col = {}
+            sheet = workbook.add_worksheet(group_name)
+            sheet.set_column(0, 0, 22)
+            sheet.set_column(1, 1, 16)
+            sheet.set_row(0, 35)
+            sheet.set_row(1, 25)
+            title = workbook.add_format(
+                {"bold": True, "font_size": 20, "align": "left", "valign": "vcenter"}
+            )
+            header_other = workbook.add_format(
+                {
+                    "bold": True,
+                    "font_size": 12,
+                    "align": "center",
+                    "valign": "vcenter",
+                    "bg_color": "#fff830",
+                }
+            )
+            header_room = workbook.add_format(
+                {
+                    "bold": True,
+                    "font_size": 12,
+                    "align": "center",
+                    "valign": "vcenter",
+                    "bg_color": "#baf9ff",
+                }
+            )
+            sunday_color = "#f7ffb0"
+            font_size = 10
+            regular_date = workbook.add_format(
+                {
+                    "num_format": "dddd d mmmm yyyy",
+                    "align": "right",
+                    "font_size": font_size,
+                }
+            )
+            regular_date_sunday = workbook.add_format(
+                {
+                    "num_format": "dddd d mmmm yyyy",
+                    "align": "right",
+                    "bg_color": sunday_color,
+                    "font_size": font_size,
+                }
+            )
+            regular = workbook.add_format({"font_size": font_size, "align": "left"})
+            regular_sunday = workbook.add_format(
+                {"font_size": font_size, "bg_color": sunday_color, "align": "left"}
+            )
+            regular_stay = workbook.add_format(
+                {"font_size": font_size, "align": "left", "bg_color": "#7eb7fc"}
+            )
+            i = 0
+            sheet.write(i, 0, _("Stays - %s") % self.company_id.name, title)
+            i += 1
+            sheet.write(i, 0, _("Date"), header_other)
+            sheet.write(i, 1, _("Celebration"), header_other)
+
+            z = 2
+            for room in rooms:
+                room2col[room] = z
+                sheet.set_column(z, z, 17)
+                sheet.write(i, z, room.code or room.name, header_room)
+                z += 1
+
+            date_dt = start_date_dt
+            date2row = {}
+            while date_dt <= end_date_dt:
+                i += 1
+                date2row[date_dt] = i
+                cell_style_date = regular_date
+                cell_style = regular
+                if date_dt.weekday() == 6:
+                    cell_style_date = regular_date_sunday
+                    cell_style = regular_sunday
+                sheet.write(i, 0, date_dt, cell_style_date)
+                sheet.write(i, 1, date2label.get(date_dt, ""), cell_style)
+                for col in room2col.values():
+                    sheet.write(i, col, "", cell_style)
+
+                date_dt += relativedelta(days=1)
+            for room in rooms:
+                room_assigns = srao.search(
+                    [
+                        ("room_id", "=", room.id),
+                        ("arrival_date", "<=", end_date_dt),
+                        ("departure_date", ">=", start_date_dt),
+                    ]
+                )
+                col = room2col[room]
+                for assign in room_assigns:
+                    nights_dt = []
+                    stay_start_dt = assign.arrival_date
+                    stay_end_dt = assign.departure_date
+                    cell_label = assign.partner_name
+                    stay_date_dt = stay_start_dt
+                    while stay_date_dt < stay_end_dt:
+                        nights_dt.append(stay_date_dt)
+                        stay_date_dt += relativedelta(days=1)
+                    for night_dt in nights_dt:
+                        row = date2row.get(night_dt)
+                        if row:
+                            sheet.write(
+                                date2row[night_dt], col, cell_label, regular_stay
+                            )
+
+        workbook.close()
+        file_data.seek(0)
+        filename = "Stay_%s.xlsx" % fields.Date.context_today(self)
+        export_file_b64 = base64.encodebytes(file_data.read())
+        self.write(
+            {
+                "filename": filename,
+                "file_xlsx": export_file_b64,
+            }
+        )
+        action = {
+            "name": "Stay",
+            "type": "ir.actions.act_url",
+            "url": "web/content/?model=%s&id=%d&filename_field=filename&"
+            "field=file_xlsx&download=true&filename=%s"
+            % (self._name, self.id, self.filename),
+            "target": "self",
+        }
+        return action
diff --git a/stay/wizard/stay_stay_xlsx_view.xml b/stay/wizard/stay_stay_xlsx_view.xml
new file mode 100644
index 00000000..d1ebdf6d
--- /dev/null
+++ b/stay/wizard/stay_stay_xlsx_view.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2020 Akretion France (https://www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+
+<record id="stay_stay_xlsx_form" model="ir.ui.view">
+    <field name="name">stay.stay.xlsx.form</field>
+    <field name="model">stay.stay.xlsx</field>
+    <field name="arch" type="xml">
+        <form string="Print Stay XLSX">
+            <group name="main">
+                <field name="company_id" groups="base.group_multi_company" />
+                <field name="start_date" />
+                <field name="end_date" />
+                <field name="group_ids" widget="many2many_tags" />
+            </group>
+            <footer>
+                <button type="object" name="run" string="Show" class="btn-primary" />
+                <button special="cancel" string="Cancel" />
+            </footer>
+        </form>
+    </field>
+</record>
+
+<record id="stay_stay_xlsx_action" model="ir.actions.act_window">
+    <field name="name">Print Stays</field>
+    <field name="res_model">stay.stay.xlsx</field>
+    <field name="view_mode">form</field>
+    <field name="target">new</field>
+</record>
+
+<menuitem
+        id="stay_stay_xlsx_menu"
+        sequence="10"
+        action="stay_stay_xlsx_action"
+        parent="stay_report_menu"
+    />
+
+
+</odoo>
diff --git a/stay/wizard/stay_toclean_print.py b/stay/wizard/stay_toclean_print.py
new file mode 100644
index 00000000..3260600c
--- /dev/null
+++ b/stay/wizard/stay_toclean_print.py
@@ -0,0 +1,46 @@
+# Copyright 2022 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class StayTocleanPrint(models.TransientModel):
+    _name = "stay.toclean.print"
+    _description = "Print to clean report"
+
+    company_id = fields.Many2one(
+        "res.company",
+        string="Company",
+        required=True,
+        default=lambda self: self.env.company,
+    )
+
+    def print_report(self):
+        action = (
+            self.env.ref("stay.report_stay_toclean")
+            .with_context({"discard_logo_check": True})
+            .report_action(self)
+        )
+        return action
+
+    def report_toclean_data(self):
+        self.ensure_one()
+        sro = self.env["stay.room"]
+        sgo = self.env["stay.group"]
+        # The result must be orderd by group and by room
+        res = {}
+        for group in sgo.search([("company_id", "=", self.company_id.id)]):
+            res[group.name] = []
+        res["none"] = []
+        for room in sro.search(
+            [("to_clean", "!=", False), ("company_id", "=", self.company_id.id)]
+        ):
+            group = room.group_id and room.group_id.name or "none"
+            res[group].append(room)
+        res_final = {}
+        # remove empty groups
+        for group, rooms in res.items():
+            if rooms:
+                res_final[group] = rooms
+        return res_final
diff --git a/stay/wizard/stay_toclean_print_view.xml b/stay/wizard/stay_toclean_print_view.xml
new file mode 100644
index 00000000..a697e180
--- /dev/null
+++ b/stay/wizard/stay_toclean_print_view.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2022 Akretion France (www.akretion.com)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+
+<record id="stay_toclean_print_form" model="ir.ui.view">
+    <field name="name">stay_toclean_print.form</field>
+    <field name="model">stay.toclean.print</field>
+    <field name="arch" type="xml">
+        <form string="To Clean Report">
+                <p>Print the <b>To Clean</b> report.</p>
+            <group name="main">
+                <field name="company_id" groups="base.group_multi_company" />
+            </group>
+            <footer>
+                <button
+                        type="object"
+                        name="print_report"
+                        string="Print"
+                        class="btn-primary"
+                    />
+                <button special="cancel" string="Cancel" />
+            </footer>
+        </form>
+    </field>
+</record>
+
+<record id="stay_toclean_print_action" model="ir.actions.act_window">
+    <field name="name">To Clean Report</field>
+    <field name="res_model">stay.toclean.print</field>
+    <field name="view_mode">form</field>
+    <field name="target">new</field>
+</record>
+
+<menuitem
+        id="stay_toclean_print_menu"
+        sequence="30"
+        action="stay_toclean_print_action"
+        parent="stay_report_menu"
+    />
+
+
+</odoo>
diff --git a/stay_report_py3o/README.rst b/stay_report_py3o/README.rst
new file mode 100644
index 00000000..b52dd2cb
--- /dev/null
+++ b/stay_report_py3o/README.rst
@@ -0,0 +1,47 @@
+.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png
+   :target: https://www.gnu.org/licenses/agpl
+   :alt: License: AGPL-3
+
+================
+Stay Report Py3o
+================
+
+This module replaces the default Qweb report of the *stay* module by a Py3o report.
+
+Usage
+=====
+
+.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
+   :alt: Try me on Runbot
+   :target: https://runbot.odoo-community.org/runbot/181/10.0
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues
+<https://github.com/OCA/vertical-abbey/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.
+
+Credits
+=======
+
+Contributors
+------------
+
+* Alexis de Lattre <alexis.delattre@akretion.com>
+
+Maintainer
+----------
+
+.. image:: https://odoo-community.org/logo.png
+   :alt: Odoo Community Association
+   :target: https://odoo-community.org
+
+This module is maintained by the OCA.
+
+OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
+To contribute to this module, please visit https://odoo-community.org.
diff --git a/stay_report_py3o/__init__.py b/stay_report_py3o/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/stay_report_py3o/__manifest__.py b/stay_report_py3o/__manifest__.py
new file mode 100644
index 00000000..e58adc89
--- /dev/null
+++ b/stay_report_py3o/__manifest__.py
@@ -0,0 +1,17 @@
+# Copyright 2018-2022 Akretion France (www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+    "name": "Stay Report Py3o",
+    "version": "14.0.1.0.0",
+    "category": "Lodging",
+    "license": "AGPL-3",
+    "summary": "Replace Qweb report by Py3o report on stay module",
+    "author": "Barroux Abbey, Akretion, Odoo Community Association (OCA)",
+    "maintainers": ["alexis-via"],
+    "website": "https://github.com/OCA/vertical-abbey",
+    "depends": ["report_py3o", "stay"],
+    "data": ["report.xml"],
+    "installable": True,
+}
diff --git a/stay_report_py3o/readme/CONTRIBUTORS.rst b/stay_report_py3o/readme/CONTRIBUTORS.rst
new file mode 100644
index 00000000..ff65d68c
--- /dev/null
+++ b/stay_report_py3o/readme/CONTRIBUTORS.rst
@@ -0,0 +1,1 @@
+* Alexis de Lattre <alexis.delattre@akretion.com>
diff --git a/stay_report_py3o/readme/DESCRIPTION.rst b/stay_report_py3o/readme/DESCRIPTION.rst
new file mode 100644
index 00000000..969e32c8
--- /dev/null
+++ b/stay_report_py3o/readme/DESCRIPTION.rst
@@ -0,0 +1,1 @@
+This module replaces the default Qweb report of the *stay* module by a Py3o report with a better layout.
diff --git a/stay_report_py3o/report.xml b/stay_report_py3o/report.xml
new file mode 100644
index 00000000..91ac983e
--- /dev/null
+++ b/stay_report_py3o/report.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<odoo>
+
+
+<record id="stay.report_stay_journal_print" model="ir.actions.report">
+    <field name="report_type">py3o</field>
+    <field name="py3o_filetype">odt</field>
+    <field name="module">stay_report_py3o</field>
+    <field name="py3o_template_fallback">stay_journal.odt</field>
+    <field name="py3o_multi_in_one" eval="True" />
+</record>
+
+<record id="stay.report_stay_journal_meal" model="ir.actions.report">
+    <field name="report_type">py3o</field>
+    <field name="py3o_filetype">odt</field>
+    <field name="module">stay_report_py3o</field>
+    <field name="py3o_template_fallback">stay_meal.odt</field>
+    <field name="py3o_multi_in_one" eval="True" />
+</record>
+
+
+<record id="stay.report_stay_journal_arrival" model="ir.actions.report">
+    <field name="report_type">py3o</field>
+    <field name="py3o_filetype">odt</field>
+    <field name="module">stay_report_py3o</field>
+    <field name="py3o_template_fallback">stay_arrival.odt</field>
+</record>
+
+<record id="stay.report_stay_toclean" model="ir.actions.report">
+    <field name="report_type">py3o</field>
+    <field name="py3o_filetype">odt</field>
+    <field name="module">stay_report_py3o</field>
+    <field name="py3o_template_fallback">stay_toclean.odt</field>
+</record>
+
+
+
+</odoo>
diff --git a/stay_report_py3o/static/description/icon.png b/stay_report_py3o/static/description/icon.png
new file mode 100644
index 00000000..3a0328b5
Binary files /dev/null and b/stay_report_py3o/static/description/icon.png differ
diff --git a/stay_report_py3o/stay_arrival.odt b/stay_report_py3o/stay_arrival.odt
new file mode 100644
index 00000000..95c48a36
Binary files /dev/null and b/stay_report_py3o/stay_arrival.odt differ
diff --git a/stay_report_py3o/stay_journal.odt b/stay_report_py3o/stay_journal.odt
new file mode 100644
index 00000000..6ce00491
Binary files /dev/null and b/stay_report_py3o/stay_journal.odt differ
diff --git a/stay_report_py3o/stay_meal.odt b/stay_report_py3o/stay_meal.odt
new file mode 100644
index 00000000..6d2fba38
Binary files /dev/null and b/stay_report_py3o/stay_meal.odt differ
diff --git a/stay_report_py3o/stay_toclean.odt b/stay_report_py3o/stay_toclean.odt
new file mode 100644
index 00000000..b006acd7
Binary files /dev/null and b/stay_report_py3o/stay_toclean.odt differ


Test patch:
diff --git a/donation_stay/tests/__init__.py b/donation_stay/tests/__init__.py
new file mode 100644
index 00000000..3c65b31d
--- /dev/null
+++ b/donation_stay/tests/__init__.py
@@ -0,0 +1,1 @@
+from . import test_donate_from_stay
diff --git a/donation_stay/tests/test_donate_from_stay.py b/donation_stay/tests/test_donate_from_stay.py
new file mode 100644
index 00000000..48d587c3
--- /dev/null
+++ b/donation_stay/tests/test_donate_from_stay.py
@@ -0,0 +1,57 @@
+# Copyright 2017-2021 Akretion France (http://www.akretion.com/)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo.tests.common import TransactionCase
+
+
+class TestDonationFromStay(TransactionCase):
+    def test_donate_from_stay(self):
+        stay = self.env.ref("stay.stay2")
+        dsco = self.env["donation.stay.create"]
+        ctx = {
+            "active_id": stay.id,
+            "active_ids": [stay.id],
+            "active_model": "stay.stay",
+        }
+        bank_journal = self.env["account.journal"].create(
+            {
+                "type": "bank",
+                "name": "test bank journal",
+            }
+        )
+        payment_mode = self.env["account.payment.mode"].create(
+            {
+                "name": "test_payment_mode",
+                "donation": True,
+                "bank_account_link": "fixed",
+                "fixed_journal_id": bank_journal.id,
+                "payment_method_id": self.env.ref(
+                    "account.account_payment_method_manual_in"
+                ).id,
+            }
+        )
+        payment_ref = "CHQ LBP 421242"
+        wiz = dsco.with_context(ctx).create(
+            {
+                "payment_mode_id": payment_mode.id,
+                "amount": 200,
+                "payment_ref": payment_ref,
+            }
+        )
+        action = wiz.create_donation()
+        donation_id = action["res_id"]
+        donation = self.env["donation.donation"].browse(donation_id)
+        self.assertEqual(donation.state, "draft")
+        self.assertEqual(
+            donation.campaign_id, stay.company_id.donation_stay_campaign_id
+        )
+        self.assertEqual(stay.donation_id, donation)
+        self.assertEqual(donation.amount_total, 200)
+        self.assertEqual(
+            donation.partner_id, self.env.ref("base.res_partner_address_2")
+        )
+        donation.validate()
+        self.assertEqual(donation.move_id.state, "posted")
+        self.assertEqual(donation.payment_mode_id, payment_mode)
+        self.assertEqual(donation.payment_ref, payment_ref)
diff --git a/stay/tests/__init__.py b/stay/tests/__init__.py
new file mode 100644
index 00000000..29dee70c
--- /dev/null
+++ b/stay/tests/__init__.py
@@ -0,0 +1,1 @@
+from . import test_stay
diff --git a/stay/tests/test_stay.py b/stay/tests/test_stay.py
new file mode 100644
index 00000000..e5b0c49d
--- /dev/null
+++ b/stay/tests/test_stay.py
@@ -0,0 +1,58 @@
+# Copyright 2017-2021 Akretion France
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+
+from datetime import datetime
+
+from dateutil.relativedelta import relativedelta
+
+from odoo.exceptions import UserError
+from odoo.tests.common import TransactionCase
+
+
+class TestStay(TransactionCase):
+    def test_full_scenario(self):
+        today = datetime.now().date()
+        tomorrow = today + relativedelta(days=1)
+        departure_date = tomorrow + relativedelta(days=3)
+        new_departure_date = departure_date + relativedelta(days=1)
+        refectory_id = self.env.ref("stay.refectory_ste_francoise").id
+        stay1 = self.env["stay.stay"].create(
+            {
+                "arrival_date": tomorrow,
+                "arrival_time": "afternoon",
+                "departure_date": departure_date,
+                "departure_time": "afternoon",
+                "partner_name": "Toto",
+                "guest_qty": 3,
+                "refectory_id": refectory_id,
+            }
+        )
+        self.assertEqual(stay1.state, "draft")
+        stay1.draft2confirm()
+        self.assertEqual(stay1.state, "confirm")
+        self.assertEqual(len(stay1.line_ids), 4)
+        self.assertEqual(min([line.date for line in stay1.line_ids]), tomorrow)
+        self.assertEqual(max([line.date for line in stay1.line_ids]), departure_date)
+        for line in stay1.line_ids:
+            self.assertEqual(line.refectory_id.id, refectory_id)
+            if line.date != departure_date:
+                self.assertEqual(line.bed_night_qty, stay1.guest_qty)
+        stay1.write({"arrival_date": today})
+        self.assertEqual(stay1.state, "current")
+        self.assertEqual(len(stay1.line_ids), 5)
+        self.assertEqual(min([line.date for line in stay1.line_ids]), today)
+        self.assertEqual(max([line.date for line in stay1.line_ids]), departure_date)
+        stay1.write({"arrival_date": tomorrow, "departure_date": new_departure_date})
+        self.assertEqual(stay1.state, "confirm")
+        self.assertEqual(len(stay1.line_ids), 5)
+        self.assertEqual(min([line.date for line in stay1.line_ids]), tomorrow)
+        self.assertEqual(
+            max([line.date for line in stay1.line_ids]), new_departure_date
+        )
+        with self.assertRaises(UserError):
+            stay1.unlink()
+        stay1.cancel()
+        self.assertEqual(len(stay1.line_ids), 0)
+        stay1.unlink()