mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[FIX]14.0-pms_api_rest: fix pre-commit
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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}" <${(object.company_id.email or user.email) | safe}></field>
|
||||
<field
|
||||
name="email_from"
|
||||
>"${object.company_id.name | safe}" <${(object.company_id.email or user.email) | safe}></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>
|
||||
|
||||
@@ -62,4 +62,3 @@ from . import pms_reservation_message
|
||||
from . import pms_avail
|
||||
from . import pms_dashboard
|
||||
from . import feed_post
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
[
|
||||
(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user