[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:
Dhawal Limbuwala
2017-07-19 15:02:16 +02:00
committed by Richard Mathot
parent f858cea1fa
commit ee9b3e0d0c
8 changed files with 141 additions and 17 deletions
+1
View File
@@ -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>
+6 -6
View File
@@ -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()
+4 -4
View File
@@ -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()
+31 -4
View File
@@ -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
+3
View File
@@ -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>