mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
@@ -14,6 +14,7 @@
|
||||
"installable": True,
|
||||
"depends": [
|
||||
"base",
|
||||
"base_automation",
|
||||
"mail",
|
||||
# "account_payment_return",
|
||||
# "email_template_qweb",
|
||||
@@ -32,6 +33,9 @@
|
||||
"security/ir.model.access.csv",
|
||||
"data/cron_jobs.xml",
|
||||
"data/pms_sequence.xml",
|
||||
"data/pms_confirmed_reservation_email_template.xml",
|
||||
"data/pms_modified_reservation_email_template.xml",
|
||||
"data/pms_cancelled_reservation_email_template.xml",
|
||||
"data/pms_data.xml",
|
||||
"data/traveller_report_paperformat.xml",
|
||||
"report/pms_folio.xml",
|
||||
@@ -77,6 +81,7 @@
|
||||
"views/res_company_views.xml",
|
||||
"views/traveller_report_template.xml",
|
||||
"wizards/wizard_split_join_swap_reservation.xml",
|
||||
"views/pms_automated_mails_views.xml",
|
||||
"wizards/wizard_massive_changes.xml",
|
||||
"wizards/wizard_advanced_filters.xml",
|
||||
],
|
||||
|
||||
160
pms/data/pms_cancelled_reservation_email_template.xml
Normal file
160
pms/data/pms_cancelled_reservation_email_template.xml
Normal file
@@ -0,0 +1,160 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="cancelled_reservation_email" model="mail.template">
|
||||
<field name="name">Cancelled Reservation</field>
|
||||
<field name="model_id" ref="pms.model_pms_reservation" />
|
||||
<field
|
||||
name="subject"
|
||||
>Your reservation in ${object.pms_property_id.name} has been cancelled</field>
|
||||
<field
|
||||
name="email_from"
|
||||
>${object.pms_property_id.partner_id.email | safe}</field>
|
||||
<field
|
||||
name="email_to"
|
||||
>${(object.email and '"%s" <%s>' % (object.name, object.email) or object.partner_id.email_formatted or '') | safe}</field>
|
||||
<field name="body_html" type="html">
|
||||
<table
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="padding-top: 16px; background-color: #F1F1F1; 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="padding: 16px; background-color: white; color: #454748; border-collapse:separate;"
|
||||
>
|
||||
<tbody>
|
||||
<!-- HEADER -->
|
||||
<!-- PROPERTY DESCRIPTION -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 0px 0px 0px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td align="right">
|
||||
<div class="col-sm-4">
|
||||
% if object.pms_property_id.partner_id.street
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street}</p>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.street2
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street2}</p>
|
||||
% endif
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.zip}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.city}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.country_id.name}</p>
|
||||
</div>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div>
|
||||
Hello ${object.partner_id.name or ''},<br
|
||||
/>
|
||||
Your reservation at ${object.pms_property_id.name} has been successfully canceled.
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- DETAILS -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<!-- CONTACT -->
|
||||
<div>
|
||||
<div
|
||||
>If you have questions please contact with us:</div>
|
||||
<ul>
|
||||
<li
|
||||
>${object.pms_property_id.name}</li>
|
||||
% if object.pms_property_id.partner_id.email
|
||||
<li>Mail: <a
|
||||
href="mailto:${object.pms_property_id.partner_id.email}"
|
||||
style="text-decoration:none;color:#875A7B;"
|
||||
>${object.pms_property_id.partner_id.email}</a></li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.phone
|
||||
<li
|
||||
>Phone: ${object.pms_property_id.partner_id.phone}</li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.mobile
|
||||
<li
|
||||
>Mobile: ${object.pms_property_id.partner_id.mobile}</li>
|
||||
% endif
|
||||
</ul>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td></tr>
|
||||
<!-- FOOTER -->
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.pms_property_id.privacy_policy
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="font-size: 10px;">
|
||||
${object.pms_property_id.privacy_policy}
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.company_id
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="text-align: center; font-size: 10px;">
|
||||
Sent by <a
|
||||
target="_blank"
|
||||
href="${object.company_id.website}"
|
||||
style="color: #875A7B;"
|
||||
>${object.company_id.name}</a>
|
||||
<br />
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
</table>
|
||||
</field>
|
||||
<field name="lang">${object.partner_id.lang}</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
260
pms/data/pms_confirmed_reservation_email_template.xml
Normal file
260
pms/data/pms_confirmed_reservation_email_template.xml
Normal file
@@ -0,0 +1,260 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="confirmed_reservation_email" model="mail.template">
|
||||
<field name="name">Confirmed Reservation</field>
|
||||
<field name="model_id" ref="pms.model_pms_reservation" />
|
||||
<field
|
||||
name="subject"
|
||||
>${object.company_id.name} has confirmed your reservation in ${object.pms_property_id.name}</field>
|
||||
<field
|
||||
name="email_from"
|
||||
>${object.pms_property_id.partner_id.email | safe}</field>
|
||||
<field
|
||||
name="email_to"
|
||||
>${(object.email and '"%s" <%s>' % (object.name, object.email) or object.partner_id.email_formatted or '') | safe}</field>
|
||||
<field name="body_html" type="html">
|
||||
<table
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="padding-top: 16px; background-color: #F1F1F1; 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="padding: 16px; background-color: white; color: #454748; border-collapse:separate;"
|
||||
>
|
||||
<head>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"
|
||||
integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
</head>
|
||||
<tbody>
|
||||
<!-- PROPERTY DESCRIPTION -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 0px 0px 0px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td align="right">
|
||||
<div class="col-sm-4">
|
||||
% if object.pms_property_id.partner_id.street
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street}</p>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.street2
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street2}</p>
|
||||
% endif
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.zip}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.city}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.country_id.name}</p>
|
||||
</div>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div>
|
||||
Hello ${object.partner_id.name or ''},<br
|
||||
/>
|
||||
We are happy to confirm your reservation in ${object.pms_property_id.name}
|
||||
</div>
|
||||
<div>
|
||||
See you soon,<br />
|
||||
<span style="color: #454748;">
|
||||
<br />
|
||||
${object.company_id.name}
|
||||
</span>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- DETAILS -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div
|
||||
align="left"
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
><strong>Reservation Details</strong></div>
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<table style="width:50%;">
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
class="far fa-calendar-alt fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px; font-size: 14px;"
|
||||
>
|
||||
<div><strong
|
||||
>From</strong> ${object.checkin} <strong
|
||||
>At</strong> ${object.arrival_hour}</div>
|
||||
<div><strong
|
||||
>To</strong> ${object.checkout} <strong
|
||||
>At</strong> ${object.departure_hour}</div>
|
||||
<div
|
||||
style="font-size:12px;color:#9e9e9e"
|
||||
><i><strong
|
||||
>TZ</strong> ${object.pms_property_id.tz}</i></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
>
|
||||
<br />
|
||||
<div
|
||||
class="fas fa-bed fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td style="vertical-align:top;">
|
||||
<br />
|
||||
<div><strong
|
||||
>Room: </strong> ${object.room_type_id.name}</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
>
|
||||
<br />
|
||||
<div
|
||||
class="fas fa-coins fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px; font-size: 14px;"
|
||||
>
|
||||
<br />
|
||||
<div><strong
|
||||
>Price: </strong> ${object.price_room_services_set} ${object.pms_property_id.country_id.currency_id.symbol}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<div>
|
||||
% if object.pms_property_id.mail_information
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div
|
||||
align="left"
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
><strong
|
||||
>Additional Information</strong></div>
|
||||
${object.pms_property_id.mail_information|safe}
|
||||
% endif
|
||||
</div>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<!-- CONTACT -->
|
||||
<div>
|
||||
<span
|
||||
style="font-weight:300;margin:10px 0px"
|
||||
>Questions about the reservation?</span>
|
||||
<div>Please contact with us:</div>
|
||||
<ul>
|
||||
<li
|
||||
>${object.pms_property_id.name}</li>
|
||||
% if object.pms_property_id.partner_id.email
|
||||
<li>Mail: <a
|
||||
href="mailto:${object.pms_property_id.partner_id.email}"
|
||||
style="text-decoration:none;color:#875A7B;"
|
||||
>${object.pms_property_id.partner_id.email}</a></li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.phone
|
||||
<li
|
||||
>Phone: ${object.pms_property_id.partner_id.phone}</li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.mobile
|
||||
<li
|
||||
>Mobile: ${object.pms_property_id.partner_id.mobile}</li>
|
||||
% endif
|
||||
</ul>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td></tr>
|
||||
<!-- FOOTER -->
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.pms_property_id.privacy_policy
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="font-size: 10px;">
|
||||
${object.pms_property_id.privacy_policy|safe}
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.company_id
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="text-align: center; font-size: 10px;">
|
||||
Sent by <a
|
||||
target="_blank"
|
||||
href="${object.company_id.website}"
|
||||
style="color: #875A7B;"
|
||||
>${object.company_id.name}</a>
|
||||
<br />
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
</table>
|
||||
</field>
|
||||
<field name="lang">${object.partner_id.lang}</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -135,7 +135,40 @@ if (permit_first_letter.upper() in ['X','Y']) and id_number.name[1:8].isdigit()
|
||||
else:
|
||||
failed = True
|
||||
</field>
|
||||
<!-- <field name="has_unique_numbers">True</field>-->
|
||||
</record>
|
||||
<!-- pms.automated_mails-->
|
||||
<record id="pms_auto_mail_confirm" model="pms.automated.mails">
|
||||
<field name="name">Confirmed Reservation</field>
|
||||
<field name="active">False</field>
|
||||
<field name="template_id" ref="pms.confirmed_reservation_email" />
|
||||
<field name="action">creation</field>
|
||||
<field
|
||||
name="pms_property_ids"
|
||||
eval="[(6, False, [ref('main_pms_property')])]"
|
||||
/>
|
||||
<field name="moment">in_act</field>
|
||||
</record>
|
||||
<record id="pms_auto_mail_write" model="pms.automated.mails">
|
||||
<field name="name">Modified Reservation</field>
|
||||
<field name="active">False</field>
|
||||
<field name="template_id" ref="pms.modified_reservation_email" />
|
||||
<field name="action">write</field>
|
||||
<field
|
||||
name="pms_property_ids"
|
||||
eval="[(6, False, [ref('main_pms_property')])]"
|
||||
/>
|
||||
<field name="moment">in_act</field>
|
||||
</record>
|
||||
<record id="pms_auto_mail_cancel" model="pms.automated.mails">
|
||||
<field name="name">Cancelled Reservation</field>
|
||||
<field name="active">False</field>
|
||||
<field name="template_id" ref="pms.cancelled_reservation_email" />
|
||||
<field name="action">cancel</field>
|
||||
<field
|
||||
name="pms_property_ids"
|
||||
eval="[(6, False, [ref('main_pms_property')])]"
|
||||
/>
|
||||
<field name="moment">in_act</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
262
pms/data/pms_modified_reservation_email_template.xml
Normal file
262
pms/data/pms_modified_reservation_email_template.xml
Normal file
@@ -0,0 +1,262 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="modified_reservation_email" model="mail.template">
|
||||
<field name="name">Modified Reservation</field>
|
||||
<field name="model_id" ref="pms.model_pms_reservation" />
|
||||
<field
|
||||
name="subject"
|
||||
>Your reservation in ${object.pms_property_id.name} has been modified</field>
|
||||
<field
|
||||
name="email_from"
|
||||
>${object.pms_property_id.partner_id.email | safe}</field>
|
||||
<field
|
||||
name="email_to"
|
||||
>${(object.email and '"%s" <%s>' % (object.name, object.email) or object.partner_id.email_formatted or '') | safe}</field>
|
||||
<field name="body_html" type="html">
|
||||
<table
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="padding-top: 16px; background-color: #F1F1F1; 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="padding: 16px; background-color: white; color: #454748; border-collapse:separate;"
|
||||
>
|
||||
<head>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"
|
||||
integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
</head>
|
||||
<tbody>
|
||||
<!-- HEADER -->
|
||||
<!-- PROPERTY DESCRIPTION -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 0px 0px 0px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td align="right">
|
||||
<div class="col-sm-4">
|
||||
% if object.pms_property_id.partner_id.street
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street}</p>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.street2
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.street2}</p>
|
||||
% endif
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.zip}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.city}</p>
|
||||
<p
|
||||
>${object.pms_property_id.partner_id.country_id.name}</p>
|
||||
</div>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div>
|
||||
Hello ${object.partner_id.name or ''},<br
|
||||
/>
|
||||
Your reservation in ${object.pms_property_id.name} has been modified
|
||||
</div>
|
||||
<div>
|
||||
See you soon,<br />
|
||||
<span style="color: #454748;">
|
||||
<br />
|
||||
${object.company_id.name}
|
||||
</span>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- DETAILS -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div
|
||||
align="left"
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
><strong>Reservation Details</strong></div>
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<table style="width:50%;">
|
||||
<tr>
|
||||
<td>
|
||||
<div
|
||||
class="far fa-calendar-alt fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px; font-size: 14px;"
|
||||
>
|
||||
<div><strong
|
||||
>From</strong> ${object.checkin} <strong
|
||||
>At</strong> ${object.arrival_hour}</div>
|
||||
<div><strong
|
||||
>To</strong> ${object.checkout} <strong
|
||||
>At</strong> ${object.departure_hour}</div>
|
||||
<div
|
||||
style="font-size:12px;color:#9e9e9e"
|
||||
><i><strong
|
||||
>TZ</strong> ${object.pms_property_id.tz}</i></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
>
|
||||
<br />
|
||||
<div
|
||||
class="fas fa-bed fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td style="vertical-align:top;">
|
||||
<br />
|
||||
<div><strong
|
||||
>Room: </strong> ${object.room_type_id.name}</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
>
|
||||
<br />
|
||||
<div
|
||||
class="fas fa-coins fa-2x"
|
||||
style="margin: 0px 16px 0px 0px;"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
style="margin: 16px 0px 16px 0px; font-size: 14px;"
|
||||
>
|
||||
<br />
|
||||
<div><strong
|
||||
>Price: </strong> ${object.price_total} ${object.pms_property_id.country_id.currency_id.symbol}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<div>
|
||||
% if object.pms_property_id.mail_information
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<div
|
||||
align="left"
|
||||
style="margin: 16px 0px 16px 0px;"
|
||||
><strong
|
||||
>Additional Information</strong></div>
|
||||
<p
|
||||
>${object.pms_property_id.mail_information|safe}</p>
|
||||
% endif
|
||||
</div>
|
||||
</td></tr>
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<hr
|
||||
width="100%"
|
||||
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"
|
||||
/>
|
||||
<!-- CONTACT -->
|
||||
<div>
|
||||
<span
|
||||
style="font-weight:300;margin:10px 0px"
|
||||
>Questions about the reservation?</span>
|
||||
<div>Please contact with us:</div>
|
||||
<ul>
|
||||
<li
|
||||
>${object.pms_property_id.name}</li>
|
||||
% if object.pms_property_id.partner_id.email
|
||||
<li>Mail: <a
|
||||
href="mailto:${object.pms_property_id.partner_id.email}"
|
||||
style="text-decoration:none;color:#875A7B;"
|
||||
>${object.pms_property_id.partner_id.email}</a></li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.phone
|
||||
<li
|
||||
>Phone: ${object.pms_property_id.partner_id.phone}</li>
|
||||
% endif
|
||||
% if object.pms_property_id.partner_id.mobile
|
||||
<li
|
||||
>Mobile: ${object.pms_property_id.partner_id.mobile}</li>
|
||||
% endif
|
||||
</ul>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td></tr>
|
||||
<!-- FOOTER -->
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.pms_property_id.privacy_policy
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="font-size: 10px;">
|
||||
${object.pms_property_id.privacy_policy|safe}
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
% if object.company_id
|
||||
<table
|
||||
width="590"
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;"
|
||||
>
|
||||
<tr><td style="text-align: center; font-size: 10px;">
|
||||
Sent by <a
|
||||
target="_blank"
|
||||
href="${object.company_id.website}"
|
||||
style="color: #875A7B;"
|
||||
>${object.company_id.name}</a>
|
||||
<br />
|
||||
</td></tr>
|
||||
</table>
|
||||
% endif
|
||||
</td></tr>
|
||||
</table>
|
||||
</field>
|
||||
<field name="lang">${object.partner_id.lang}</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -31,7 +31,7 @@ from . import product_pricelist_item
|
||||
from . import res_partner
|
||||
from . import pms_sale_channel
|
||||
|
||||
# from . import mail_compose_message
|
||||
from . import mail_compose_message
|
||||
from . import pms_room_type_class
|
||||
from . import pms_room_closure_reason
|
||||
from . import pms_service_line
|
||||
@@ -46,3 +46,4 @@ from . import account_bank_statement
|
||||
from . import account_journal
|
||||
from . import pms_availability
|
||||
from . import res_partner_id_number
|
||||
from . import pms_automated_mails
|
||||
|
||||
@@ -1,24 +1,43 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class MailComposeMessage(models.TransientModel):
|
||||
_inherit = "mail.compose.message"
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
res = super(MailComposeMessage, self).default_get(fields)
|
||||
template = self.env["mail.template"].browse(self._context.get("template_id"))
|
||||
res.update(
|
||||
{
|
||||
"composition_mode": "comment",
|
||||
"attachment_ids": False,
|
||||
"template_id": template.id,
|
||||
}
|
||||
)
|
||||
return res
|
||||
|
||||
def send_mail(self, auto_commit=False):
|
||||
if (
|
||||
self._context.get("default_model") == "pms.folio"
|
||||
and self._context.get("default_res_id")
|
||||
and self._context.get("mark_so_as_sent")
|
||||
):
|
||||
# TODO: WorkFlow Mails
|
||||
folio = self.env["pms.folio"].browse([self._context["default_res_id"]])
|
||||
if folio:
|
||||
cmds = [
|
||||
(1, lid, {"to_send": False}) for lid in folio.reservation_ids.ids
|
||||
]
|
||||
if any(cmds):
|
||||
folio.reservation_ids = cmds
|
||||
return super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)
|
||||
# if (
|
||||
# self._context.get("default_model") == "pms.folio"
|
||||
# and self._context.get("default_res_id")
|
||||
# and self._context.get("mark_so_as_sent")
|
||||
# ):
|
||||
# # TODO: WorkFlow Mails
|
||||
# folio = self.env["pms.folio"].browse([self._context["default_res_id"]])
|
||||
# if folio:
|
||||
# cmds = [
|
||||
# (1, lid, {"to_send": False}) for lid in folio.reservation_ids.ids
|
||||
# ]
|
||||
# if any(cmds):
|
||||
# folio.reservation_ids = cmds
|
||||
res = super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)
|
||||
if self._context.get("record_id"):
|
||||
reservation = self.env["pms.reservation"].search(
|
||||
[("id", "=", self._context.get("record_id"))]
|
||||
)
|
||||
reservation.is_mail_send = True
|
||||
return res
|
||||
|
||||
367
pms/models/pms_automated_mails.py
Normal file
367
pms/models/pms_automated_mails.py
Normal file
@@ -0,0 +1,367 @@
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class PmsAutomatedMails(models.Model):
|
||||
_name = "pms.automated.mails"
|
||||
_description = "Automatic Mails"
|
||||
|
||||
name = fields.Char(string="Name", help="Name of the automated mail.", required=True)
|
||||
|
||||
pms_property_ids = fields.Many2many(
|
||||
string="Property",
|
||||
help="Properties with access to the element;"
|
||||
" if not set, all properties can access",
|
||||
comodel_name="pms.property",
|
||||
)
|
||||
|
||||
automated_actions_id = fields.Many2one(
|
||||
string="Automated Actions",
|
||||
help="automated action that is created when creating automated emails ",
|
||||
comodel_name="base.automation",
|
||||
)
|
||||
|
||||
time = fields.Integer(string="Time", help="Amount of time")
|
||||
|
||||
time_type = fields.Selection(
|
||||
string="Time Range",
|
||||
help="Type of date range",
|
||||
selection=[
|
||||
("minutes", "Minutes"),
|
||||
("hour", "Hour"),
|
||||
("day", "Days"),
|
||||
("month", "Months"),
|
||||
],
|
||||
default="day",
|
||||
)
|
||||
template_id = fields.Many2one(
|
||||
string="Template",
|
||||
help="The template that will be sent by email",
|
||||
comodel_name="mail.template",
|
||||
required=True,
|
||||
)
|
||||
|
||||
action = fields.Selection(
|
||||
string="Action",
|
||||
help="The action that will cause the email to be sent ",
|
||||
selection=[
|
||||
("creation", "Reservation creation"),
|
||||
("write", "Reservation modification"),
|
||||
("cancel", "Reservation cancellation"),
|
||||
("checkin", "Checkin"),
|
||||
("checkout", "Checkout"),
|
||||
("payment", "Payment"),
|
||||
("invoice", "Invoice"),
|
||||
],
|
||||
default="creation",
|
||||
required=True,
|
||||
)
|
||||
|
||||
moment = fields.Selection(
|
||||
string="Moment",
|
||||
help="Moment in relation to the action in which the email will be sent",
|
||||
selection=[
|
||||
("before", "Before"),
|
||||
("after", "After"),
|
||||
("in_act", "In the act"),
|
||||
],
|
||||
default="before",
|
||||
)
|
||||
|
||||
active = fields.Boolean(
|
||||
string="Active", help="Indicates if the automated mail is active", default=True
|
||||
)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
name = vals.get("name")
|
||||
action = vals.get("action")
|
||||
time = vals.get("time")
|
||||
date_range_type = vals.get("time_type")
|
||||
template_id = vals.get("template_id")
|
||||
active = vals.get("active")
|
||||
moment = vals.get("moment")
|
||||
properties = vals.get("pms_property_ids")
|
||||
is_create = True
|
||||
if action in ("creation", "write", "cancel", "invoice") and moment == "before":
|
||||
raise UserError(_("The moment for this action cannot be 'Before'"))
|
||||
dict_val = self._prepare_automated_actions_id(
|
||||
action, time, moment, properties, is_create
|
||||
)
|
||||
action_server_vals = {
|
||||
"name": name,
|
||||
"state": "email",
|
||||
"usage": "ir_cron",
|
||||
"model_id": dict_val["model_id"],
|
||||
}
|
||||
action_server = self.env["ir.actions.server"].create(action_server_vals)
|
||||
automated_actions_vals = {
|
||||
"active": active,
|
||||
"action_server_id": action_server.id,
|
||||
"trigger": dict_val["trigger"],
|
||||
"filter_domain": dict_val["filter_domain"],
|
||||
"filter_pre_domain": dict_val["filter_pre_domain"],
|
||||
"trg_date_range": dict_val["time"],
|
||||
"trg_date_range_type": date_range_type,
|
||||
"template_id": template_id,
|
||||
}
|
||||
model_field = dict_val["model_field"]
|
||||
if model_field:
|
||||
automated_actions_vals.update(
|
||||
{
|
||||
"trg_date_id": dict_val["model_field"].id,
|
||||
}
|
||||
)
|
||||
trigger_field = dict_val["trigger_fields"]
|
||||
if trigger_field:
|
||||
automated_actions_vals.update(
|
||||
{
|
||||
"trigger_field_ids": dict_val["trigger_fields"].ids,
|
||||
}
|
||||
)
|
||||
automated_action = self.env["base.automation"].create(automated_actions_vals)
|
||||
vals.update({"automated_actions_id": automated_action.id})
|
||||
return super(PmsAutomatedMails, self).create(vals)
|
||||
|
||||
def write(self, vals):
|
||||
result = super(PmsAutomatedMails, self).write(vals)
|
||||
is_create = False
|
||||
if (
|
||||
self.action in ("creation", "write", "cancel", "invoice")
|
||||
and self.moment == "before"
|
||||
):
|
||||
raise UserError(_("The moment for this action cannot be 'Before'"))
|
||||
dict_val = self._prepare_automated_actions_id(
|
||||
self.action, self.time, self.moment, self.pms_property_ids, is_create
|
||||
)
|
||||
automated_actions_id = self.automated_actions_id
|
||||
action_server = automated_actions_id.action_server_id
|
||||
action_server_vals = {
|
||||
"name": self.name,
|
||||
"state": "email",
|
||||
"usage": "ir_cron",
|
||||
"model_id": dict_val["model_id"],
|
||||
}
|
||||
action_server.write(action_server_vals)
|
||||
automated_actions_vals = {
|
||||
"active": self.active,
|
||||
"action_server_id": action_server.id,
|
||||
"trigger": dict_val["trigger"],
|
||||
"filter_domain": dict_val["filter_domain"],
|
||||
"filter_pre_domain": dict_val["filter_pre_domain"],
|
||||
"trg_date_range": dict_val["time"],
|
||||
"trg_date_range_type": self.time_type,
|
||||
"template_id": self.template_id,
|
||||
}
|
||||
model_field = dict_val["model_field"]
|
||||
if model_field:
|
||||
automated_actions_vals.update(
|
||||
{
|
||||
"trg_date_id": dict_val["model_field"].id,
|
||||
}
|
||||
)
|
||||
trigger_field = dict_val["trigger_fields"]
|
||||
if trigger_field:
|
||||
automated_actions_vals.update(
|
||||
{
|
||||
"trigger_field_ids": dict_val["trigger_fields"].ids,
|
||||
}
|
||||
)
|
||||
automated_actions_id.write(automated_actions_vals)
|
||||
vals.update({"automated_actions_id": automated_actions_id.id})
|
||||
return result
|
||||
|
||||
def unlink(self):
|
||||
automated_actions_id = self.automated_actions_id
|
||||
action_server = automated_actions_id.action_server_id
|
||||
automated_actions_id.unlink()
|
||||
action_server.unlink()
|
||||
return super(PmsAutomatedMails, self).unlink()
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_creation_action(self, moment, time):
|
||||
model_field = False
|
||||
model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
|
||||
if moment == "in_act":
|
||||
trigger = "on_create"
|
||||
time = 0
|
||||
else:
|
||||
trigger = "on_time"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "create_date")]
|
||||
)
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"trigger": trigger,
|
||||
"model_field": model_field,
|
||||
"time": time,
|
||||
}
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_write_or_cancel_action(self, moment, time):
|
||||
model_field = False
|
||||
model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
|
||||
if moment == "in_act":
|
||||
trigger = "on_write"
|
||||
time = 0
|
||||
else:
|
||||
trigger = "on_time"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "write_date")]
|
||||
)
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"trigger": trigger,
|
||||
"model_field": model_field,
|
||||
"time": time,
|
||||
}
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_checkin_action(self, moment, time):
|
||||
model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
|
||||
trigger = "on_time"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "checkin")]
|
||||
)
|
||||
if moment == "before":
|
||||
time = time * (-1)
|
||||
if moment == "in_act":
|
||||
trigger = "on_write"
|
||||
time = 0
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"trigger": trigger,
|
||||
"model_field": model_field,
|
||||
"time": time,
|
||||
}
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_checkout_action(self, moment, time):
|
||||
model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
|
||||
trigger = "on_time"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "checkout")]
|
||||
)
|
||||
if moment == "before":
|
||||
time = time * (-1)
|
||||
if moment == "in_act":
|
||||
trigger = "on_write"
|
||||
time = 0
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"trigger": trigger,
|
||||
"model_field": model_field,
|
||||
"time": time,
|
||||
}
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_payment_action(self, moment, time):
|
||||
model_field = False
|
||||
model_id = (
|
||||
self.env["ir.model"]
|
||||
.search([("model", "=", "account.payment"), ("transient", "=", False)])
|
||||
.id
|
||||
)
|
||||
if moment == "in_act":
|
||||
trigger = "on_create"
|
||||
time = 0
|
||||
else:
|
||||
trigger = "on_time"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "account.payment"), ("name", "=", "date")]
|
||||
)
|
||||
if moment == "before":
|
||||
time = time * (-1)
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"trigger": trigger,
|
||||
"model_field": model_field,
|
||||
"time": time,
|
||||
}
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _get_auto_action_fields_in_invoice_action(self, moment, time):
|
||||
trigger = False
|
||||
model_id = self.env["ir.model"].search([("model", "=", "account.move")]).id
|
||||
if moment == "in_act":
|
||||
trigger = "on_create"
|
||||
time = 0
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"time": time,
|
||||
"trigger": trigger,
|
||||
"model_field": False,
|
||||
}
|
||||
return result
|
||||
|
||||
def _prepare_automated_actions_id(
|
||||
self, action, time, moment, properties, is_create
|
||||
):
|
||||
filter_domain = []
|
||||
filter_pre_domain = []
|
||||
trigger_fields = False
|
||||
dict_val = {}
|
||||
if action == "creation":
|
||||
dict_val = self._get_auto_action_fields_in_creation_action(moment, time)
|
||||
elif action == "write" or action == "cancel":
|
||||
dict_val = self._get_auto_action_fields_in_write_or_cancel_action(
|
||||
moment, time
|
||||
)
|
||||
if action == "cancel":
|
||||
filter_domain = [
|
||||
("state", "=", "cancelled"),
|
||||
]
|
||||
elif action == "checkin":
|
||||
dict_val = self._get_auto_action_fields_in_checkin_action(moment, time)
|
||||
if moment == "in_act":
|
||||
trigger_fields = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "state")]
|
||||
)
|
||||
filter_pre_domain = [("state", "=", "confirm")]
|
||||
filter_domain = [
|
||||
("state", "=", "onboard"),
|
||||
]
|
||||
elif action == "checkout":
|
||||
dict_val = self._get_auto_action_fields_in_checkout_action(moment, time)
|
||||
if moment == "in_act":
|
||||
trigger_fields = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "state")]
|
||||
)
|
||||
filter_pre_domain = [("state", "=", "onboard")]
|
||||
filter_domain = [
|
||||
("state", "=", "out"),
|
||||
]
|
||||
elif action == "payment":
|
||||
dict_val = self._get_auto_action_fields_in_payment_action(moment, time)
|
||||
elif action == "invoice":
|
||||
dict_val = self._get_auto_action_fields_in_invoice_action(moment, time)
|
||||
filter_domain = [
|
||||
("folio_ids", "!=", False),
|
||||
]
|
||||
pms_property_ids = self._get_pms_property_ids(properties, is_create)
|
||||
if pms_property_ids:
|
||||
filter_domain.append(("pms_property_id", "in", pms_property_ids))
|
||||
result = {
|
||||
"trigger": dict_val["trigger"],
|
||||
"model_field": dict_val["model_field"],
|
||||
"trigger_fields": trigger_fields,
|
||||
"filter_pre_domain": filter_pre_domain,
|
||||
"filter_domain": filter_domain,
|
||||
"time": dict_val["time"],
|
||||
"model_id": dict_val["model_id"],
|
||||
}
|
||||
return result
|
||||
|
||||
def _get_pms_property_ids(self, properties, is_create):
|
||||
pms_property_ids = []
|
||||
if is_create:
|
||||
pms_property_ids = properties[0][2]
|
||||
else:
|
||||
for pms_property in properties:
|
||||
pms_property_ids.append(pms_property.id)
|
||||
return pms_property_ids
|
||||
@@ -115,6 +115,39 @@ class PmsProperty(models.Model):
|
||||
compute="_compute_availability",
|
||||
)
|
||||
|
||||
mail_information = fields.Html(
|
||||
string="Mail Information", help="Additional information of the mail"
|
||||
)
|
||||
|
||||
privacy_policy = fields.Html(string="Privacy Policy", help="Mail privacy policy ")
|
||||
|
||||
property_confirmed_template = fields.Many2one(
|
||||
string="Confirmation Template",
|
||||
help="Confirmation email template",
|
||||
comodel_name="mail.template",
|
||||
default=lambda self: self.env["mail.template"]
|
||||
.search([("name", "=", "Confirmed Reservation")])
|
||||
.id,
|
||||
)
|
||||
|
||||
property_modified_template = fields.Many2one(
|
||||
string="Modification Template",
|
||||
help="Modification email template",
|
||||
comodel_name="mail.template",
|
||||
default=lambda self: self.env["mail.template"]
|
||||
.search([("name", "=", "Modified Reservation")])
|
||||
.id,
|
||||
)
|
||||
|
||||
property_canceled_template = fields.Many2one(
|
||||
string="Cancellation Template",
|
||||
help="Cancellation email template",
|
||||
comodel_name="mail.template",
|
||||
default=lambda self: self.env["mail.template"]
|
||||
.search([("name", "=", "Cancelled Reservation")])
|
||||
.id,
|
||||
)
|
||||
|
||||
@api.depends_context(
|
||||
"checkin",
|
||||
"checkout",
|
||||
|
||||
@@ -644,6 +644,19 @@ class PmsReservation(models.Model):
|
||||
|
||||
add_possible_customer = fields.Boolean(string="Add possible Customer")
|
||||
|
||||
is_mail_send = fields.Boolean(string="Mail Sent", default=False)
|
||||
|
||||
is_modified_reservation = fields.Boolean(
|
||||
string="Is A Modified Reservation",
|
||||
compute="_compute_is_modified_reservation",
|
||||
readonly=False,
|
||||
store=True,
|
||||
)
|
||||
|
||||
lang = fields.Many2one(
|
||||
string="Language", comodel_name="res.lang", compute="_compute_lang"
|
||||
)
|
||||
|
||||
def _compute_date_order(self):
|
||||
for record in self:
|
||||
record.date_order = datetime.datetime.today()
|
||||
@@ -1428,6 +1441,25 @@ class PmsReservation(models.Model):
|
||||
for record in self:
|
||||
self.env["pms.folio"]._apply_is_possible_existing_customer_id(record)
|
||||
|
||||
@api.depends("checkin", "checkout")
|
||||
def _compute_is_modified_reservation(self):
|
||||
for record in self:
|
||||
if record.state in "draft":
|
||||
record.is_modified_reservation = False
|
||||
elif record.state in ("confirm", "onboard") and record.is_mail_send:
|
||||
record.is_modified_reservation = True
|
||||
record.is_mail_send = False
|
||||
else:
|
||||
record.is_modified_reservation = False
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_lang(self):
|
||||
for record in self:
|
||||
if record.partner_id:
|
||||
record.lang = record.partner_id.lang
|
||||
else:
|
||||
record.lang = self.env["res.lang"].get_installed()
|
||||
|
||||
def _search_allowed_checkin(self, operator, value):
|
||||
if operator not in ("=",):
|
||||
raise UserError(
|
||||
@@ -1666,6 +1698,54 @@ class PmsReservation(models.Model):
|
||||
},
|
||||
}
|
||||
|
||||
def action_open_mail_composer(self):
|
||||
self.ensure_one()
|
||||
template = False
|
||||
if (
|
||||
not self.is_mail_send
|
||||
and not self.is_modified_reservation
|
||||
and self.state not in "cancel"
|
||||
):
|
||||
template = self.env.ref(
|
||||
"pms.confirmed_reservation_email", raise_if_not_found=False
|
||||
)
|
||||
elif (
|
||||
not self.is_mail_send
|
||||
and self.is_modified_reservation
|
||||
and self.state not in "cancel"
|
||||
):
|
||||
template = self.env.ref(
|
||||
"pms.modified_reservation_email", raise_if_not_found=False
|
||||
)
|
||||
elif not self.is_mail_send and self.state in "cancel":
|
||||
template = self.env.ref(
|
||||
"pms.cancelled_reservation_email", raise_if_not_found=False
|
||||
)
|
||||
compose_form = self.env.ref(
|
||||
"mail.email_compose_message_wizard_form", raise_if_not_found=False
|
||||
)
|
||||
ctx = dict(
|
||||
model="pms.reservation",
|
||||
default_res_model="pms.reservation",
|
||||
default_res_id=self.id,
|
||||
template_id=template and template.id or False,
|
||||
composition_mode="comment",
|
||||
partner_ids=[self.partner_id.id],
|
||||
force_email=True,
|
||||
record_id=self.id,
|
||||
)
|
||||
return {
|
||||
"name": _("Send Confirmed Reservation Mail "),
|
||||
"type": "ir.actions.act_window",
|
||||
"view_type": "form",
|
||||
"view_mode": "form",
|
||||
"res_model": "mail.compose.message",
|
||||
"views": [(compose_form.id, "form")],
|
||||
"view_id": compose_form.id,
|
||||
"target": "new",
|
||||
"context": ctx,
|
||||
}
|
||||
|
||||
@api.model
|
||||
def name_search(self, name="", args=None, operator="ilike", limit=100):
|
||||
if args is None:
|
||||
@@ -1811,6 +1891,7 @@ class PmsReservation(models.Model):
|
||||
else:
|
||||
record.state = "cancel"
|
||||
record.folio_id._compute_amount()
|
||||
record.is_mail_send = False
|
||||
|
||||
def action_assign(self):
|
||||
for record in self:
|
||||
|
||||
@@ -60,3 +60,4 @@ user_access_wizard_payment_folio,user_access_wizard_payment_folio,model_wizard_p
|
||||
user_access_wizard_folio_changes,user_access_wizard_folio_changes,model_wizard_folio_changes,pms.group_pms_user,1,1,1,1
|
||||
user_access_pms_folio_portal,user_access_pms_folio_portal,model_pms_folio,base.group_portal,1,0,0,0
|
||||
user_access_pms_reservation_portal,user_access_pms_reservation_portal,model_pms_reservation,base.group_portal,1,0,0,0
|
||||
user_access_pms_automated_mails,user_access_pms_automated_mails,model_pms_automated_mails,pms.group_pms_user,1,1,1,1
|
||||
|
||||
|
@@ -38,3 +38,4 @@ from . import test_pms_wizard_split_join_swap_reservation
|
||||
from . import test_product_template
|
||||
from . import test_pms_multiproperty
|
||||
from . import test_shared_room
|
||||
from . import test_automated_mails
|
||||
|
||||
618
pms/tests/test_automated_mails.py
Normal file
618
pms/tests/test_automated_mails.py
Normal file
@@ -0,0 +1,618 @@
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
from .common import TestPms
|
||||
|
||||
|
||||
class TestPmsAutomatedMails(TestPms):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.template = self.env["mail.template"].search(
|
||||
[("name", "=", "Confirmed Reservation")]
|
||||
)
|
||||
|
||||
def test_create_automated_action(self):
|
||||
"""
|
||||
Checks that an automated_action is created correctly when an
|
||||
automated_mail is created.
|
||||
---------------------
|
||||
An automated_mail is created and then it is verified that
|
||||
the automated_action was created.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "creation",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
auto_mail.automated_actions_id, "Automated action should be created "
|
||||
)
|
||||
|
||||
def test_no_action_creation_before(self):
|
||||
"""
|
||||
Check that an automated mail cannot be created with action='creation'
|
||||
and moment='before'.
|
||||
-----------------------
|
||||
An automated mail is created with action = 'creation' and moment = 'before'.
|
||||
Then it is verified that a UserError was thrown because an automated_mail with
|
||||
these parameters cannot be created.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "creation",
|
||||
"moment": "before",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT & ASSERT
|
||||
with self.assertRaises(
|
||||
UserError,
|
||||
msg="It should not be allowed to create the automated mail "
|
||||
"with action 'creation' and moment 'before' values",
|
||||
):
|
||||
self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
def test_trigger_moment_in_act_creation(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'creation' and moment = 'in_act' the trigger of the
|
||||
automated_action created is 'on_create'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "creation",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trigger,
|
||||
"on_create",
|
||||
"The trigger of the automated action must be 'on_create'",
|
||||
)
|
||||
|
||||
def test_trigger_moment_after_in_creation_action(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'creation' and moment = 'after' the trigger of the
|
||||
automated_action created is 'on_time'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "creation",
|
||||
"moment": "after",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
"time": 1,
|
||||
"time_type": "hour",
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trigger,
|
||||
"on_time",
|
||||
"The trigger of the automated action must be 'on_time'",
|
||||
)
|
||||
|
||||
def test_trigger_moment_in_act_in_write_action(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'write' and moment = 'in_act' the trigger of the
|
||||
automated_action created is 'on_write'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "write",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trigger,
|
||||
"on_write",
|
||||
"The trigger of the automated action must be 'on_write'",
|
||||
)
|
||||
|
||||
def test_trigger_moment_after_in_write_action(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'write' and moment = 'after' the trigger of the
|
||||
automated_action created is 'on_time'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "write",
|
||||
"moment": "after",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
"time": 1,
|
||||
"time_type": "hour",
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trigger,
|
||||
"on_time",
|
||||
"The trigger of the automated action must be 'on_time'",
|
||||
)
|
||||
|
||||
def test_time_moment_before_in_checkin(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkin' and moment = 'before' the trg_date_range
|
||||
of the automated_action created is equal to
|
||||
(automated_mail.time * -1)'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkin",
|
||||
"moment": "before",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
"time": 60,
|
||||
"time_type": "minutes",
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trg_date_range,
|
||||
-60,
|
||||
"The trg_date_range of the automated action must be '-60'",
|
||||
)
|
||||
|
||||
def test_time_moment_in_act_in_checkin(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkin' and moment = 'in_act' the trg_date_range
|
||||
of the automated_action created is equal to 0
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkin",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trg_date_range,
|
||||
0,
|
||||
"The trg_date_range of the automated action must be '0'",
|
||||
)
|
||||
|
||||
def test_trigger_moment_before_in_checkin(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkin' and moment = 'before' the trigger of the
|
||||
automated_action created is 'on_time'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkin",
|
||||
"moment": "before",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
"time": 24,
|
||||
"time_type": "hour",
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trigger,
|
||||
"on_time",
|
||||
"The trigger of the automated action must be 'on_time'",
|
||||
)
|
||||
|
||||
def test_trigger_moment_in_act_in_checkin(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkin' and moment = 'in_act' the trigger of the
|
||||
automated_action created is 'on_write'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkin",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trigger,
|
||||
"on_write",
|
||||
"The trigger of the automated action must be 'on_write'",
|
||||
)
|
||||
|
||||
def test_time_moment_before_in_checkout(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkout' and moment = 'before' the trg_date_range
|
||||
of the automated_action created is equal to
|
||||
(automated_mail.time * -1)'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkout",
|
||||
"moment": "before",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
"time": 60,
|
||||
"time_type": "minutes",
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trg_date_range,
|
||||
-60,
|
||||
"The trg_date_range of the automated action must be '-60'",
|
||||
)
|
||||
|
||||
def test_time_moment_in_act_in_checkout(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkout' and moment = 'in_act' the trg_date_range
|
||||
of the automated_action created is equal to 0.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkout",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trg_date_range,
|
||||
0,
|
||||
"The trg_date_range of the automated action must be '0'",
|
||||
)
|
||||
|
||||
def test_trigger_moment_before_in_checkout(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkout' and moment = 'before' the trigger of the
|
||||
automated_action created is 'on_time'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkout",
|
||||
"moment": "before",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
"time": 24,
|
||||
"time_type": "hour",
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trigger,
|
||||
"on_time",
|
||||
"The trigger of the automated action must be 'on_time'",
|
||||
)
|
||||
|
||||
def test_trigger_moment_in_act_in_checkout(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkout' and moment = 'in_act' the trigger of the
|
||||
automated_action created is 'on_write'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkout",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trigger,
|
||||
"on_write",
|
||||
"The trigger of the automated action must be 'on_write'",
|
||||
)
|
||||
|
||||
def test_trigger_moment_in_act_in_payment_action(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'payment' and moment = 'in_act' the trigger of the
|
||||
automated_action created is 'on_create'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "payment",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trigger,
|
||||
"on_create",
|
||||
"The trigger of the automated action must be 'on_create'",
|
||||
)
|
||||
|
||||
def test_trigger_moment_before_in_payment_action(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'payment' and moment = 'before' the trigger of the
|
||||
automated_action created is 'on_time'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "payment",
|
||||
"moment": "before",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
"time": 24,
|
||||
"time_type": "hour",
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trigger,
|
||||
"on_time",
|
||||
"The trigger of the automated action must be 'on_time'",
|
||||
)
|
||||
|
||||
def test_time_moment_before_in_payment_action(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'payment' and moment = 'before' the trg_date_range
|
||||
field of the automated_action is (automated_mail.time * -1).
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "payment",
|
||||
"moment": "before",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
"time": 24,
|
||||
"time_type": "hour",
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trg_date_range,
|
||||
-24,
|
||||
"The trg_date_range of the automated action must be '-24'",
|
||||
)
|
||||
|
||||
def test_trigger_moment_in_act_in_invoice_action(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'invoice' and moment = 'in_act' the trigger field
|
||||
of the automated_action created is 'on_create'.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "invoice",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trigger,
|
||||
"on_create",
|
||||
"The trigger of the automated action must be 'on_create'",
|
||||
)
|
||||
|
||||
def test_time_moment_in_act_in_invoice_action(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'invoice' and moment = 'in_act' the trg_date_range
|
||||
field of the automated_action is 0.
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "invoice",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.trg_date_range,
|
||||
0,
|
||||
"The trg_date_range of the automated action must be '0'",
|
||||
)
|
||||
|
||||
def test_filter_pre_domain_moment_in_act_in_checkin(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkin' and moment = 'in_act' the filter_pre_domain
|
||||
field of the automated_action is [('state', '=', 'confirm')].
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkin",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.filter_pre_domain,
|
||||
"[('state', '=', 'confirm')]",
|
||||
"The filter_pre_domain of the automated action "
|
||||
"must be '[('state', '=', 'confirm')]'",
|
||||
)
|
||||
|
||||
def test_filter_domain_moment_in_act_in_checkin(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkin' and moment = 'in_act' the filter_domain
|
||||
field of the automated_action is
|
||||
[('state', '=', 'onboard'), ('pms_property_id', '=', [value of property_id.id])]].
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkin",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
pms_property_id_str = str(auto_mail.pms_property_ids.ids)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.filter_domain,
|
||||
"[('state', '=', 'onboard'), ('pms_property_id', 'in', "
|
||||
+ pms_property_id_str
|
||||
+ ")]",
|
||||
"The filter_domain of the automated action must be "
|
||||
"'[('state', '=', 'onboard'), "
|
||||
"('pms_property_id', '=', [value of property_id.id])]'",
|
||||
)
|
||||
|
||||
def test_filter_pre_domain_moment_in_act_in_checkout(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkout' and moment = 'in_act' the filter_pre_domain
|
||||
field of the automated_action is [('state', '=', 'onboard')].
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkout",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.filter_pre_domain,
|
||||
"[('state', '=', 'onboard')]",
|
||||
"The filter_pre_domain of the automated action must "
|
||||
"be '[('state', '=', 'onboard')]'",
|
||||
)
|
||||
|
||||
def test_filter_domain_moment_in_act_in_checkout(self):
|
||||
"""
|
||||
Check that when creating an automated mail with parameters
|
||||
action = 'checkout' and moment = 'in_act' the filter_domain
|
||||
field of the automated_action is
|
||||
[('state', '=', 'out'), ('pms_property_id', '=', [value of property_id.id])]].
|
||||
"""
|
||||
# ARRANGE
|
||||
automated_mail_vals = {
|
||||
"name": "Auto Mail 1",
|
||||
"template_id": self.template.id,
|
||||
"action": "checkout",
|
||||
"moment": "in_act",
|
||||
"pms_property_ids": [(6, 0, [self.pms_property1.id])],
|
||||
}
|
||||
|
||||
# ACT
|
||||
auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
|
||||
pms_property_id_str = str(auto_mail.pms_property_ids.ids)
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.filter_domain,
|
||||
"[('state', '=', 'out'), ('pms_property_id', 'in', "
|
||||
+ pms_property_id_str
|
||||
+ ")]",
|
||||
"The filter_pre_domain of the automated action must "
|
||||
"be '[('state', '=', 'out'), ('pms_property_id', '=', [value of property_id.id])]",
|
||||
)
|
||||
@@ -3424,3 +3424,77 @@ class TestPmsReservations(TestPms):
|
||||
partner.id,
|
||||
"The partner was not added to the reservation ",
|
||||
)
|
||||
|
||||
def test_is_modified_reservation(self):
|
||||
"""
|
||||
Checked that the is_modified_reservation field is correctly set
|
||||
to True when the checkin or checkout fields are modified in a
|
||||
reservation.
|
||||
----------------------
|
||||
A reservation is created. The checkin and checkout fields of
|
||||
the reservation are modified. The state of the boolean
|
||||
is_mail_send is changed to True so that the compute of
|
||||
the is_modified_reservation field is activated correctly
|
||||
and it is verified that the state of this field is True.
|
||||
"""
|
||||
# ARRANGE
|
||||
checkin = fields.date.today()
|
||||
checkout = fields.date.today() + datetime.timedelta(days=2)
|
||||
reservation_vals = {
|
||||
"checkin": checkin,
|
||||
"checkout": checkout,
|
||||
"room_type_id": self.room_type_double.id,
|
||||
"partner_id": self.partner1.id,
|
||||
"pms_property_id": self.pms_property1.id,
|
||||
}
|
||||
|
||||
reservation = self.env["pms.reservation"].create(reservation_vals)
|
||||
|
||||
# ACT
|
||||
writed_checkin = fields.date.today() + datetime.timedelta(days=4)
|
||||
writed_checkout = fields.date.today() + datetime.timedelta(days=6)
|
||||
reservation.is_mail_send = True
|
||||
reservation.update(
|
||||
{
|
||||
"checkin": writed_checkin,
|
||||
"checkout": writed_checkout,
|
||||
}
|
||||
)
|
||||
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
reservation.is_modified_reservation,
|
||||
"is_modified_reservation field should be True ",
|
||||
)
|
||||
|
||||
def test_is_not_modified_reservation(self):
|
||||
"""
|
||||
Checked that the is_modified_reservation field is correctly set
|
||||
to False when the reservation is modified but not the checkin
|
||||
or checkout fields.
|
||||
----------------------
|
||||
A reservation is created. The adults, arrival_hour and departure_hours
|
||||
fields of the reservation are modified.The it is verified that the state
|
||||
of this field is False.
|
||||
"""
|
||||
# ARRANGE
|
||||
checkin = fields.date.today()
|
||||
checkout = fields.date.today() + datetime.timedelta(days=2)
|
||||
reservation_vals = {
|
||||
"checkin": checkin,
|
||||
"checkout": checkout,
|
||||
"room_type_id": self.room_type_double.id,
|
||||
"partner_id": self.partner1.id,
|
||||
"pms_property_id": self.pms_property1.id,
|
||||
}
|
||||
|
||||
reservation = self.env["pms.reservation"].create(reservation_vals)
|
||||
reservation.update(
|
||||
{"adults": 1, "arrival_hour": "18:00", "departure_hour": "08:00"}
|
||||
)
|
||||
|
||||
# ASSERT
|
||||
self.assertFalse(
|
||||
reservation.is_modified_reservation,
|
||||
"is_modified_reservation field should be False ",
|
||||
)
|
||||
|
||||
73
pms/views/pms_automated_mails_views.xml
Normal file
73
pms/views/pms_automated_mails_views.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="pms_automated_mails_view">
|
||||
<field name="name">pms.automated_mails_view_form</field>
|
||||
<field name="model">pms.automated.mails</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Automated Mails" class="pt-1">
|
||||
<sheet>
|
||||
<div class="col-5">
|
||||
<label for="name" />
|
||||
<group>
|
||||
<h2><field name="name" /></h2>
|
||||
</group>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-5">
|
||||
<group>
|
||||
<field name="active" widget="boolean_toggle" />
|
||||
<field name="template_id" />
|
||||
<field name="action" />
|
||||
<field
|
||||
name="pms_property_ids"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True,'no_open': True}"
|
||||
/>
|
||||
</group>
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<group>
|
||||
<field name="moment" />
|
||||
<field
|
||||
name="time"
|
||||
attrs="{'invisible':[('moment','=','in_act')]}"
|
||||
/>
|
||||
<field
|
||||
name="time_type"
|
||||
attrs="{'invisible':[('moment','=','in_act')]}"
|
||||
/>
|
||||
</group>
|
||||
</div>
|
||||
</div>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_automated_mails_tree" model="ir.ui.view">
|
||||
<field name="name">pms.automated.mails.tree</field>
|
||||
<field name="model">pms.automated.mails</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Automated Mails">
|
||||
<field name="name" />
|
||||
<field name="action" />
|
||||
<field name="template_id" />
|
||||
<field name="moment" />
|
||||
<field name="time" />
|
||||
<field name="time_type" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.actions.act_window" id="open_pms_automated_mails_tree">
|
||||
<field name="name">Automated Mails</field>
|
||||
<field name="res_model">pms.automated.mails</field>
|
||||
<field name="view_id" ref="view_automated_mails_tree" />
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Automated Mails"
|
||||
id="menu_pms_automated_mails"
|
||||
action="open_pms_automated_mails_tree"
|
||||
sequence="40"
|
||||
parent="pms.pms_configuration_menu"
|
||||
/>
|
||||
</odoo>
|
||||
@@ -85,6 +85,20 @@
|
||||
<field name="room_ids" />
|
||||
</group>
|
||||
</page>
|
||||
<page string="Email Configuration">
|
||||
<group string="Templates">
|
||||
<field name="property_confirmed_template" />
|
||||
<field name="property_modified_template" />
|
||||
<field name="property_canceled_template" />
|
||||
</group>
|
||||
<group string="Mail Information" colspan="4">
|
||||
<field
|
||||
name="mail_information"
|
||||
string="Aditional Mail Information"
|
||||
/>
|
||||
<field name="privacy_policy" />
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
|
||||
@@ -43,7 +43,27 @@
|
||||
states="onboard,departure_delayed"
|
||||
type="object"
|
||||
/>
|
||||
<button
|
||||
name="action_open_mail_composer"
|
||||
string="Send Confirmation Email "
|
||||
type="object"
|
||||
attrs="{'invisible':['|','|',('is_mail_send', '=', True),('is_modified_reservation', '=', True),('state', 'in', 'cancel')]}"
|
||||
/>
|
||||
<button
|
||||
name="action_open_mail_composer"
|
||||
string="Send Modification Email "
|
||||
type="object"
|
||||
attrs="{'invisible':['|','|',('is_mail_send', '=', True), ('is_modified_reservation', '=', False), ('state', 'in', 'cancel')]}"
|
||||
/>
|
||||
<button
|
||||
name="action_open_mail_composer"
|
||||
string="Send Cancellation Email "
|
||||
type="object"
|
||||
attrs="{'invisible':['|',('is_mail_send', '=', True), ('state', 'not in', 'cancel')]}"
|
||||
/>
|
||||
<field name="state" widget="statusbar" />
|
||||
<field name="is_mail_send" invisible="1" />
|
||||
<field name="is_modified_reservation" invisible="1" />
|
||||
</header>
|
||||
<div
|
||||
class="alert alert-info"
|
||||
@@ -120,7 +140,7 @@
|
||||
class="alert alert-warning"
|
||||
role="alert"
|
||||
style="margin-bottom:0px;"
|
||||
attrs="{'invisible': [('is_possible_existing_customer_id','=',False)]}"
|
||||
attrs="{'invisible': [('is_possible_existing_customer_id','=',[])]}"
|
||||
>
|
||||
There is a customer with this email or mobile, do you want to add it to the reservation?
|
||||
<field name="is_possible_existing_customer_id" invisible="1" />
|
||||
@@ -1043,4 +1063,45 @@
|
||||
<field name="binding_view_types">form</field>
|
||||
</record>
|
||||
|
||||
<record id="action_resend_confirmation_email" model="ir.actions.act_window">
|
||||
<field name="name">Resend confirmation email</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">mail.compose.message</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="binding_model_id" ref="pms.model_pms_reservation" />
|
||||
<field name="binding_view_types">form</field>
|
||||
<field
|
||||
name="context"
|
||||
eval="{'template_id': ref('pms.confirmed_reservation_email')}"
|
||||
/>
|
||||
</record>
|
||||
|
||||
<record id="action_resend_modification_email" model="ir.actions.act_window">
|
||||
<field name="name">Resend modification email</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">mail.compose.message</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="binding_model_id" ref="pms.model_pms_reservation" />
|
||||
<field name="binding_view_types">form</field>
|
||||
<field
|
||||
name="context"
|
||||
eval="{'template_id': ref('pms.modified_reservation_email')}"
|
||||
/>
|
||||
</record>
|
||||
|
||||
<record id="action_resend_cancellation_email" model="ir.actions.act_window">
|
||||
<field name="name">Resend cancellation email</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">mail.compose.message</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="binding_model_id" ref="pms.model_pms_reservation" />
|
||||
<field name="binding_view_types">form</field>
|
||||
<field
|
||||
name="context"
|
||||
eval="{'template_id': ref('pms.cancelled_reservation_email')}"
|
||||
/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user