[IMP] delivery: notification email for shippings
When an order is shipped, a notification email is sent to the customer. If there is a tracking URL, it is included in the email. (and also a bit of refactoring)
This commit is contained in:
@@ -21,6 +21,7 @@ invoices from picking, the system is able to add and compute the shipping line.
|
||||
'views/partner_view.xml',
|
||||
'views/product_template_view.xml',
|
||||
'data/delivery_data.xml',
|
||||
'data/mail_template_data.xml',
|
||||
'views/report_shipping.xml',
|
||||
'views/report_deliveryslip.xml',
|
||||
'views/sale_config_settings_views.xml',
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="mail_template_data_delivery_confirmation" model="mail.template">
|
||||
<field name="name">Delivery: Send by Email</field>
|
||||
<field name="subject">${object.company_id.name} Delivery Order (Ref ${object.name or 'n/a' })</field>
|
||||
<field name="partner_to">${object.partner_id.id}</field>
|
||||
<field name="model_id" ref="delivery.model_stock_picking"/>
|
||||
<field name="report_template" ref="stock.action_report_delivery"/>
|
||||
<field name="report_name">${(object.name or '').replace('/','_')}</field>
|
||||
<field name="lang">${object.partner_id.lang}</field>
|
||||
<field name="body_html" type="xml">
|
||||
<p>Dear ${object.partner_id.name},</p>
|
||||
<p>We are glad to inform you that your order has been shipped.</p>
|
||||
<p>
|
||||
%if object.carrier_tracking_ref:
|
||||
Your tracking reference:
|
||||
%if object.carrier_tracking_url:
|
||||
<a href="${object.carrier_tracking_url}" target="_blank">${object.carrier_tracking_ref}</a>.
|
||||
%else:
|
||||
${object.carrier_tracking_ref}.
|
||||
%endif
|
||||
%endif
|
||||
</p>
|
||||
<p>Find your delivery order attached for more details.</p>
|
||||
<p>Thank you,</p>
|
||||
</field>
|
||||
</record>
|
||||
<!--Email Notification template for Delivery-->
|
||||
<record id="mail_template_data_delivery_notification" model="mail.template">
|
||||
<field name="name">Delivery: Custom Notification Email</field>
|
||||
<field name="subject">${object.subject}</field>
|
||||
<field name="model_id" ref="mail.model_mail_message"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html" type="xml">
|
||||
<table border="0" width="100%" cellpadding="0" bgcolor="#ededed" style="font-family:Arial,Helvetica,sans-serif; padding: 20px; background-color: #ededed" summary="o_mail_notification">
|
||||
<tbody>
|
||||
<!-- HEADER -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table width="650" border="0" cellpadding="0" bgcolor="#875A7B" style="min-width: 590px; background-color: rgb(135,90,123); padding: 20px;">
|
||||
<tr>
|
||||
<td valign="middle">
|
||||
<span style="font-size:20px; color:white; font-weight: bold;">${object.record_name}</span>
|
||||
</td>
|
||||
<td valign="middle" align="right">
|
||||
<img src="/logo.png" style="padding: 0px; margin: 0px; height: auto; width: 80px;" alt="${user.company_id.name}"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- CONTENT -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table width="650" border="0" cellpadding="0" bgcolor="#ffffff" style="min-width: 590px; background-color: rgb(255, 255, 255); padding: 20px;">
|
||||
<tbody>
|
||||
<td valign="top" style="color: #555; font-size: 14px;">${object.body | safe}</td>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- FOOTER -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table width="650" border="0" cellpadding="0" bgcolor="#875A7B" style="min-width: 590px; background-color: rgb(135,90,123); padding: 20px;">
|
||||
<tr>
|
||||
<td valign="middle" align="left" style="color: #fff; padding-top: 10px; padding-bottom: 10px; font-size: 12px;">${user.company_id.name}<br/>${user.company_id.phone or ''}</td>
|
||||
<td valign="middle" align="right" style="color: #fff; padding-top: 10px; padding-bottom: 10px; font-size: 12px;">
|
||||
% if user.company_id.email:
|
||||
<a href="mailto:${user.company_id.email}" style="text-decoration:none; color: white;">${user.company_id.email}</a><br/>
|
||||
% endif
|
||||
% if user.company_id.website:
|
||||
<a href="${user.company_id.website}" style="text-decoration:none; color: white;">${user.company_id.website}</a>
|
||||
% endif
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">Powered by <a href="https://www.odoo.com">Odoo</a>.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -136,15 +136,15 @@ class DeliveryCarrier(models.Model):
|
||||
if hasattr(self, '%s_send_shipping' % self.delivery_type):
|
||||
return getattr(self, '%s_send_shipping' % self.delivery_type)(pickings)
|
||||
|
||||
def get_tracking_link(self, pickings):
|
||||
def get_tracking_link(self, picking):
|
||||
''' Ask the tracking link to the service provider
|
||||
|
||||
:param pickings: A recordset of pickings
|
||||
:return list: A list of string URLs, containing the tracking links for every picking
|
||||
:param picking: record of stock.picking
|
||||
:return str: an URL containing the tracking link or False
|
||||
'''
|
||||
self.ensure_one()
|
||||
if hasattr(self, '%s_get_tracking_link' % self.delivery_type):
|
||||
return getattr(self, '%s_get_tracking_link' % self.delivery_type)(pickings)
|
||||
return getattr(self, '%s_get_tracking_link' % self.delivery_type)(picking)
|
||||
|
||||
def cancel_shipment(self, pickings):
|
||||
''' Cancel a shipment
|
||||
@@ -183,8 +183,8 @@ class DeliveryCarrier(models.Model):
|
||||
'tracking_number': False}]
|
||||
return res
|
||||
|
||||
def fixed_get_tracking_link(self, pickings):
|
||||
raise NotImplementedError()
|
||||
def fixed_get_tracking_link(self, picking):
|
||||
return False
|
||||
|
||||
def fixed_cancel_shipment(self, pickings):
|
||||
raise NotImplementedError()
|
||||
|
||||
@@ -104,12 +104,12 @@ class ProviderGrid(models.Model):
|
||||
carrier = self._match_address(p.partner_id)
|
||||
if not carrier:
|
||||
raise ValidationError(_('Error: no matching grid.'))
|
||||
res = res + [{'exact_price': p.carrier_id._get_price_available(p.sale_id), # TODO cleanme
|
||||
res = res + [{'exact_price': p.carrier_id._get_price_available(p.sale_id) if p.sale_id else 0.0, # TODO cleanme
|
||||
'tracking_number': False}]
|
||||
return res
|
||||
|
||||
def base_on_rule__get_tracking_link(self, pickings):
|
||||
raise NotImplementedError()
|
||||
def base_on_rule_get_tracking_link(self, picking):
|
||||
return False
|
||||
|
||||
def base_on_rule__cancel_shipment(self, pickings):
|
||||
def base_on_rule_cancel_shipment(self, pickings):
|
||||
raise NotImplementedError()
|
||||
|
||||
@@ -84,12 +84,18 @@ class StockPicking(models.Model):
|
||||
volume = fields.Float(copy=False)
|
||||
weight = fields.Float(compute='_cal_weight', digits=dp.get_precision('Stock Weight'), store=True)
|
||||
carrier_tracking_ref = fields.Char(string='Tracking Reference', copy=False)
|
||||
carrier_tracking_url = fields.Char(string='Tracking URL', compute='_compute_carrier_tracking_url')
|
||||
number_of_packages = fields.Integer(string='Number of Packages', copy=False)
|
||||
weight_uom_id = fields.Many2one('product.uom', string='Unit of Measure', required=True, readonly="1", help="Unit of measurement for Weight", default=_default_uom)
|
||||
package_ids = fields.Many2many('stock.quant.package', compute='_compute_packages', string='Packages')
|
||||
weight_bulk = fields.Float('Bulk Weight', compute='_compute_bulk_weight')
|
||||
shipping_weight = fields.Float("Weight for Shipping", compute='_compute_shipping_weight')
|
||||
|
||||
@api.depends('carrier_id', 'carrier_tracking_ref')
|
||||
def _compute_carrier_tracking_url(self):
|
||||
for picking in self:
|
||||
picking.carrier_tracking_url = picking.carrier_id.get_tracking_link(picking) if picking.carrier_id and picking.carrier_tracking_ref else False
|
||||
|
||||
@api.depends('product_id', 'move_lines')
|
||||
def _cal_weight(self):
|
||||
for picking in self:
|
||||
@@ -128,6 +134,29 @@ class StockPicking(models.Model):
|
||||
else:
|
||||
return self._put_in_pack()
|
||||
|
||||
@api.multi
|
||||
def action_send_confirmation_email(self):
|
||||
self.ensure_one()
|
||||
delivery_template_id = self.env.ref('delivery.mail_template_data_delivery_confirmation').id
|
||||
compose_form_id = self.env.ref('mail.email_compose_message_wizard_form').id
|
||||
ctx = dict(
|
||||
default_composition_mode='comment',
|
||||
default_res_id=self.id,
|
||||
default_model='stock.picking',
|
||||
default_use_template=bool(delivery_template_id),
|
||||
default_template_id=delivery_template_id,
|
||||
custom_layout='delivery.mail_template_data_delivery_notification'
|
||||
)
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'mail.compose.message',
|
||||
'view_id': compose_form_id,
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def send_to_shipper(self):
|
||||
self.ensure_one()
|
||||
@@ -148,15 +177,13 @@ class StockPicking(models.Model):
|
||||
@api.multi
|
||||
def open_website_url(self):
|
||||
self.ensure_one()
|
||||
if self.carrier_id.get_tracking_link(self):
|
||||
url = self.carrier_id.get_tracking_link(self)[0]
|
||||
else:
|
||||
if not self.carrier_tracking_url:
|
||||
raise UserError(_("Your delivery method has no redirect on courier provider's website to track this order."))
|
||||
|
||||
client_action = {'type': 'ir.actions.act_url',
|
||||
'name': "Shipment Tracking Page",
|
||||
'target': 'new',
|
||||
'url': url,
|
||||
'url': self.carrier_tracking_url,
|
||||
}
|
||||
return client_action
|
||||
|
||||
|
||||
@@ -227,6 +227,9 @@
|
||||
<xpath expr="/form/header/button[last()]" position="after">
|
||||
<button name="send_to_shipper" string="Send to Shipper" type="object" attrs="{'invisible':['|','|','|',('carrier_tracking_ref','!=',False),('delivery_type','in', ['fixed', 'base_on_rule']),('delivery_type','=',False),('state','not in',('done'))]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//button[@name='do_print_picking']" position="after">
|
||||
<button name="action_send_confirmation_email" string="Send Confirmation Email" type="object" attrs="{'invisible':['|', ('state', '!=', 'done'), ('carrier_id', '=', False)]}"/>
|
||||
</xpath>
|
||||
<field name="result_package_id" position="before">
|
||||
<button name="manage_package_type" string="Manage Package Type" type="object" icon="fa-dropbox" groups="stock.group_tracking_lot" attrs="{'invisible': [('result_package_id','=', False)]}"/>
|
||||
</field>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<xpath expr="//th[@name='td_sched_date_h']" position="after">
|
||||
<th t-if="o.picking_type_id.code == 'outgoing' and o.carrier_id"><strong>Carrier</strong></th>
|
||||
<th t-if="o.weight"><strong>Weight</strong></th>
|
||||
<th t-if="o.carrier_tracking_ref"><strong>Tracking Number</strong></th>
|
||||
</xpath>
|
||||
<xpath expr="//td[@name='td_sched_date']" position="after">
|
||||
<td t-if="o.picking_type_id.code == 'outgoing' and o.carrier_id">
|
||||
@@ -12,6 +13,9 @@
|
||||
<span t-field="o.weight"/>
|
||||
<span t-field="o.weight_uom_id"/>
|
||||
</td>
|
||||
<td t-if="o.carrier_tracking_ref">
|
||||
<span t-field="o.carrier_tracking_ref"/>
|
||||
</td>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
|
||||
@@ -58,10 +58,10 @@
|
||||
<xpath expr="//div[@id='picking_info']" position="after">
|
||||
<div t-if="i.carrier_tracking_ref">
|
||||
Tracking: <span t-field="i.carrier_id.name"/>
|
||||
<t t-if="i.carrier_id and i.carrier_id.delivery_type not in ['fixed', 'base_on_rule']">
|
||||
<a t-att-href="i.carrier_id.get_tracking_link(i)[0]" target="_blank"><span t-field="i.carrier_tracking_ref"/></a>
|
||||
<t t-if="i.carrier_tracking_url">
|
||||
<a t-att-href="i.carrier_tracking_url" target="_blank"><span t-field="i.carrier_tracking_ref"/></a>
|
||||
</t>
|
||||
<t t-if="not i.carrier_id or i.carrier_id.delivery_type in ['fixed', 'base_on_rule']">
|
||||
<t t-else="">
|
||||
<span t-field="i.carrier_tracking_ref"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user