Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions stay_api/README.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

====
Stay
====
========
Stay API
========

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Expand All @@ -17,7 +13,7 @@ Stay
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fvertical--abbey-lightgray.png?logo=github
Expand Down
6 changes: 3 additions & 3 deletions stay_api/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Stay",
"version": "14.0.3.3.0",
"name": "Stay API",
"version": "14.0.4.0.0",
"category": "Lodging",
"license": "AGPL-3",
"summary": "API for stay module",
"summary": "REST API for stay module",
"author": "Akretion, Odoo Community Association (OCA)",
"maintainers": ["alexis-via"],
"website": "https://github.com/OCA/vertical-abbey",
Expand Down
12 changes: 6 additions & 6 deletions stay_api/data/res_users.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
-->
<odoo noupdate="1">

<record
id="stay_api_user"
model="res.users"
context="{'no_reset_password': True, 'no_reset_password': True}"
>
<record id="stay_api_user" model="res.users" context="{'no_reset_password': True}">
<field name="name">Stay API User</field>
<field name="login">stay_api_user</field>
<field name="groups_id" eval="[(6, 0, [])]" />
<field name="email">stay_api_user@example.org</field>
<field
name="groups_id"
eval="[(6, 0, [ref('base.group_user'), ref('stay.group_stay_user'), ref('fastapi.group_fastapi_endpoint_runner')])]"
/>
</record>

</odoo>
16 changes: 16 additions & 0 deletions stay_api/migrations/14.0.4.0.0/post-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2025 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).

from openupgradelib import openupgrade


@openupgrade.migrate()
def migrate(env, version):
openupgrade.convert_field_to_html(
env.cr,
"stay_stay",
openupgrade.get_legacy_name("controller_notes"),
"controller_notes",
verbose=False,
)
16 changes: 16 additions & 0 deletions stay_api/migrations/14.0.4.0.0/pre-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2025 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).

from openupgradelib import openupgrade

_columns_copy = {
"stay_stay": [
("controller_notes", None, None),
],
}


@openupgrade.migrate()
def migrate(env, version):
openupgrade.copy_columns(env.cr, _columns_copy)
5 changes: 2 additions & 3 deletions stay_api/models/stay_stay.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class StayStay(models.Model):
controller_phone = fields.Char(tracking=True, string="Phone")
controller_mobile = fields.Char(tracking=True, string="Mobile")
controller_message = fields.Char(string="Guest Message")
controller_notes = fields.Text(string="Web Form Other Information")
controller_notes = fields.Html(string="Additional Questions")
controller_street = fields.Char(string="Address Line 1")
controller_street2 = fields.Char(string="Address Line 2")
controller_zip = fields.Char(string="ZIP")
Expand Down Expand Up @@ -204,7 +204,6 @@ def _controller_prepare_create_update(self, cobject, try_match_partner=True):
title_code = cobject.title
title_id = False
if title_code:
# TODO set lang
title = self.env["res.partner.title"].search(
[("stay_code", "=", title_code)], limit=1
)
Expand Down Expand Up @@ -282,7 +281,7 @@ def _controller_prepare_create_update(self, cobject, try_match_partner=True):
"controller_zip": cobject.zip,
"controller_city": cobject.city,
"controller_country_id": country_id,
"controller_notes": "\n".join(notes_list),
"controller_notes": "<br>".join(notes_list),
}
if try_match_partner:
vals["partner_id"] = self._controller_try_match_partner(vals)
Expand Down
165 changes: 94 additions & 71 deletions stay_api/routers/stay.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@
authenticated_partner_env,
)

from ..schemas import StayCreate, StayCreated, StayMatch, StayRead, StayUpdate
from ..schemas import (
StayCreate,
StayCreated,
StayMatch,
StayRead,
StayUpdate,
StayUpdated,
)

logger = logging.getLogger(__name__)

Expand All @@ -34,7 +41,7 @@ def stay_new(
partner: Annotated[Partner, Depends(authenticated_partner)],
staycreate: StayCreate,
) -> StayCreated:
logger.debug("Start stay create controller staycreate=%s", staycreate)
logger.info("Stay controller /new called with staycreate=%s", staycreate)
sso = env["stay.stay"]
company_id = staycreate.company_id
if not company_id:
Expand Down Expand Up @@ -110,12 +117,22 @@ def stay_new(
raise HTTPException(
status_code=status.HTTP_406_NOT_ACCEPTABLE, detail=error_msg
)
group_id = staycreate.group_id or False
if group_id:
avail_groups = env["stay.group"].search_read([], ["id"])
avail_group_ids = [group["id"] for group in avail_groups]
if group_id not in avail_group_ids:
error_msg = f"Group ID {group_id} doesn't exist."
logger.error(error_msg)
raise HTTPException(
status_code=status.HTTP_406_NOT_ACCEPTABLE, detail=error_msg
)

vals.update(
{
"controller_mode": "created",
"company_id": company_id,
"group_id": staycreate.group_id or False,
"group_id": group_id,
"guest_qty": guest_qty,
"arrival_date": arrival_date,
"departure_date": departure_date,
Expand All @@ -131,15 +148,17 @@ def stay_new(
logger.info("Mail sent for stay creation notification")
except Exception as e:
logger.error("Failed to generate stay creation email: %s", e)
return StayCreated(
name=stay.name,
id=stay.id,
company_id=vals["company_id"],
partner_id=vals["partner_id"],
phone=vals["controller_phone"],
mobile=vals["controller_mobile"],
uuid=stay.controller_uuid,
)
answer_dict = {
"name": stay.name,
"id": stay.id,
"company_id": vals["company_id"],
"partner_id": vals["partner_id"],
"phone": vals["controller_phone"],
"mobile": vals["controller_mobile"],
"uuid": stay.controller_uuid,
}
logger.info("Stay controller /new answer: %s", answer_dict)
return StayCreated(**answer_dict)


@stay_api_router.get("/cancel")
Expand All @@ -148,7 +167,7 @@ def stay_cancel(
partner: Annotated[Partner, Depends(authenticated_partner)],
staymatch: StayMatch,
):
logger.debug("Start stay cancel controller staymatch=%s", staymatch)
logger.info("Stay controller /cancel called with staymatch=%s", staymatch)
stay = env["stay.stay"]._get_stay_from_uuid(
staymatch.uuid, "/cancel", ignore_states=("cancel", "done")
)
Expand All @@ -171,47 +190,47 @@ def stay_read(
partner: Annotated[Partner, Depends(authenticated_partner)],
staymatch: StayMatch,
) -> StayRead:
logger.debug("Start stay read controller staymatch=%s", staymatch)
logger.info("Stay controller /read called wih staymatch=%s", staymatch)
stay = env["stay.stay"]._get_stay_from_uuid(
staymatch.uuid, "/read", raise_states=("cancel", "done")
)
if stay:
vals = {
"name": stay.name,
"guest_qty": stay.guest_qty,
"arrival_date": stay.arrival_date,
"departure_date": stay.departure_date,
}
if stay.arrival_time != "unknown":
vals["arrival_time"] = stay.arrival_time
if stay.departure_time != "unknown":
vals["departure_time"] = stay.departure_time
if stay.partner_id:
vals = {
"name": stay.name,
"guest_qty": stay.guest_qty,
"arrival_date": stay.arrival_date,
"departure_date": stay.departure_date,
}
if stay.arrival_time != "unknown":
vals["arrival_time"] = stay.arrival_time
if stay.departure_time != "unknown":
vals["departure_time"] = stay.departure_time
if stay.partner_id:
vals.update(
{
"street": stay.partner_id.street or None,
"street2": stay.partner_id.street2 or None,
"zip": stay.partner_id.zip or None,
"city": stay.partner_id.city or None,
"country_code": stay.partner_id.country_id
and stay.partner_id.country_id.code
or None,
"phone": stay.partner_id.phone or None,
"mobile": stay.partner_id.mobile or None,
"email": stay.partner_id.email or None,
"partner_name": stay.partner_id.name,
}
)
if hasattr(stay.partner_id, "firstname"):
vals.update(
{
"street": stay.partner_id.street or None,
"street2": stay.partner_id.street2 or None,
"zip": stay.partner_id.zip or None,
"city": stay.partner_id.city or None,
"country_code": stay.partner_id.country_id
and stay.partner_id.country_id.code
or None,
"phone": stay.partner_id.phone or None,
"mobile": stay.partner_id.mobile or None,
"email": stay.partner_id.email or None,
"partner_name": stay.partner_id.name,
"firstname": stay.partner_id.firstname,
"lastname": stay.partner_id.lastname,
}
)
if hasattr(stay.partner_id, "firstname"):
vals.update(
{
"firstname": stay.partner_id.firstname,
"lastname": stay.partner_id.lastname,
}
)
if stay.partner_id.title and stay.partner_id.title.stay_code:
vals["title"] = stay.partner_id.title.stay_code
return StayRead(**vals)
if stay.partner_id.title and stay.partner_id.title.stay_code:
vals["title"] = stay.partner_id.title.stay_code
logger.info("Stay controller /read answer: %s", vals)
return StayRead(**vals)


@stay_api_router.post("/update")
Expand All @@ -220,30 +239,34 @@ def stay_update(
partner: Annotated[Partner, Depends(authenticated_partner)],
stayupdate: StayUpdate,
):
logger.debug("Start stay update controller stayupdate=%s", stayupdate)
logger.info("Stay controller /update called wih stayupdate=%s", stayupdate)
stay = env["stay.stay"]._get_stay_from_uuid(
stayupdate.uuid, "/update", raise_states=("cancel", "done")
)
if stay:
try_match_partner = True
if stay.partner_id:
try_match_partner = False
vals = env["stay.stay"]._controller_prepare_create_update(
stayupdate, try_match_partner=try_match_partner
)
if not vals:
return False
vals.update(
{
"controller_mode": "updated",
}
)
logger.debug("Updating stay %s ID %s with vals=%s", stay.name, stay.id, vals)
stay.write(vals)
try:
env.ref("stay_api.stay_controller_notify").sudo().with_context(
action_description=_("updated")
).send_mail(stay.id)
logger.info("Mail sent for stay update notification")
except Exception as e:
logger.error("Failed to generate stay update email: %s", e)
try_match_partner = True
if stay.partner_id:
try_match_partner = False
vals = env["stay.stay"]._controller_prepare_create_update(
stayupdate, try_match_partner=try_match_partner
)
if not vals:
return False
vals["controller_mode"] = "updated"
logger.debug("Updating stay %s ID %s with vals=%s", stay.name, stay.id, vals)
stay.write(vals)
try:
env.ref("stay_api.stay_controller_notify").sudo().with_context(
action_description=_("updated")
).send_mail(stay.id)
logger.info("Mail sent for stay update notification")
except Exception as e:
logger.error("Failed to generate stay update email: %s", e)
answer_dict = {
"name": stay.name,
"id": stay.id,
"phone": vals["controller_phone"],
"mobile": vals["controller_mobile"],
"partner_id": stay.partner_id.id or None,
}
logger.info("Stay controller /update answer: %s", answer_dict)
return StayUpdated(**answer_dict)
1 change: 1 addition & 0 deletions stay_api/schemas/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from .stay_match import StayMatch
from .stay_read import StayRead
from .stay_update import StayUpdate
from .stay_updated import StayUpdated
1 change: 0 additions & 1 deletion stay_api/schemas/stay_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class StayUpdate(BaseModel):
departure_time: str
departure_note: str = None
company_id: int = None
group_id: int = None
message: str = None
notes_list: list = None
country_code: str = None
Expand Down
13 changes: 13 additions & 0 deletions stay_api/schemas/stay_updated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2025 Akretion France (https://www.akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from pydantic import BaseModel


class StayUpdated(BaseModel):
name: str
id: int
phone: str = None
mobile: str = None
partner_id: int = None
Loading