[FIX]14.0-pms_api_rest: fix pre-commit

This commit is contained in:
braisab
2023-12-19 17:00:31 +01:00
committed by Darío Lodeiros
parent 3106e6246b
commit a9e5f72927
34 changed files with 658 additions and 411 deletions

View File

@@ -27,6 +27,7 @@
"views/pms_property_views.xml",
"views/res_users_views.xml",
"views/pms_room_type_class_views.xml",
"views/product_template_views.xml",
],
"demo": [
"demo/pms_api_rest_master_data.xml",

View File

@@ -1,20 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<record id="pms_reset_password_email" model="mail.template">
<field name="name">Pms Reset Password</field>
<field name="model_id" ref="base.model_res_users"/>
<field name="model_id" ref="base.model_res_users" />
<field name="subject">Restablecer Contraseña</field>
<field name="email_from">"${object.company_id.name | safe}" &lt;${(object.company_id.email or user.email) | safe}&gt;</field>
<field
name="email_from"
>"${object.company_id.name | safe}" &lt;${(object.company_id.email or user.email) | safe}&gt;</field>
<field name="email_to">${object.email_formatted | safe}</field>
<field name="body_html" type="html">
<table border="0" cellpadding="0" cellspacing="0" style=" font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;"><tr><td align="center">
<table border="0" cellpadding="0" cellspacing="0" width="590" style="background-color: white; color: #454748; border-collapse:separate; font-family:Verdana, font-family:Verdana, Arial,sans-serif; box-shadow: rgb(0 0 0 / 24%) 0px 3px 8px; border-radius: 24px">
<table
border="0"
cellpadding="0"
cellspacing="0"
style=" font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;"
><tr><td align="center">
<table
border="0"
cellpadding="0"
cellspacing="0"
width="590"
style="background-color: white; color: #454748; border-collapse:separate; font-family:Verdana, font-family:Verdana, Arial,sans-serif; box-shadow: rgb(0 0 0 / 24%) 0px 3px 8px; border-radius: 24px"
>
<tbody>
<!-- HEADER -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590" height="100" style="min-width: 590px; background-color: #4BB1E0; color:white; border-collapse:separate; border-radius: 24px 24px 0 0">
<table
border="0"
cellpadding="0"
cellspacing="0"
width="590"
height="100"
style="min-width: 590px; background-color: #4BB1E0; color:white; border-collapse:separate; border-radius: 24px 24px 0 0"
>
<tr>
<td valign="middle" align="middle">
<span style="font-size: 24px; font-weight: bold;">
@@ -27,13 +46,23 @@
</tr>
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; border-collapse:separate;padding: 24px 24px 0 24px; margin-bottom: 24px;">
<table
border="0"
cellpadding="0"
cellspacing="0"
width="590"
style="min-width: 590px; background-color: white; border-collapse:separate;padding: 24px 24px 0 24px; margin-bottom: 24px;"
>
<tr><td valign="middle">
<span style="font-size: 20px; font-weight: bold;">
${object.name}
</span>
</td><td valign="middle" align="right">
<img src="/logo.png?company=${object.company_id.id}" style="padding: 0px; margin: 0px; height: auto; width: 80px;" alt="${object.company_id.name}"/>
<img
src="/logo.png?company=${object.company_id.id}"
style="padding: 0px; margin: 0px; height: auto; width: 80px;"
alt="${object.company_id.name}"
/>
</td></tr>
</table>
</td>
@@ -41,22 +70,31 @@
<!-- CONTENT -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 24px; border-collapse:separate; margin-bottom: 40px">
<table
border="0"
cellpadding="0"
cellspacing="0"
width="590"
style="min-width: 590px; background-color: white; padding: 0px 24px; border-collapse:separate; margin-bottom: 40px"
>
<tr><td valign="top" style="font-size: 13px;">
<div>
A password reset was requested for the Odoo account linked to this email.
You may change your password by following this link which will remain valid during 15 minutes:
<br/>
<br />
<div style="margin: 32px 0">
<a href="${ctx.get('app_url')}/reset-password?token=${object.signup_token}"
style="background-color: #4BB1E0; padding: 8px 16px 8px 16px; text-decoration: none; color: #fff; border-radius: 5px; font-size:13px;">
<a
href="${ctx.get('app_url')}/reset-password?token=${object.signup_token}"
style="background-color: #4BB1E0; padding: 8px 16px 8px 16px; text-decoration: none; color: #fff; border-radius: 5px; font-size:13px;"
>
Reestablecer contraseña
</a>
</div>
If you do not expect this, you can safely ignore this email.<br/><br/>
If you do not expect this, you can safely ignore this email.<br
/><br />
Thanks,
% if user.signature:
<br/>
<br />
${user.signature | safe}
% endif
</div>
@@ -67,17 +105,29 @@
<!-- FOOTER -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590" style="border-radius: 0 0 24px 24px;min-width: 590px; background-color: white; font-size: 11px; padding: 0 24px 24px 24px; border-collapse:separate;">
<table
border="0"
cellpadding="0"
cellspacing="0"
width="590"
style="border-radius: 0 0 24px 24px;min-width: 590px; background-color: white; font-size: 11px; padding: 0 24px 24px 24px; border-collapse:separate;"
>
<tr><td valign="middle" align="left">
${object.company_id.name}
</td></tr>
<tr><td valign="middle" align="left" style="opacity: 0.7;">
${object.company_id.phone}
% if object.company_id.email
| <a href="'mailto:%s' % ${object.company_id.email}" style="text-decoration:none; color: #454748;">${object.company_id.email}</a>
| <a
href="'mailto:%s' % ${object.company_id.email}"
style="text-decoration:none; color: #454748;"
>${object.company_id.email}</a>
% endif
% if object.company_id.website
| <a href="'%s' % ${object.company_id.website}" style="text-decoration:none; color: #454748;">
| <a
href="'%s' % ${object.company_id.website}"
style="text-decoration:none; color: #454748;"
>
${object.company_id.website}
</a>
% endif
@@ -92,8 +142,6 @@
</table>
</field>
<field name="lang">${object.lang}</field>
<field name="auto_delete" eval="True"/>
</record>
</data>
<field name="auto_delete" eval="True" />
</record>
</odoo>

View File

@@ -62,4 +62,3 @@ from . import pms_reservation_message
from . import pms_avail
from . import pms_dashboard
from . import feed_post

View File

@@ -4,7 +4,7 @@ from odoo.addons.datamodel.core import Datamodel
class FeedPost(Datamodel):
_name ="feed.post.info"
_name = "feed.post.info"
postId = fields.String(required=True, allow_none=False)
title = fields.String(required=True, allow_none=False)
link = fields.String(required=True, allow_none=False)
@@ -12,4 +12,3 @@ class FeedPost(Datamodel):
publishDate = fields.String(required=True, allow_none=False)
author = fields.String(required=True, allow_none=False)
imageUrl = fields.String(required=True, allow_none=False)

View File

@@ -36,7 +36,9 @@ class PmsDashboardStateRooms(Datamodel):
class PmsDashboardReservationsBySaleChannel(Datamodel):
_name = "pms.dashboard.reservations.by.sale.channel"
saleChannelName = fields.String(required=False, allow_none=True)
percentageReservationsSoldBySaleChannel = fields.Integer(required=False, allow_none=True)
percentageReservationsSoldBySaleChannel = fields.Integer(
required=False, allow_none=True
)
class PmsDashboardNumericResponse(Datamodel):
@@ -45,6 +47,6 @@ class PmsDashboardNumericResponse(Datamodel):
class PmsDashboardDailyBilling(Datamodel):
_name ="pms.dashboard.daily.billing"
_name = "pms.dashboard.daily.billing"
date = fields.String(required=False, allow_none=True)
billing = fields.Float(required=False, allow_none=True)

View File

@@ -3,6 +3,7 @@ from marshmallow import fields
from odoo.addons.datamodel.core import Datamodel
from odoo.addons.datamodel.fields import NestedModel
class PmsInvoiceSearchParam(Datamodel):
_name = "pms.invoice.search.param"
_inherit = "pms.rest.metadata"
@@ -14,6 +15,7 @@ class PmsInvoiceSearchParam(Datamodel):
dateEnd = fields.String(required=False, allow_none=True)
pmsPropertyId = fields.Integer(required=False, allow_none=True)
class PmsAccountInvoiceInfo(Datamodel):
_name = "pms.invoice.info"
id = fields.Integer(required=False, allow_none=True)
@@ -25,7 +27,9 @@ class PmsAccountInvoiceInfo(Datamodel):
# REVIEW: partnerName??, is not enought partnerId?
partnerName = fields.String(required=False, allow_none=True)
partnerId = fields.Integer(required=False, allow_none=True)
moveLines = fields.List(NestedModel("pms.invoice.line.info"), required=False, allow_none=True)
moveLines = fields.List(
NestedModel("pms.invoice.line.info"), required=False, allow_none=True
)
folioId = fields.Integer(required=False, allow_none=True)
saleLines = fields.List(NestedModel("pms.folio.sale.line.info"))
narration = fields.String(required=False, allow_none=True)
@@ -42,9 +46,9 @@ class PmsAccountInvoiceInfo(Datamodel):
ref = fields.String(required=False, allow_none=True)
pmsPropertyId = fields.Integer(required=False, allow_none=True)
class PmsInvoiceResults(Datamodel):
_name = "pms.invoice.results"
invoices = fields.List(NestedModel("pms.invoice.info"))
total = fields.Float(required=False, allow_none=True)
totalInvoices = fields.Integer(required=False, allow_none=True)

View File

@@ -32,6 +32,7 @@ class PmsApiRestUserOutput(Datamodel):
fields.String(), required=False, allow_none=True
)
class PmsApiRestUserLoginOutput(Datamodel):
_name = "pms.api.rest.user.login.output"
login = fields.String(required=True, allow_none=False)

View File

@@ -6,6 +6,8 @@ from odoo.addons.datamodel.core import Datamodel
class ResCityZipSearchParam(Datamodel):
_name = "res.city.zip.search.param"
address = fields.String(required=False, allow_none=False)
class ResCityZipInfo(Datamodel):
_name = "res.city.zip.info"
resZipId = fields.Integer(required=False, allow_none=True)

View File

@@ -1,32 +1,50 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="1">
<record id="base.user_admin" model="res.users">
<field
name="availability_rule_field_ids"
eval="[(6, 0, [ref('pms.field_pms_availability_plan_rule__min_stay'), ref('pms.field_pms_availability_plan_rule__quota')])]"
/>
</record>
<record id="base.user_demo" model="res.users">
<field
name="availability_rule_field_ids"
eval="[(6, 0, [ref('pms.field_pms_availability_plan_rule__min_stay'), ref('pms.field_pms_availability_plan_rule__quota')])]"
/>
</record>
<record id="pms.main_pms_property" model="pms.property">
<field name="hotel_image_pms_api_rest" type="base64" file="pms_api_rest/demo/pms_property_hotel_image_pms_api_rest_my_property.jpg"/>
</record>
<record id="pms.san_carlos_property" model="pms.property">
<field name="hotel_image_pms_api_rest" type="base64" file="pms_api_rest/demo/pms_property_hotel_image_pms_api_rest_san_carlos.jpg"/>
</record>
<record id="pms.pms_room_type_class_bedroom" model="pms.room.type.class">
<field name="icon_pms_api_rest" type="base64" file="pms_api_rest/demo/pms_room_type_class_icon_pms_api_rest_room.svg"/>
</record>
<record id="pms.pms_room_type_class_conference_room" model="pms.room.type.class">
<field name="icon_pms_api_rest" type="base64" file="pms_api_rest/demo/pms_room_type_class_icon_pms_api_rest_conference.svg"/>
</record>
<record id="pms.pms_room_type_class_parking" model="pms.room.type.class">
<field name="icon_pms_api_rest" type="base64" file="pms_api_rest/demo/pms_room_type_class_icon_pms_api_rest_parking.svg"/>
</record>
</data>
<odoo noupdate="1">
<record id="base.user_admin" model="res.users">
<field
name="availability_rule_field_ids"
eval="[(6, 0, [ref('pms.field_pms_availability_plan_rule__min_stay'), ref('pms.field_pms_availability_plan_rule__quota')])]"
/>
</record>
<record id="base.user_demo" model="res.users">
<field
name="availability_rule_field_ids"
eval="[(6, 0, [ref('pms.field_pms_availability_plan_rule__min_stay'), ref('pms.field_pms_availability_plan_rule__quota')])]"
/>
</record>
<record id="pms.main_pms_property" model="pms.property">
<field
name="hotel_image_pms_api_rest"
type="base64"
file="pms_api_rest/demo/pms_property_hotel_image_pms_api_rest_my_property.jpg"
/>
</record>
<record id="pms.san_carlos_property" model="pms.property">
<field
name="hotel_image_pms_api_rest"
type="base64"
file="pms_api_rest/demo/pms_property_hotel_image_pms_api_rest_san_carlos.jpg"
/>
</record>
<record id="pms.pms_room_type_class_bedroom" model="pms.room.type.class">
<field
name="icon_pms_api_rest"
type="base64"
file="pms_api_rest/demo/pms_room_type_class_icon_pms_api_rest_room.svg"
/>
</record>
<record id="pms.pms_room_type_class_conference_room" model="pms.room.type.class">
<field
name="icon_pms_api_rest"
type="base64"
file="pms_api_rest/demo/pms_room_type_class_icon_pms_api_rest_conference.svg"
/>
</record>
<record id="pms.pms_room_type_class_parking" model="pms.room.type.class">
<field
name="icon_pms_api_rest"
type="base64"
file="pms_api_rest/demo/pms_room_type_class_icon_pms_api_rest_parking.svg"
/>
</record>
</odoo>

View File

@@ -2,18 +2,24 @@ from odoo.http import request
def url_image_pms_api_rest(model, record_id, field):
rt_image_attach = request.env['ir.attachment'].sudo().search([
('res_model', '=', model),
('res_id', '=', record_id),
('res_field', '=', field),
])
rt_image_attach = (
request.env["ir.attachment"]
.sudo()
.search(
[
("res_model", "=", model),
("res_id", "=", record_id),
("res_field", "=", field),
]
)
)
if rt_image_attach and not rt_image_attach.access_token:
rt_image_attach.generate_access_token()
result = (
request.env['ir.config_parameter']
.sudo().get_param('web.base.url') +
'/web/image/%s?access_token=%s' % (
rt_image_attach.id, rt_image_attach.access_token
) if rt_image_attach else False
request.env["ir.config_parameter"].sudo().get_param("web.base.url")
+ "/web/image/%s?access_token=%s"
% (rt_image_attach.id, rt_image_attach.access_token)
if rt_image_attach
else False
)
return result if result else ''
return result if result else ""

View File

@@ -24,7 +24,7 @@ class PmsFeedRss(Component):
def get_feed_posts(self):
result_rss = []
PmsFeedRss = self.env.datamodels["feed.post.info"]
for rss in self.env["rss.post"].search([], limit=5, order='publish_date desc'):
for rss in self.env["rss.post"].search([], limit=5, order="publish_date desc"):
result_rss.append(
PmsFeedRss(
postId=rss.post_id,
@@ -33,7 +33,8 @@ class PmsFeedRss(Component):
description=rss.description,
publishDate=str(rss.publish_date),
author=rss.author if rss.author else "",
imageUrl="https://www.roomdoo.com/wp-content/uploads/2021/09/hotel-roomdoo.png"
imageUrl="https://www.roomdoo.com/wp-content"
"/uploads/2021/09/hotel-roomdoo.png",
)
)
return result_rss

View File

@@ -43,7 +43,9 @@ class PmsAgencyService(Component):
PmsAgencyInfo(
id=agency.id,
name=agency.name,
imageUrl=url_image_pms_api_rest('res.partner', agency.id, 'image_128'),
imageUrl=url_image_pms_api_rest(
"res.partner", agency.id, "image_128"
),
)
)
return result_agencies
@@ -72,7 +74,7 @@ class PmsAgencyService(Component):
return PmsAgencieInfo(
id=agency.id,
name=agency.name if agency.name else None,
imageUrl=url_image_pms_api_rest('res.partner', agency.id, 'image_128'),
imageUrl=url_image_pms_api_rest("res.partner", agency.id, "image_128"),
)
else:
raise MissingError(_("Agency not found"))

View File

@@ -1,5 +1,6 @@
from datetime import datetime, timedelta
from odoo import _
from odoo.exceptions import MissingError, ValidationError
from odoo.addons.base_rest import restapi
@@ -238,14 +239,24 @@ class PmsAvailabilityPlanService(Component):
input_param=Datamodel("pms.availability.plan.rules.info", is_list=False),
auth="jwt_api_pms",
)
def create_availability_plan_rule(self, availability_plan_id, pms_avail_plan_rules_info):
def create_availability_plan_rule(
self, availability_plan_id, pms_avail_plan_rules_info
):
availability_plan_ids = list(
{
item.availabilityPlanId for item in pms_avail_plan_rules_info.availabilityPlanRules
item.availabilityPlanId
for item in pms_avail_plan_rules_info.availabilityPlanRules
}
)
if len(availability_plan_ids) > 1 or availability_plan_ids[0] != availability_plan_id:
raise ValidationError("You cannot create availability plan rules for different availability plans")
if (
len(availability_plan_ids) > 1
or availability_plan_ids[0] != availability_plan_id
):
raise ValidationError(
_(
"You cannot create availability plan rules for different availability plans"
)
)
else:
self._create_or_update_avail_plan_rules(pms_avail_plan_rules_info)

View File

@@ -52,7 +52,9 @@ class PmsBoardServiceService(Component):
roomTypeId=board_service.pms_room_type_id.id,
amount=round(board_service.amount, 2),
boardServiceId=board_service.pms_board_service_id,
productIds=board_service.board_service_line_ids.mapped("product_id.id"),
productIds=board_service.board_service_line_ids.mapped(
"product_id.id"
),
)
)
return result_board_services

View File

@@ -5,7 +5,7 @@ from odoo.addons.base_rest_datamodel.restapi import Datamodel
from odoo.addons.component.core import Component
def build_reservation_line_info( calendar_item, previous_item=False, next_item=False):
def build_reservation_line_info(calendar_item, previous_item=False, next_item=False):
next_itemSplitted = (
calendar_item["splitted"]
and next_item
@@ -25,29 +25,39 @@ def build_reservation_line_info( calendar_item, previous_item=False, next_item=F
)
)
return {
"date": datetime.combine(calendar_item['date'], datetime.min.time()).isoformat(),
"roomId": calendar_item['room_id'],
"roomTypeId": calendar_item['room_type_id'],
"id": calendar_item['id'],
"state": calendar_item['state'],
"priceDayTotal": calendar_item['price_day_total'],
"toAssign": calendar_item['to_assign'],
"splitted": calendar_item['splitted'],
"partnerId": calendar_item['partner_id'],
"partnerName": calendar_item['partner_name'],
"folioId": calendar_item['folio_id'],
"reservationId": calendar_item['reservation_id'],
"reservationName": calendar_item['reservation_name'],
"reservationType": calendar_item['reservation_type'],
"checkin": datetime.combine(calendar_item['checkin'], datetime.min.time()).isoformat(),
"checkout": datetime.combine(calendar_item['checkout'], datetime.min.time()).isoformat(),
"priceTotal": calendar_item['price_total'],
"adults": calendar_item['adults'],
"pendingPayment": calendar_item['folio_pending_amount'],
"closureReasonId": calendar_item['closure_reason_id'],
"isFirstNight": calendar_item['date'] == calendar_item['checkin'] if calendar_item['checkin'] else None,
"isLastNight": calendar_item['date'] == calendar_item['checkout'] + timedelta(days=-1)
if calendar_item['checkout'] else None,
"date": datetime.combine(
calendar_item["date"], datetime.min.time()
).isoformat(),
"roomId": calendar_item["room_id"],
"roomTypeId": calendar_item["room_type_id"],
"id": calendar_item["id"],
"state": calendar_item["state"],
"priceDayTotal": calendar_item["price_day_total"],
"toAssign": calendar_item["to_assign"],
"splitted": calendar_item["splitted"],
"partnerId": calendar_item["partner_id"],
"partnerName": calendar_item["partner_name"],
"folioId": calendar_item["folio_id"],
"reservationId": calendar_item["reservation_id"],
"reservationName": calendar_item["reservation_name"],
"reservationType": calendar_item["reservation_type"],
"checkin": datetime.combine(
calendar_item["checkin"], datetime.min.time()
).isoformat(),
"checkout": datetime.combine(
calendar_item["checkout"], datetime.min.time()
).isoformat(),
"priceTotal": calendar_item["price_total"],
"adults": calendar_item["adults"],
"pendingPayment": calendar_item["folio_pending_amount"],
"closureReasonId": calendar_item["closure_reason_id"],
"isFirstNight": calendar_item["date"] == calendar_item["checkin"]
if calendar_item["checkin"]
else None,
"isLastNight": calendar_item["date"]
== calendar_item["checkout"] + timedelta(days=-1)
if calendar_item["checkout"]
else None,
"nextLineSplitted": next_itemSplitted,
"previousLineSplitted": previous_itemSplitted,
}
@@ -55,20 +65,20 @@ def build_reservation_line_info( calendar_item, previous_item=False, next_item=F
def build_restriction(item):
result = {}
if item['closed'] is not None and item['closed']:
result.update({'closed': True})
if item['closed_arrival'] is not None and item['closed_arrival']:
result.update({'closedArrival': True})
if item['closed_departure'] is not None and item['closed_departure']:
result.update({'closedDeparture': True})
if item['min_stay'] is not None and item['min_stay'] != 0:
result.update({'minStay': item['min_stay']})
if item['max_stay'] is not None and item['max_stay'] != 0:
result.update({'maxStay': item['max_stay']})
if item['min_stay_arrival'] is not None and item['min_stay_arrival'] != 0:
result.update({'minStayArrival': item['min_stay_arrival']})
if item['max_stay_arrival'] is not None and item['max_stay_arrival'] != 0:
result.update({'maxStayArrival': item['max_stay_arrival']})
if item["closed"] is not None and item["closed"]:
result.update({"closed": True})
if item["closed_arrival"] is not None and item["closed_arrival"]:
result.update({"closedArrival": True})
if item["closed_departure"] is not None and item["closed_departure"]:
result.update({"closedDeparture": True})
if item["min_stay"] is not None and item["min_stay"] != 0:
result.update({"minStay": item["min_stay"]})
if item["max_stay"] is not None and item["max_stay"] != 0:
result.update({"maxStay": item["max_stay"]})
if item["min_stay_arrival"] is not None and item["min_stay_arrival"] != 0:
result.update({"minStayArrival": item["min_stay_arrival"]})
if item["max_stay_arrival"] is not None and item["max_stay_arrival"] != 0:
result.update({"maxStayArrival": item["max_stay_arrival"]})
return result
@@ -165,7 +175,7 @@ class PmsCalendarService(Component):
item
for item in lines
if item["reservation_id"] == line["reservation_id"]
and item["date"] == line["date"] + timedelta(days=1)
and item["date"] == line["date"] + timedelta(days=1)
),
False,
)
@@ -177,7 +187,7 @@ class PmsCalendarService(Component):
item
for item in lines
if item["reservation_id"] == line["reservation_id"]
and item["date"] == line["date"] + timedelta(days=-1)
and item["date"] == line["date"] + timedelta(days=-1)
),
False,
)
@@ -277,24 +287,25 @@ class PmsCalendarService(Component):
r_rt_rtc.room_type_class_id,
r_rt_rtc.sequence
FROM (SELECT (CURRENT_DATE + date ) date
FROM generate_series(date %s- CURRENT_DATE, date %s - CURRENT_DATE) date
FROM generate_series(date %s- CURRENT_DATE, date %s - CURRENT_DATE) date
) dates,
(SELECT r.id room_id, r.capacity, rt.id room_type_id, rtc.id room_type_class_id,
r.sequence
(SELECT r.id room_id, r.capacity, rt.id room_type_id,
rtc.id room_type_class_id, r.sequence
FROM pms_room r
INNER JOIN pms_room_type rt ON rt.id = r.room_type_id
INNER JOIN pms_room_type_class rtc ON rtc.id = rt.class_id
WHERE r.active = true AND r.pms_property_id = %s) r_rt_rtc
) dr
LEFT OUTER JOIN ( SELECT id, state, price_day_total, room_id, date, reservation_id
FROM pms_reservation_line
WHERE pms_property_id = %s AND state != 'cancel'
AND occupies_availability = true AND date <= %s
LEFT OUTER JOIN (
SELECT id, state, price_day_total, room_id, date, reservation_id
FROM pms_reservation_line
WHERE pms_property_id = %s AND state != 'cancel'
AND occupies_availability = true AND date <= %s
) l ON l.room_id = dr.room_id AND l.date = dr.date
LEFT OUTER JOIN ( SELECT date, room_type_id, min_stay, min_stay_arrival, max_stay,
max_stay_arrival, closed, closed_departure, closed_arrival
FROM pms_availability_plan_rule
WHERE availability_plan_id = %s and pms_property_id = %s
LEFT OUTER JOIN (SELECT date, room_type_id, min_stay, min_stay_arrival,
max_stay, max_stay_arrival, closed, closed_departure, closed_arrival
FROM pms_availability_plan_rule
WHERE availability_plan_id = %s and pms_property_id = %s
) ru ON ru.date = dr.date AND ru.room_type_id = dr.room_type_id
LEFT OUTER JOIN pms_reservation r ON l.reservation_id = r.id
LEFT OUTER JOIN pms_folio f ON r.folio_id = f.id
@@ -317,17 +328,19 @@ class PmsCalendarService(Component):
index_date_last_reservation = False
for index, item in enumerate(result):
date = {
"date": datetime.combine(item['date'], datetime.min.time()).isoformat(),
"date": datetime.combine(item["date"], datetime.min.time()).isoformat(),
"reservationLines": [],
}
restriction = build_restriction(item)
if restriction:
date.update({
"restriction": restriction,
})
date.update(
{
"restriction": restriction,
}
)
if last_room_id != item['room_id']:
last_room_id = item['room_id']
if last_room_id != item["room_id"]:
last_room_id = item["room_id"]
last_reservation_id = False
response.append(
CalendarRenderInfo(
@@ -335,17 +348,16 @@ class PmsCalendarService(Component):
capacity=item["capacity"],
roomTypeClassId=item["room_type_class_id"],
roomTypeId=item["room_type_id"],
dates=[
date
],
dates=[date],
)
)
else:
response[-1].dates.append(
date
)
if item['reservation_id'] is not None and item['reservation_id'] != last_reservation_id:
response[-1].dates[-1]['reservationLines'].append(
response[-1].dates.append(date)
if (
item["reservation_id"] is not None
and item["reservation_id"] != last_reservation_id
):
response[-1].dates[-1]["reservationLines"].append(
build_reservation_line_info(
item,
previous_item=False
@@ -356,10 +368,15 @@ class PmsCalendarService(Component):
else result[index + 1],
)
)
last_reservation_id = item['reservation_id']
last_reservation_id = item["reservation_id"]
index_date_last_reservation = len(response[-1].dates) - 1
elif item['reservation_id'] is not None and item['reservation_id'] == last_reservation_id:
response[-1].dates[index_date_last_reservation]['reservationLines'].append(
elif (
item["reservation_id"] is not None
and item["reservation_id"] == last_reservation_id
):
response[-1].dates[index_date_last_reservation][
"reservationLines"
].append(
build_reservation_line_info(
item,
previous_item=False
@@ -370,7 +387,7 @@ class PmsCalendarService(Component):
else result[index + 1],
)
)
last_reservation_id = item['reservation_id']
last_reservation_id = item["reservation_id"]
else:
last_reservation_id = False
return response
@@ -394,7 +411,7 @@ class PmsCalendarService(Component):
date_to = datetime.strptime(calendar_search_param.dateTo, "%Y-%m-%d").date()
self.env.cr.execute(
f"""
"""
SELECT dr.room_type_id,
dr.date date,
it.id pricelist_item_id,
@@ -412,7 +429,8 @@ class PmsCalendarService(Component):
SELECT ipp.value_float
FROM ir_pms_property ipp, (SELECT id field_id, model_id
FROM ir_model_fields
WHERE name = 'list_price' AND model = 'product.template'
WHERE name = 'list_price'
AND model = 'product.template'
) imf
WHERE ipp.model_id = imf.model_id
AND ipp.field_id = imf.field_id
@@ -422,7 +440,8 @@ class PmsCalendarService(Component):
) price,
(SELECT COUNT (1)
FROM pms_room r
WHERE r.room_type_id = dr.room_type_id AND r.active = true AND r.pms_property_id = %s
WHERE r.room_type_id = dr.room_type_id
AND r.active = true AND r.pms_property_id = %s
AND NOT EXISTS (SELECT 1
FROM pms_reservation_line
WHERE date = dr.date
@@ -465,7 +484,8 @@ class PmsCalendarService(Component):
AND it.pricelist_id = %s
AND EXISTS (SELECT 1
FROM product_pricelist_item_pms_property_rel relp
WHERE relp.product_pricelist_item_id = it.id AND relp.pms_property_id = %s)
WHERE relp.product_pricelist_item_id = it.id
AND relp.pms_property_id = %s)
ORDER BY dr.sequence, dr.room_type_id, dr.date;
""",
(
@@ -482,30 +502,30 @@ class PmsCalendarService(Component):
)
result = self.env.cr.dictfetchall()
CalendarPricesRulesRenderInfo = self.env.datamodels["pms.calendar.prices.rules.render.info"]
CalendarPricesRulesRenderInfo = self.env.datamodels[
"pms.calendar.prices.rules.render.info"
]
last_room_type_id = False
for index, item in enumerate(result):
for _index, item in enumerate(result):
date = {
"date": datetime.combine(item['date'], datetime.min.time()).isoformat(),
"freeRooms": item['free_rooms'],
"pricelistItemId": item['pricelist_item_id'],
"price": item['price'],
"date": datetime.combine(item["date"], datetime.min.time()).isoformat(),
"freeRooms": item["free_rooms"],
"pricelistItemId": item["pricelist_item_id"],
"price": item["price"],
#
"availabilityPlanRuleId": item['availability_plan_rule_id'],
"maxAvail": item['max_avail'],
"quota": item['quota'],
"closed": item['closed'],
"closedArrival": item['closed_arrival'],
"closedDeparture": item['closed_departure'],
"minStay": item['min_stay'],
"minStayArrival": item['min_stay_arrival'],
"maxStay": item['max_stay'],
"maxStayArrival": item['max_stay_arrival'],
"availabilityPlanRuleId": item["availability_plan_rule_id"],
"maxAvail": item["max_avail"],
"quota": item["quota"],
"closed": item["closed"],
"closedArrival": item["closed_arrival"],
"closedDeparture": item["closed_departure"],
"minStay": item["min_stay"],
"minStayArrival": item["min_stay_arrival"],
"maxStay": item["max_stay"],
"maxStayArrival": item["max_stay_arrival"],
}
if last_room_type_id != item['room_type_id']:
last_room_type_id = item['room_type_id']
if last_room_type_id != item["room_type_id"]:
last_room_type_id = item["room_type_id"]
response.append(
CalendarPricesRulesRenderInfo(
roomTypeId=item["room_type_id"],
@@ -537,7 +557,7 @@ class PmsCalendarService(Component):
room_ids = tuple(calendar_search_param.roomIds)
self.env.cr.execute(
f"""
"""
SELECT d.date,
bool_or(l.overbooking) overbooking,
CEIL(SUM(l.price_day_total)) daily_billing,
@@ -600,10 +620,14 @@ class PmsCalendarService(Component):
for item in result:
response.append(
CalendarHeaderInfo(
date=datetime.combine(item['date'], datetime.min.time()).isoformat(),
date=datetime.combine(
item["date"], datetime.min.time()
).isoformat(),
dailyBilling=item["daily_billing"] if item["daily_billing"] else 0,
freeRooms=item["free_rooms"] if item["free_rooms"] else 0,
occupancyRate=item["occupancy_rate"] if item["occupancy_rate"] else 0,
occupancyRate=item["occupancy_rate"]
if item["occupancy_rate"]
else 0,
overbooking=item["overbooking"] if item["overbooking"] else False,
)
)

View File

@@ -1,9 +1,10 @@
from odoo.addons.component.core import Component
from odoo.addons.base_rest import restapi
from odoo.addons.base_rest_datamodel.restapi import Datamodel
from odoo import fields
from datetime import datetime
from odoo import fields
from odoo.addons.base_rest import restapi
from odoo.addons.base_rest_datamodel.restapi import Datamodel
from odoo.addons.component.core import Component
class PmsDashboardServices(Component):
@@ -30,17 +31,20 @@ class PmsDashboardServices(Component):
dateTo = fields.Date.from_string(pms_dashboard_search_param.dateTo)
self.env.cr.execute(
f"""
"""
SELECT
d.date,
SUM(CASE WHEN r.checkin = d.date AND r.state IN ('confirm', 'arrival_delayed') THEN 1 ELSE 0
SUM(CASE WHEN r.checkin = d.date AND r.state IN ('confirm', 'arrival_delayed')
THEN 1 ELSE 0
END) AS reservations_pending_arrival,
SUM(CASE WHEN r.checkin = d.date AND r.state = 'onboard' THEN 1 ELSE 0
END) AS
reservations_on_board,
SUM(CASE WHEN r.checkout = d.date AND r.state IN ('onboard', 'departure_delayed') THEN 1 ELSE 0
SUM(CASE WHEN r.checkout = d.date AND r.state IN ('onboard', 'departure_delayed')
THEN 1 ELSE 0
END) AS reservations_pending_departure,
SUM(CASE WHEN r.checkout = d.date AND r.state = 'done' THEN 1 ELSE 0 END) AS reservations_completed
SUM(CASE WHEN r.checkout = d.date AND r.state = 'done' THEN 1 ELSE 0 END)
AS reservations_completed
FROM ( SELECT CURRENT_DATE + date AS date
FROM generate_series(date %s - CURRENT_DATE, date %s - CURRENT_DATE) date) d
LEFT JOIN pms_reservation r
@@ -57,19 +61,30 @@ class PmsDashboardServices(Component):
),
)
result = self.env.cr.dictfetchall()
pending_reservations = []
DashboardPendingReservations = self.env.datamodels["pms.dashboard.pending.reservations"]
DashboardPendingReservations = self.env.datamodels[
"pms.dashboard.pending.reservations"
]
for item in result:
pending_reservations.append(
DashboardPendingReservations(
date=datetime.combine(item['date'], datetime.min.time()).isoformat(),
pendingArrivalReservations=item["reservations_pending_arrival"] if item["reservations_pending_arrival"] else 0,
completedArrivalReservations=item["reservations_on_board"] if item["reservations_on_board"] else 0,
pendingDepartureReservations=item["reservations_pending_departure"] if item["reservations_pending_departure"] else 0,
completedDepartureReservations=item["reservations_completed"] if item["reservations_completed"] else 0,
date=datetime.combine(
item["date"], datetime.min.time()
).isoformat(),
pendingArrivalReservations=item["reservations_pending_arrival"]
if item["reservations_pending_arrival"]
else 0,
completedArrivalReservations=item["reservations_on_board"]
if item["reservations_on_board"]
else 0,
pendingDepartureReservations=item["reservations_pending_departure"]
if item["reservations_pending_departure"]
else 0,
completedDepartureReservations=item["reservations_completed"]
if item["reservations_completed"]
else 0,
)
)
return pending_reservations
@@ -91,7 +106,7 @@ class PmsDashboardServices(Component):
date_occupancy = fields.Date.from_string(pms_dashboard_search_param.date)
self.env.cr.execute(
f"""
"""
SELECT CEIL(l.num * 100.00 / tr.num_total_rooms) AS occupancy
FROM
(
@@ -124,7 +139,8 @@ class PmsDashboardServices(Component):
value=result[0]["occupancy"] if result[0]["occupancy"] else 0,
)
@restapi.method([
@restapi.method(
[
(
[
"/state-rooms",
@@ -140,7 +156,7 @@ class PmsDashboardServices(Component):
dateFrom = fields.Date.from_string(pms_dashboard_search_param.dateFrom)
dateTo = fields.Date.from_string(pms_dashboard_search_param.dateTo)
self.env.cr.execute(
f"""
"""
SELECT d.date,
COALESCE(rln.num_occupied_rooms, 0) AS num_occupied_rooms,
COALESCE( rlo.num_out_of_service_rooms, 0) AS num_out_of_service_rooms,
@@ -193,22 +209,29 @@ class PmsDashboardServices(Component):
for item in result:
state_rooms_result.append(
DashboardStateRooms(
date=datetime.combine(item['date'], datetime.min.time()).isoformat(),
numOccupiedRooms=item["num_occupied_rooms"] if item["num_occupied_rooms"] else 0,
numOutOfServiceRooms=item["num_out_of_service_rooms"] if item["num_out_of_service_rooms"] else 0,
date=datetime.combine(
item["date"], datetime.min.time()
).isoformat(),
numOccupiedRooms=item["num_occupied_rooms"]
if item["num_occupied_rooms"]
else 0,
numOutOfServiceRooms=item["num_out_of_service_rooms"]
if item["num_out_of_service_rooms"]
else 0,
numFreeRooms=item["free_rooms"] if item["free_rooms"] else 0,
)
)
return state_rooms_result
@restapi.method([
(
[
"/reservations-by-sale-channel",
],
"GET",
)
],
@restapi.method(
[
(
[
"/reservations-by-sale-channel",
],
"GET",
)
],
input_param=Datamodel("pms.dashboard.range.dates.search.param"),
output_param=Datamodel("pms.dashboard.state.rooms", is_list=True),
auth="jwt_api_pms",
@@ -217,11 +240,12 @@ class PmsDashboardServices(Component):
dateFrom = fields.Date.from_string(pms_dashboard_search_param.dateFrom)
dateTo = fields.Date.from_string(pms_dashboard_search_param.dateTo)
self.env.cr.execute(
f"""
"""
SELECT CASE WHEN sc.channel_type = 'direct' THEN sc.name
ELSE (SELECT name FROM res_partner WHERE id = r.agency_id)
END AS sale_channel_name,
CEIL(COUNT(r.id) * 100.00 / tr.num_total_reservations) AS percentage_by_sale_channel
CEIL(COUNT(r.id) * 100.00 / tr.num_total_reservations)
AS percentage_by_sale_channel
FROM
(
SELECT COUNT(1) num_total_reservations
@@ -235,7 +259,11 @@ class PmsDashboardServices(Component):
WHERE r.create_date::date BETWEEN %s AND %s
AND r.reservation_type != 'out'
AND r.pms_property_id = %s
GROUP BY r.sale_channel_origin_id, sc.channel_type, sc.name, r.agency_id, tr.num_total_reservations
GROUP BY
r.sale_channel_origin_id,
sc.channel_type, sc.name,
r.agency_id,
tr.num_total_reservations
ORDER BY percentage_by_sale_channel DESC;
""",
(
@@ -250,12 +278,20 @@ class PmsDashboardServices(Component):
result = self.env.cr.dictfetchall()
state_rooms_result = []
DashboardReservationsBySaleChannel = self.env.datamodels["pms.dashboard.reservations.by.sale.channel"]
DashboardReservationsBySaleChannel = self.env.datamodels[
"pms.dashboard.reservations.by.sale.channel"
]
for item in result:
state_rooms_result.append(
DashboardReservationsBySaleChannel(
saleChannelName=item["sale_channel_name"] if item["sale_channel_name"] else '',
percentageReservationsSoldBySaleChannel=item["percentage_by_sale_channel"] if item["percentage_by_sale_channel"] else 0,
saleChannelName=item["sale_channel_name"]
if item["sale_channel_name"]
else "",
percentageReservationsSoldBySaleChannel=item[
"percentage_by_sale_channel"
]
if item["percentage_by_sale_channel"]
else 0,
)
)
return state_rooms_result
@@ -277,7 +313,7 @@ class PmsDashboardServices(Component):
date_billing = fields.Date.from_string(pms_dashboard_search_param.date)
self.env.cr.execute(
f"""
"""
SELECT SUM(l.price_day_total) billing
FROM pms_reservation_line l INNER JOIN pms_reservation r ON l.reservation_id = r.id
WHERE l.date = %s
@@ -295,7 +331,7 @@ class PmsDashboardServices(Component):
result = self.env.cr.dictfetchall()
DashboardNumericResponse = self.env.datamodels["pms.dashboard.numeric.response"]
return DashboardNumericResponse(
value=result[0]["billing"] if result[0]['billing'] else 0,
value=result[0]["billing"] if result[0]["billing"] else 0,
)
@restapi.method(
@@ -315,7 +351,9 @@ class PmsDashboardServices(Component):
date_from = fields.Date.from_string(pms_dashboard_search_param.dateFrom)
date_to = fields.Date.from_string(pms_dashboard_search_param.dateTo)
pms_property = self.env["pms.property"].search([("id", "=", pms_dashboard_search_param.pmsPropertyId)])
pms_property = self.env["pms.property"].search(
[("id", "=", pms_dashboard_search_param.pmsPropertyId)]
)
adr = pms_property._get_adr(date_from, date_to)
@@ -342,7 +380,9 @@ class PmsDashboardServices(Component):
date_from = fields.Date.from_string(pms_dashboard_search_param.dateFrom)
date_to = fields.Date.from_string(pms_dashboard_search_param.dateTo)
pms_property = self.env["pms.property"].search([("id", "=", pms_dashboard_search_param.pmsPropertyId)])
pms_property = self.env["pms.property"].search(
[("id", "=", pms_dashboard_search_param.pmsPropertyId)]
)
revpar = pms_property._get_revpar(date_from, date_to)
@@ -369,7 +409,7 @@ class PmsDashboardServices(Component):
date_new_folios = fields.Date.from_string(pms_dashboard_search_param.date)
self.env.cr.execute(
f"""
"""
SELECT COUNT(1) new_folios
FROM pms_folio f
WHERE DATE(f.create_date) = %s
@@ -407,7 +447,7 @@ class PmsDashboardServices(Component):
date = fields.Date.from_string(pms_dashboard_search_param.date)
self.env.cr.execute(
f"""
"""
SELECT COUNT(1) overnights
FROM pms_reservation_line l
INNER JOIN pms_reservation r ON r.id = l.reservation_id
@@ -419,7 +459,6 @@ class PmsDashboardServices(Component):
AND r.reservation_type != 'out'
""",
(
date,
pms_dashboard_search_param.pmsPropertyId,
),
@@ -449,7 +488,7 @@ class PmsDashboardServices(Component):
date = fields.Date.from_string(pms_dashboard_search_param.date)
self.env.cr.execute(
f"""
"""
SELECT COUNT(1) cancelled_overnights
FROM pms_reservation_line l
INNER JOIN pms_reservation r ON r.id = l.reservation_id
@@ -470,7 +509,9 @@ class PmsDashboardServices(Component):
DashboardNumericResponse = self.env.datamodels["pms.dashboard.numeric.response"]
return DashboardNumericResponse(
value=result[0]["cancelled_overnights"] if result[0]["cancelled_overnights"] else 0,
value=result[0]["cancelled_overnights"]
if result[0]["cancelled_overnights"]
else 0,
)
@restapi.method(
@@ -490,7 +531,7 @@ class PmsDashboardServices(Component):
date = fields.Date.from_string(pms_dashboard_search_param.date)
self.env.cr.execute(
f"""
"""
SELECT COUNT(1) overbookings
FROM pms_reservation_line l
WHERE l.date = %s
@@ -498,7 +539,6 @@ class PmsDashboardServices(Component):
AND l.overbooking = true
""",
(
date,
pms_dashboard_search_param.pmsPropertyId,
),
@@ -511,7 +551,8 @@ class PmsDashboardServices(Component):
value=result[0]["overbookings"] if result[0]["overbookings"] else 0,
)
@restapi.method([
@restapi.method(
[
(
[
"/occupied-rooms",
@@ -519,7 +560,6 @@ class PmsDashboardServices(Component):
"GET",
)
],
input_param=Datamodel("pms.dashboard.range.dates.search.param"),
output_param=Datamodel("pms.dashboard.state.rooms", is_list=True),
auth="jwt_api_pms",
@@ -528,7 +568,7 @@ class PmsDashboardServices(Component):
dateFrom = fields.Date.from_string(pms_dashboard_search_param.dateFrom)
dateTo = fields.Date.from_string(pms_dashboard_search_param.dateTo)
self.env.cr.execute(
f"""
"""
SELECT d.date, COALESCE(rln.num_occupied_rooms, 0) AS num_occupied_rooms
FROM
(
@@ -559,20 +599,25 @@ class PmsDashboardServices(Component):
for item in result:
occupied_rooms_result.append(
DashboardStateRooms(
date=datetime.combine(item['date'], datetime.min.time()).isoformat(),
numOccupiedRooms=item["num_occupied_rooms"] if item["num_occupied_rooms"] else 0,
date=datetime.combine(
item["date"], datetime.min.time()
).isoformat(),
numOccupiedRooms=item["num_occupied_rooms"]
if item["num_occupied_rooms"]
else 0,
)
)
return occupied_rooms_result
@restapi.method([
(
[
"/daily-billings",
],
"GET",
)
],
@restapi.method(
[
(
[
"/daily-billings",
],
"GET",
)
],
input_param=Datamodel("pms.dashboard.range.dates.search.param"),
output_param=Datamodel("pms.dashboard.state.rooms", is_list=True),
auth="jwt_api_pms",
@@ -581,12 +626,12 @@ class PmsDashboardServices(Component):
dateFrom = fields.Date.from_string(pms_dashboard_search_param.dateFrom)
dateTo = fields.Date.from_string(pms_dashboard_search_param.dateTo)
self.env.cr.execute(
f"""
"""
SELECT d.date, COALESCE(rln.daily_billing, 0) AS daily_billing
FROM
(
SELECT (CURRENT_DATE + date) date
FROM generate_series(date %s- CURRENT_DATE, date %s - CURRENT_DATE
FROM generate_series(date %s - CURRENT_DATE, date %s - CURRENT_DATE
) date) d
LEFT OUTER JOIN (SELECT sum(l.price_day_total) daily_billing, date
FROM pms_reservation_line l
@@ -612,20 +657,23 @@ class PmsDashboardServices(Component):
for item in result:
result_daily_billings.append(
DashboardStateRooms(
date=datetime.combine(item['date'], datetime.min.time()).isoformat(),
date=datetime.combine(
item["date"], datetime.min.time()
).isoformat(),
billing=item["daily_billing"] if item["daily_billing"] else 0,
)
)
return result_daily_billings
@restapi.method([
(
[
"/last-received-folios",
],
"GET",
),
],
@restapi.method(
[
(
[
"/last-received-folios",
],
"GET",
),
],
input_param=Datamodel("pms.folio.search.param", is_list=False),
output_param=Datamodel("pms.folio.short.info", is_list=True),
auth="jwt_api_pms",
@@ -633,7 +681,7 @@ class PmsDashboardServices(Component):
def get_last_received_folios(self, pms_folio_search_param):
result_folios = []
PmsFolioShortInfo = self.env.datamodels["pms.folio.short.info"]
for folio in self.env['pms.folio'].search(
for folio in self.env["pms.folio"].search(
[
("first_checkin", ">=", datetime.now().date()),
("pms_property_id", "=", pms_folio_search_param.pmsPropertyId),
@@ -642,7 +690,6 @@ class PmsDashboardServices(Component):
offset=pms_folio_search_param.offset,
order="create_date desc",
):
print(folio.id)
result_folios.append(
PmsFolioShortInfo(
id=folio.id,
@@ -674,19 +721,20 @@ class PmsDashboardServices(Component):
)
return result_folios
@restapi.method([
(
[
"/num-last-received-folios",
],
"GET",
),
],
@restapi.method(
[
(
[
"/num-last-received-folios",
],
"GET",
),
],
input_param=Datamodel("pms.folio.search.param", is_list=False),
auth="jwt_api_pms",
)
def get_num_last_received_folios(self, pms_folio_search_param):
return self.env['pms.folio'].search_count(
return self.env["pms.folio"].search_count(
[
("first_checkin", ">=", datetime.now().date()),
("pms_property_id", "=", pms_folio_search_param.pmsPropertyId),

View File

@@ -2,6 +2,8 @@ import base64
import logging
from datetime import datetime, timedelta
import pytz
from odoo import _, fields
from odoo.exceptions import MissingError, ValidationError
from odoo.osv import expression
@@ -10,7 +12,6 @@ from odoo.tools import get_lang
from odoo.addons.base_rest import restapi
from odoo.addons.base_rest_datamodel.restapi import Datamodel
from odoo.addons.component.core import Component
import pytz
from ..pms_api_rest_utils import url_image_pms_api_rest
@@ -133,11 +134,7 @@ class PmsFolioService(Component):
domain_filter = list()
if folio_search_param.last:
domain_filter.append(
[
("checkin", ">=", fields.Date.today())
]
)
domain_filter.append([("checkin", ">=", fields.Date.today())])
if folio_search_param.filter:
target = folio_search_param.filter
@@ -1251,7 +1248,9 @@ class PmsFolioService(Component):
]
for message in messages:
reservation_message_date = pytz.UTC.localize(message.date)
reservation_message_date = reservation_message_date.astimezone(user_tz)
reservation_message_date = reservation_message_date.astimezone(
user_tz
)
message_body = self.parse_message_body(message)
if message.message_type == "email":
subject = "Email enviado: " + message.subject
@@ -1272,7 +1271,9 @@ class PmsFolioService(Component):
).decode("utf-8")
if message.author_id.image_1024
else None,
authorImageUrl=url_image_pms_api_rest('res.partner', message.author_id.id, 'image_1024'),
authorImageUrl=url_image_pms_api_rest(
"res.partner", message.author_id.id, "image_1024"
),
)
)
PmsFolioMessageInfo = self.env.datamodels["pms.folio.message.info"]
@@ -1298,7 +1299,9 @@ class PmsFolioService(Component):
).decode("utf-8")
if folio_message.author_id.image_1024
else None,
authorImageUrl=url_image_pms_api_rest('res.partner', folio_message.author_id.id, 'image_1024'),
authorImageUrl=url_image_pms_api_rest(
"res.partner", folio_message.author_id.id, "image_1024"
),
)
)
PmsMessageInfo = self.env.datamodels["pms.message.info"]

View File

@@ -24,7 +24,11 @@ class PmsIdCategoryService(Component):
def get_id_categories(self):
result_id_categories = []
PmsIdCategoryInfo = self.env.datamodels["pms.id.category.info"]
for id_category in self.env["res.partner.id_category"].with_context(lang=self.env.user.lang).search([]):
for id_category in (
self.env["res.partner.id_category"]
.with_context(lang=self.env.user.lang)
.search([])
):
result_id_categories.append(
PmsIdCategoryInfo(
id=id_category.id,

View File

@@ -9,8 +9,10 @@ from odoo.exceptions import AccessDenied
from odoo.addons.base_rest import restapi
from odoo.addons.base_rest_datamodel.restapi import Datamodel
from odoo.addons.component.core import Component
from ..pms_api_rest_utils import url_image_pms_api_rest
class PmsLoginService(Component):
_inherit = "base.rest.service"
_name = "pms.auth.service"
@@ -81,7 +83,9 @@ class PmsLoginService(Component):
userImageBase64=user_record.partner_id.image_1024
if user_record.partner_id.image_1024
else None,
userImageUrl=url_image_pms_api_rest('res.partner', user_record.partner_id.id, 'image_1024'),
userImageUrl=url_image_pms_api_rest(
"res.partner", user_record.partner_id.id, "image_1024"
),
isNewInterfaceUser=user_record.is_new_interface_app_user,
availabilityRuleFields=avail_rule_names,
)

View File

@@ -1,6 +1,7 @@
import datetime
from odoo import fields
from odoo.addons.base_rest import restapi
from odoo.addons.base_rest_datamodel.restapi import Datamodel
from odoo.addons.component.core import Component

View File

@@ -1,66 +1,68 @@
import re
from datetime import datetime, date, timedelta
from datetime import date, datetime, timedelta
from odoo import _
from odoo.exceptions import ValidationError
from odoo.osv import expression
from odoo.addons.base_rest import restapi
from odoo.addons.base_rest_datamodel.restapi import Datamodel
from odoo.addons.component.core import Component
from odoo.exceptions import ValidationError
from odoo import _
_ref_vat = {
'al': 'J91402501L',
'ar': '200-5536168-2 or 20055361682',
'at': 'U12345675',
'au': '83 914 571 673',
'be': '0477472701',
'bg': '1234567892',
'ch': 'CHE-123.456.788 TVA or CHE-123.456.788 MWST or CHE-123.456.788 IVA',
'cl': '76086428-5',
'co': '213123432-1 or 213.123.432-1',
'cy': '10259033P',
'cz': '12345679',
'de': '123456788',
'dk': '12345674',
'do': '1-01-85004-3 or 101850043',
'ec': '1792060346-001',
'ee': '123456780',
'el': '12345670',
'es': '12345674A',
'fi': '12345671',
'fr': '23334175221',
'gb': '123456782 or 123456782',
'gr': '12345670',
'hu': '12345676',
'hr': '01234567896',
'ie': '1234567FA',
'in': "12AAAAA1234AAZA",
'is': '062199',
'it': '12345670017',
'lt': '123456715',
'lu': '12345613',
'lv': '41234567891',
'mc': '53000004605',
'mt': '12345634',
'mx': 'GODE561231GR8',
'nl': '123456782B90',
'no': '123456785',
'pe': '10XXXXXXXXY or 20XXXXXXXXY or 15XXXXXXXXY or 16XXXXXXXXY or 17XXXXXXXXY',
'ph': '123-456-789-123',
'pl': '1234567883',
'pt': '123456789',
'ro': '1234567897',
'rs': '101134702',
'ru': '123456789047',
'se': '123456789701',
'si': '12345679',
'sk': '2022749619',
'sm': '24165',
'tr': '1234567890 (VERGINO) or 17291716060 (TCKIMLIKNO)',
've': 'V-12345678-1, V123456781, V-12.345.678-1',
'xi': '123456782',
"al": "J91402501L",
"ar": "200-5536168-2 or 20055361682",
"at": "U12345675",
"au": "83 914 571 673",
"be": "0477472701",
"bg": "1234567892",
"ch": "CHE-123.456.788 TVA or CHE-123.456.788 MWST or CHE-123.456.788 IVA",
"cl": "76086428-5",
"co": "213123432-1 or 213.123.432-1",
"cy": "10259033P",
"cz": "12345679",
"de": "123456788",
"dk": "12345674",
"do": "1-01-85004-3 or 101850043",
"ec": "1792060346-001",
"ee": "123456780",
"el": "12345670",
"es": "12345674A",
"fi": "12345671",
"fr": "23334175221",
"gb": "123456782 or 123456782",
"gr": "12345670",
"hu": "12345676",
"hr": "01234567896",
"ie": "1234567FA",
"in": "12AAAAA1234AAZA",
"is": "062199",
"it": "12345670017",
"lt": "123456715",
"lu": "12345613",
"lv": "41234567891",
"mc": "53000004605",
"mt": "12345634",
"mx": "GODE561231GR8",
"nl": "123456782B90",
"no": "123456785",
"pe": "10XXXXXXXXY or 20XXXXXXXXY or 15XXXXXXXXY or 16XXXXXXXXY or 17XXXXXXXXY",
"ph": "123-456-789-123",
"pl": "1234567883",
"pt": "123456789",
"ro": "1234567897",
"rs": "101134702",
"ru": "123456789047",
"se": "123456789701",
"si": "12345679",
"sk": "2022749619",
"sm": "24165",
"tr": "1234567890 (VERGINO) or 17291716060 (TCKIMLIKNO)",
"ve": "V-12345678-1, V123456781, V-12.345.678-1",
"xi": "123456782",
}
class PmsPartnerService(Component):
_inherit = "base.rest.service"
_name = "pms.partner.service"
@@ -83,7 +85,6 @@ class PmsPartnerService(Component):
def get_partners(self, pms_partner_search_params):
result_partners = []
domain = []
print("pms_partner_search_params", pms_partner_search_params)
if pms_partner_search_params.housedNow:
partners_housed_now = (
@@ -99,14 +100,26 @@ class PmsPartnerService(Component):
self.env["pms.checkin.partner"]
.search(
[
'|',
'&', ('checkin', '>=', last_week_day), ('checkin', '<=', today),
'|', ('checkout', '>=', last_week_day), ('checkout', '<=', today),
'|', '&', ('checkin', '<=', last_week_day), ('checkout', '<', today),
'&', ('checkin', '>=', last_week_day), ('checkout', '>', today),
'|', ('checkin', '<', last_week_day), ('checkout', '>', today),
"|",
"&",
("checkin", ">=", last_week_day),
("checkin", "<=", today),
"|",
("checkout", ">=", last_week_day),
("checkout", "<=", today),
"|",
"&",
("checkin", "<=", last_week_day),
("checkout", "<", today),
"&",
("checkin", ">=", last_week_day),
("checkout", ">", today),
"|",
("checkin", "<", last_week_day),
("checkout", ">", today),
]
).mapped("partner_id")
)
.mapped("partner_id")
)
domain.append(("id", "in", partners_housed_last_week.ids))
if pms_partner_search_params.housedLastMonth:
@@ -116,14 +129,26 @@ class PmsPartnerService(Component):
self.env["pms.checkin.partner"]
.search(
[
'|',
'&', ('checkin', '>=', last_month_day), ('checkin', '<=', today),
'|', ('checkout', '>=', last_month_day), ('checkout', '<=', today),
'|', '&', ('checkin', '<=', last_month_day), ('checkout', '<', today),
'&', ('checkin', '>=', last_month_day), ('checkout', '>', today),
'|', ('checkin', '<', last_month_day), ('checkout', '>', today),
"|",
"&",
("checkin", ">=", last_month_day),
("checkin", "<=", today),
"|",
("checkout", ">=", last_month_day),
("checkout", "<=", today),
"|",
"&",
("checkin", "<=", last_month_day),
("checkout", "<", today),
"&",
("checkin", ">=", last_month_day),
("checkout", ">", today),
"|",
("checkin", "<", last_month_day),
("checkout", ">", today),
]
).mapped("partner_id")
)
.mapped("partner_id")
)
domain.append(("id", "in", partners_housed_last_month.ids))
if (
@@ -325,7 +350,9 @@ class PmsPartnerService(Component):
name=payment.name if payment.name else None,
amount=payment.amount,
journalId=payment.journal_id.id if payment.journal_id else None,
destinationJournalId=destination_journal_id if destination_journal_id else None,
destinationJournalId=destination_journal_id
if destination_journal_id
else None,
date=datetime.combine(
payment.date, datetime.min.time()
).isoformat(),
@@ -373,18 +400,14 @@ class PmsPartnerService(Component):
PmsInvoiceLineInfo(
id=move_line.id,
name=move_line.name if move_line.name else None,
quantity=move_line.quantity
if move_line.quantity
else None,
quantity=move_line.quantity if move_line.quantity else None,
priceUnit=move_line.price_unit
if move_line.price_unit
else None,
total=move_line.price_total
if move_line.price_total
else None,
discount=move_line.discount
if move_line.discount
else None,
discount=move_line.discount if move_line.discount else None,
displayType=move_line.display_type
if move_line.display_type
else None,
@@ -420,15 +443,11 @@ class PmsPartnerService(Component):
else None,
date=invoice_date,
state=move.state if move.state else None,
paymentState=move.payment_state
if move.payment_state
else None,
paymentState=move.payment_state if move.payment_state else None,
partnerName=move.partner_id.name
if move.partner_id.name
else None,
partnerId=move.partner_id.id
if move.partner_id.id
else None,
partnerId=move.partner_id.id if move.partner_id.id else None,
moveLines=move_lines if move_lines else None,
portalUrl=portal_url,
moveType=move.move_type,
@@ -467,7 +486,6 @@ class PmsPartnerService(Component):
lambda doc: doc.category_id.id == doc_type.id
)
PmsCheckinPartnerInfo = self.env.datamodels["pms.checkin.partner.info"]
document_expedition_date = False
@@ -475,9 +493,7 @@ class PmsPartnerService(Component):
document_expedition_date = doc_number.valid_from.strftime("%d/%m/%Y")
birthdate_date = False
if partner.birthdate_date:
birthdate_date = partner.birthdate_date.strftime(
"%d/%m/%Y"
)
birthdate_date = partner.birthdate_date.strftime("%d/%m/%Y")
partners.append(
PmsCheckinPartnerInfo(
partnerId=partner.id or None,
@@ -507,7 +523,8 @@ class PmsPartnerService(Component):
[
(
[
"/check-doc-number/<string:document_number>/<int:document_type_id>/<int:country_id>",
"/check-doc-number/<string:document_number>/"
"<int:document_type_id>/<int:country_id>",
],
"GET",
)
@@ -517,8 +534,8 @@ class PmsPartnerService(Component):
# REVIEW: create a new datamodel and service for documents?
def check_document_number(self, document_number, document_type_id, country_id):
error_mens = False
country = self.env['res.country'].browse(country_id)
document_type = self.env['res.partner.id_category'].browse(document_type_id)
country = self.env["res.country"].browse(country_id)
document_type = self.env["res.partner.id_category"].browse(document_type_id)
id_number = self.env["res.partner.id_number"].new(
{
"name": document_number,
@@ -536,7 +553,9 @@ class PmsPartnerService(Component):
vat_number=document_number,
)
if error:
error_mens = self._construct_check_vat_error_msg(vat_number=document_number, country_code=country.code)
error_mens = self._construct_check_vat_error_msg(
vat_number=document_number, country_code=country.code
)
if error_mens:
raise ValidationError(error_mens)
@@ -742,18 +761,20 @@ class PmsPartnerService(Component):
country_code = country_code.lower()
vat_no = "(##=VAT Number)"
vat_no = _ref_vat.get(country_code) or vat_no
if self.env.context.get('company_id'):
company = self.env['res.company'].browse(self.env.context['company_id'])
if self.env.context.get("company_id"):
company = self.env["res.company"].browse(self.env.context["company_id"])
else:
company = self.env.company
if company.vat_check_vies:
return '\n' + _(
'The VAT number [%(vat)s] either failed the VIES VAT validation check or did not respect the expected format %(format)s.',
return "\n" + _(
"The VAT number [%(vat)s] either failed the VIES VAT "
"validation check or did not respect the expected format %(format)s.",
vat=vat_number,
format=vat_no
format=vat_no,
)
return '\n' + _(
'The VAT number [%(vat)s] does not seem to be valid. \nNote: the expected format is %(format)s',
return "\n" + _(
"The VAT number [%(vat)s] does not seem to be valid. "
"\nNote: the expected format is %(format)s",
vat=vat_number,
format=vat_no
format=vat_no,
)

View File

@@ -49,11 +49,7 @@ class PmsPriceService(Component):
[("id", "=", prices_search_param.boardServiceId)]
)
else:
raise MissingError(
_(
"Wrong input param"
)
)
raise MissingError(_("Wrong input param"))
PmsPriceInfo = self.env.datamodels["pms.price.info"]
result_prices = []
@@ -154,7 +150,7 @@ class PmsPriceService(Component):
):
price = 0
if product_id:
products = self.env['product.product'].browse(product_id)
products = self.env["product.product"].browse(product_id)
else:
products = board_service.board_service_line_ids.mapped("product_id")
for product in products:

View File

@@ -32,7 +32,7 @@ class PmsPricelistService(Component):
("is_pms_available", "=", True),
]
if pms_search_param.daily and pms_search_param.daily is True:
domain.append(("pricelist_type", "=", 'daily'))
domain.append(("pricelist_type", "=", "daily"))
pricelists = self.env["product.pricelist"].search(domain)
if pms_search_param.pmsPropertyIds and pms_search_param.pmsPropertyId:
@@ -192,7 +192,7 @@ class PmsPricelistService(Component):
input_param=Datamodel("pms.pricelist.items.info", is_list=False),
auth="jwt_api_pms",
)
def create_pricelist_item(self, pricelist_id, pms_pricelist_item_info):
def create_pricelist_item_old(self, pricelist_id, pms_pricelist_item_info):
self._create_or_update_pricelist_items(pms_pricelist_item_info)
@restapi.method(
@@ -207,10 +207,14 @@ class PmsPricelistService(Component):
input_param=Datamodel("pms.pricelist.items.info", is_list=False),
auth="jwt_api_pms",
)
def create_pricelist_item(self, pricelist_id, pms_pricelist_item_info):
pricelist_ids = list({item.pricelistId for item in pms_pricelist_item_info.pricelistItems})
def create_pricelist_item_fix_patch(self, pricelist_id, pms_pricelist_item_info):
pricelist_ids = list(
{item.pricelistId for item in pms_pricelist_item_info.pricelistItems}
)
if len(pricelist_ids) > 1 or pricelist_ids[0] != pricelist_id:
raise ValidationError("You cannot create pricelist items for different pricelists at once.")
raise ValidationError(
_("You cannot create pricelist items for different pricelists at once.")
)
else:
self._create_or_update_pricelist_items(pms_pricelist_item_info)

View File

@@ -1,6 +1,7 @@
from odoo.addons.base_rest import restapi
from odoo.addons.base_rest_datamodel.restapi import Datamodel
from odoo.addons.component.core import Component
from ..pms_api_rest_utils import url_image_pms_api_rest
@@ -31,7 +32,11 @@ class PmsPropertyService(Component):
):
state_name = False
if prop.state_id:
state_name = self.env['res.country.state'].search([('id', '=', prop.state_id.id)]).name
state_name = (
self.env["res.country.state"]
.search([("id", "=", prop.state_id.id)])
.name
)
result_properties.append(
PmsPropertyInfo(
id=prop.id,
@@ -53,7 +58,9 @@ class PmsPropertyService(Component):
simpleInColor=prop.simple_in_color,
simpleFutureColor=prop.simple_future_color,
language=prop.lang,
hotelImageUrl=url_image_pms_api_rest('pms.property', prop.id, 'hotel_image_pms_api_rest'),
hotelImageUrl=url_image_pms_api_rest(
"pms.property", prop.id, "hotel_image_pms_api_rest"
),
)
)
return result_properties

View File

@@ -127,11 +127,15 @@ class PmsReservationService(Component):
numServices=len(reservation.service_ids)
if reservation.service_ids
else 0,
isReselling=any(line.is_reselling for line in reservation.reservation_line_ids),
)
isReselling=any(
line.is_reselling for line in reservation.reservation_line_ids
),
)
return res
def _create_vals_from_params(self, reservation_vals, reservation_data, reservation_id):
def _create_vals_from_params(
self, reservation_vals, reservation_data, reservation_id
):
if reservation_data.preferredRoomId:
reservation_vals.update(
{"preferred_room_id": reservation_data.preferredRoomId}
@@ -158,7 +162,6 @@ class PmsReservationService(Component):
if reservation_data.checkout:
reservation_vals.update({"checkout": reservation_data.checkout})
return reservation_vals
@restapi.method(
@@ -231,8 +234,13 @@ class PmsReservationService(Component):
)
service_cmds = []
if reservation_data.boardServiceId is not None or reservation_data.boardServices is not None:
for service in reservation.service_ids.filtered(lambda x: x.is_board_service):
if (
reservation_data.boardServiceId is not None
or reservation_data.boardServices is not None
):
for service in reservation.service_ids.filtered(
lambda x: x.is_board_service
):
service_cmds.append((2, service.id))
if reservation_data.boardServices is not None:
@@ -261,18 +269,19 @@ class PmsReservationService(Component):
"is_board_service": True,
"reservation_id": reservation_id,
"service_line_ids": service_line_cmds,
}
},
)
)
if service_cmds:
reservation_vals.update({"service_ids": service_cmds})
if reservation_vals:
if reservation_data.boardServices:
reservation.with_context(skip_compute_service_ids=True).write(reservation_vals)
else:
reservation.write(reservation_vals)
# print(reservation.service_ids.mapped("name"))
# if service_cmds:
# reservation_vals.update({"service_ids": service_cmds})
# if reservation_vals:
# if reservation_data.boardServices:
# reservation.with_context(skip_compute_service_ids=True).write(
# reservation_vals
# )
# else:
# reservation.write(reservation_vals)
# # print(reservation.service_ids.mapped("name"))
def _get_reservation_lines_mapped(self, origin_data, reservation_line=False):
# Return dict witch reservation.lines values (only modified if line exist,
@@ -542,7 +551,7 @@ class PmsReservationService(Component):
pass
else:
# TODO Review state draft
#.filtered(
# .filtered(
# lambda ch: ch.state != "dummy"
# )
for checkin_partner in reservation.checkin_partner_ids:

View File

@@ -97,8 +97,13 @@ class PmsRoomService(Component):
roomAmenityIds=room.room_amenity_ids.ids
if room.room_amenity_ids
else None,
roomAmenityInName=room.room_amenity_ids.filtered(lambda x: x.is_add_code_room_name).default_code if
room.room_amenity_ids.filtered(lambda x: x.is_add_code_room_name).name else ''
roomAmenityInName=room.room_amenity_ids.filtered(
lambda x: x.is_add_code_room_name
).default_code
if room.room_amenity_ids.filtered(
lambda x: x.is_add_code_room_name
).name
else "",
)
)
return result_rooms

View File

@@ -1,8 +1,10 @@
from odoo.addons.base_rest import restapi
from odoo.addons.base_rest_datamodel.restapi import Datamodel
from odoo.addons.component.core import Component
from ..pms_api_rest_utils import url_image_pms_api_rest
class PmsRoomTypeClassService(Component):
_inherit = "base.rest.service"
_name = "pms.room.type.class.service"
@@ -51,7 +53,9 @@ class PmsRoomTypeClassService(Component):
name=room.name,
defaultCode=room.default_code if room.default_code else None,
pmsPropertyIds=room.pms_property_ids.mapped("id"),
imageUrl=url_image_pms_api_rest('pms.room.type.class', room.id, 'icon_pms_api_rest'),
imageUrl=url_image_pms_api_rest(
"pms.room.type.class", room.id, "icon_pms_api_rest"
),
)
)
return result_room_type_class

View File

@@ -4,8 +4,10 @@ from odoo.exceptions import MissingError
from odoo.addons.base_rest import restapi
from odoo.addons.base_rest_datamodel.restapi import Datamodel
from odoo.addons.component.core import Component
from ..pms_api_rest_utils import url_image_pms_api_rest
class PmsSaleChannelService(Component):
_inherit = "base.rest.service"
_name = "pms.sale.channel.service"
@@ -62,7 +64,9 @@ class PmsSaleChannelService(Component):
channelType=sale_channel.channel_type
if sale_channel.channel_type
else None,
iconUrl=url_image_pms_api_rest('pms.sale.channel', sale_channel.id, 'icon'),
iconUrl=url_image_pms_api_rest(
"pms.sale.channel", sale_channel.id, "icon"
),
)
)
return result_sale_channels

View File

@@ -85,11 +85,15 @@ class PmsTransactionService(Component):
type_domain = []
for transaction_type in transaction_types:
payment_type, partner_type = self._get_mapper_transaction_type(transaction_type)
type_domain.append([
["partner_type", "=", partner_type],
["payment_type", "=", payment_type],
])
payment_type, partner_type = self._get_mapper_transaction_type(
transaction_type
)
type_domain.append(
[
["partner_type", "=", partner_type],
["payment_type", "=", payment_type],
]
)
if type_domain:
type_domain = expression.OR(type_domain)

View File

@@ -9,7 +9,6 @@ class ResCityZipService(Component):
_usage = "zips"
_collection = "pms.services"
@restapi.method(
[
(
@@ -28,7 +27,9 @@ class ResCityZipService(Component):
if not zip_search_param.address:
return result_res_zip
ResCityZipInfo = self.env.datamodels["res.city.zip.info"]
res_zip = self.env["res.city.zip"].search([("display_name", "ilike", zip_search_param.address)], limit=10)
res_zip = self.env["res.city.zip"].search(
[("display_name", "ilike", zip_search_param.address)], limit=10
)
if res_zip:
for address in res_zip:
@@ -44,7 +45,6 @@ class ResCityZipService(Component):
)
return result_res_zip
@restapi.method(
[
(

View File

@@ -24,7 +24,9 @@ class ResCountryService(Component):
def get_countries(self):
result_countries = []
ResCountriesInfo = self.env.datamodels["res.country.info"]
for country in self.env["res.country"].with_context(lang=self.env.user.lang).search([]):
for country in (
self.env["res.country"].with_context(lang=self.env.user.lang).search([])
):
result_countries.append(
ResCountriesInfo(
id=country.id,

View File

@@ -24,7 +24,11 @@ class PmsPartnerCategoriesService(Component):
def get_categories(self):
result_categories = []
ResPartnerCategoryInfo = self.env.datamodels["res.partner.category.info"]
for category in self.env["res.partner.category"].with_context(lang=self.env.user.lang).search([]):
for category in (
self.env["res.partner.category"]
.with_context(lang=self.env.user.lang)
.search([])
):
result_categories.append(
ResPartnerCategoryInfo(
id=category.id,

View File

@@ -4,9 +4,16 @@
<field name="model">pms.property</field>
<field name="inherit_id" ref="pms.pms_property_views_form" />
<field name="arch" type="xml">
<xpath expr="//page[@name='property_general']//field[@name='street']" position="before">
<xpath
expr="//page[@name='property_general']//field[@name='street']"
position="before"
>
<group>
<field name="hotel_image_pms_api_rest" widget="image" class="oe_avatar"/>
<field
name="hotel_image_pms_api_rest"
widget="image"
class="oe_avatar"
/>
</group>
</xpath>
<xpath expr="//field[@name='default_departure_hour']" position="after">

View File

@@ -5,7 +5,7 @@
<field name="inherit_id" ref="pms.pms_room_type_class_view_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='overnight']" position="after">
<field name="icon_pms_api_rest" widget="image" class="oe_avatar"/>
<field name="icon_pms_api_rest" widget="image" class="oe_avatar" />
</xpath>
</field>
</record>