-
-
Notifications
You must be signed in to change notification settings - Fork 412
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] sale_gelato: integrate with Gelato for Print-On-Demand
This commit adds the possibility to fetch attributes of a template configured on Gelato to automatically create the corresponding variants in Odoo. When such variant is included in a sales order, the order is forwarded to Gelato to trigger the printing and dropshipping of the product. task-3935688 Part-of: odoo#193457 Related: odoo/enterprise#77839 Related: odoo/documentation#11823 Signed-off-by: Antoine Vandevenne (anv) <[email protected]> Co-authored-by: Antoine Vandevenne (anv) <[email protected]>
- Loading branch information
1 parent
dead43d
commit d57b032
Showing
43 changed files
with
1,638 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Part of Odoo. See LICENSE file for full copyright and licensing details. | ||
|
||
from . import controlers | ||
from . import models | ||
from . import wizards |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Part of Odoo. See LICENSE file for full copyright and licensing details. | ||
|
||
{ | ||
'name': "Gelato", | ||
'summary': "Place orders through Gelato's print-on-demand service", | ||
'category': 'Sales/Sales', | ||
'depends': ['sale_management', 'delivery'], | ||
'data': [ | ||
'data/product_data.xml', | ||
'data/delivery_carrier_data.xml', # Depends on product_data.xml | ||
'data/mail_template_data.xml', | ||
|
||
'views/delivery_carrier_views.xml', | ||
'views/product_document_views.xml', | ||
'views/product_product_views.xml', | ||
'views/product_template_views.xml', | ||
'wizards/res_config_settings_views.xml', | ||
], | ||
'license': 'LGPL-3', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Part of Odoo. See LICENSE file for full copyright and licensing details. | ||
|
||
COUNTRIES_WITHOUT_ZIPCODE = [ | ||
'AO', 'AG', 'AW', 'BS', 'BZ', 'BJ', 'BW', 'BF', 'BI', 'CM', 'CF', 'KM', | ||
'CG', 'CD', 'CK', 'CI', 'DJ', 'DM', 'GQ', 'ER', 'FJ', 'TF', 'GM', 'GH', | ||
'GD', 'GN', 'GY', 'HK', 'IE', 'JM', 'KE', 'KI', 'MO', 'MW', 'ML', 'MR', | ||
'MU', 'MS', 'NR', 'AN', 'NU', 'KP', 'PA', 'QA', 'RW', 'KN', 'LC', 'ST', | ||
'SC', 'SL', 'SB', 'SO', 'ZA', 'SR', 'SY', 'TZ', 'TL', 'TK', 'TO', 'TT', | ||
'TV', 'UG', 'AE', 'VU', 'YE', 'ZW' | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Part of Odoo. See LICENSE file for full copyright and licensing details. | ||
|
||
from . import main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# Part of Odoo. See LICENSE file for full copyright and licensing details. | ||
|
||
import hmac | ||
import logging | ||
import pprint | ||
|
||
from werkzeug.exceptions import Forbidden | ||
|
||
from odoo import SUPERUSER_ID, _ | ||
from odoo.http import Controller, request, route | ||
|
||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
class GelatoController(Controller): | ||
_webhook_url = '/gelato/webhook' | ||
|
||
@route(_webhook_url, type='http', methods=['POST'], auth='public', csrf=False) | ||
def gelato_webhook(self): | ||
""" Process the notification data sent by Gelato to the webhook. | ||
See https://dashboard.gelato.com/docs/orders/order_details/#order-statuses for the event | ||
codes. | ||
:return: An empty response to acknowledge the notification. | ||
:rtype: odoo.http.Response | ||
""" | ||
event_data = request.get_json_data() | ||
_logger.info("Webhook notification received from Gelato:\n%s", pprint.pformat(event_data)) | ||
|
||
if event_data['event'] == 'order_status_updated': | ||
# Check the signature of the webhook notification. | ||
order_id = int(event_data['orderReferenceId']) | ||
order_sudo = request.env['sale.order'].sudo().browse(order_id).exists() | ||
received_signature = request.httprequest.headers.get('signature', '') | ||
self._verify_notification_signature(received_signature, order_sudo) | ||
|
||
# Process the event. | ||
fulfillment_status = event_data.get('fulfillmentStatus') | ||
if fulfillment_status == 'failed': | ||
# Log a message on the order. | ||
log_message = _( | ||
"Gelato could not proceed with the fulfillment of order %(order_reference)s:" | ||
" %(gelato_message)s", | ||
order_reference=order_sudo.display_name, | ||
gelato_message=event_data['comment'], | ||
) | ||
order_sudo.message_post( | ||
body=log_message, author_id=request.env.ref('base.partner_root').id | ||
) | ||
elif fulfillment_status == 'canceled': | ||
# Cancel the order. | ||
order_sudo.with_user(SUPERUSER_ID)._action_cancel() | ||
|
||
# Manually cache the currency while in a sudoed environment to prevent an | ||
# AccessError. The state of the sales order is a dependency of | ||
# `untaxed_amount_to_invoice`, which is a monetary field. They require the currency | ||
# to ensure the values are saved in the correct format. However, the currency cannot | ||
# be read directly during the flush due to access rights, necessitating manual | ||
# caching. | ||
order_sudo.order_line.currency_id | ||
|
||
# Send the generic order cancellation email. | ||
order_sudo.message_post_with_source( | ||
source_ref=request.env.ref('sale.mail_template_sale_cancellation'), | ||
author_id=request.env.ref('base.partner_root').id, | ||
) | ||
elif fulfillment_status == 'in_transit': | ||
# Send the Gelato order status update email. | ||
tracking_data = self._extract_tracking_data(item_data=event_data['items']) | ||
order_sudo.with_context({'tracking_data': tracking_data}).message_post_with_source( | ||
source_ref=request.env.ref('sale_gelato.order_status_update'), | ||
author_id=request.env.ref('base.partner_root').id, | ||
) | ||
elif fulfillment_status == 'delivered': | ||
# Send the Gelato order status update email. | ||
order_sudo.with_context({'order_delivered': True}).message_post_with_source( | ||
source_ref=request.env.ref('sale_gelato.order_status_update'), | ||
author_id=request.env.ref('base.partner_root').id, | ||
) | ||
elif fulfillment_status == 'returned': | ||
# Log a message on the order. | ||
log_message = _( | ||
"Gelato has returned order %(reference)s.", reference=order_sudo.display_name | ||
) | ||
order_sudo.message_post( | ||
body=log_message, author_id=request.env.ref('base.partner_root').id | ||
) | ||
return request.make_json_response('') | ||
|
||
@staticmethod | ||
def _verify_notification_signature(received_signature, order_sudo): | ||
""" Check if the received signature matches the expected one. | ||
:param str received_signature: The received signature. | ||
:param sale.order order_sudo: The sales order for which the webhook notification was sent. | ||
:return: None | ||
:raise Forbidden: If the signatures don't match. | ||
""" | ||
company_sudo = order_sudo.company_id.sudo() # In sudo mode to read on the company. | ||
expected_signature = company_sudo.gelato_webhook_secret | ||
if not hmac.compare_digest(received_signature, expected_signature): | ||
_logger.warning("Received notification with invalid signature.") | ||
raise Forbidden() | ||
|
||
@staticmethod | ||
def _extract_tracking_data(item_data): | ||
""" Extract the tracking URL and code from the item data. | ||
:param dict item_data: The item data. | ||
:return: The extracted tracking data. | ||
:rtype: dict | ||
""" | ||
tracking_data = {} | ||
for i in item_data: | ||
for fulfilment_data in i['fulfillments']: | ||
tracking_data.setdefault( | ||
fulfilment_data['trackingUrl'], fulfilment_data['trackingCode'] | ||
) # Different items can have the same tracking URL. | ||
return tracking_data |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<odoo noupdate="1"> | ||
|
||
<record id="standard_delivery" model="delivery.carrier"> | ||
<field name="name">Standard Delivery</field> | ||
<field name="delivery_type">gelato</field> | ||
<field name="integration_level">rate</field> | ||
<field name="gelato_shipping_service_type">normal</field> | ||
<field name="product_id" ref="sale_gelato.standard_delivery_product"/> | ||
<field name="prod_environment" eval="True"/> | ||
</record> | ||
|
||
<record id="express_delivery" model="delivery.carrier"> | ||
<field name="name">Express Delivery</field> | ||
<field name="delivery_type">gelato</field> | ||
<field name="integration_level">rate</field> | ||
<field name="gelato_shipping_service_type">express</field> | ||
<field name="product_id" ref="sale_gelato.express_delivery_product"/> | ||
<field name="prod_environment" eval="True"/> | ||
</record> | ||
|
||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?xml version='1.0' encoding='utf-8'?> | ||
<odoo noupdate="1"> | ||
|
||
<record id="order_status_update" model="mail.template"> | ||
<field name="name">Gelato: Order status update</field> | ||
<field name="model_id" ref="model_sale_order"/> | ||
<field name="subject">{{ object.reference }}</field> | ||
<field name="partner_to">{{ object.partner_id.email and object.partner_id.id or object.partner_id.parent_id.id }}</field> | ||
<field name="description">Sent to the customer when Gelato updates the status of an order</field> | ||
<field name="body_html" type="html"> | ||
<div style="margin: 0px; padding: 0px;"> | ||
<p style="margin: 0px; padding: 0px; font-size: 13px;"> | ||
Hello <t t-out="object.partner_id.name or ''">Brandon Freeman</t>,<br/><br/> | ||
<!-- Order in transit body --> | ||
<t t-if="ctx.get('tracking_data')"> | ||
We are glad to inform you that your order is in transit. | ||
<t t-if="len(ctx['tracking_data']) == 1"> | ||
<t t-set="tracking_url" t-value="list(ctx['tracking_data'].keys())[0]"/> | ||
Your tracking number is <a t-attf-href="tracking_url" t-out="ctx['tracking_data'][tracking_url]"/>. | ||
<br/><br/> | ||
</t> | ||
<t t-else=""> | ||
Your tracking numbers are: | ||
<ul> | ||
<li t-foreach="ctx['tracking_data']" t-as="tracking_url"> | ||
<a t-attf-href="{{tracking_url}}" t-out="ctx['tracking_data'][tracking_url]"/> | ||
</li> | ||
</ul> | ||
</t> | ||
</t> | ||
<!-- Order delivered body --> | ||
<t t-if="ctx.get('order_delivered')"> | ||
We are glad to inform you that your order has been delivered. | ||
<br/><br/> | ||
</t> | ||
Thank you, | ||
<t t-if="object.user_id.name"> | ||
<br /> | ||
<t t-out="object.user_id.name or ''">--<br/>Mitchell Admin</t> | ||
</t> | ||
</p> | ||
</div> | ||
</field> | ||
<field name="lang">{{ object.partner_id.lang }}</field> | ||
<field name="auto_delete" eval="True"/> | ||
</record> | ||
|
||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
-- disable Gelato | ||
UPDATE res_company | ||
SET gelato_api_key = NULL, | ||
gelato_webhook_secret = NULL; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<odoo noupdate="1"> | ||
|
||
<record id="standard_delivery_product" model="product.product"> | ||
<field name="name">Standard Delivery (Gelato)</field> | ||
<field name="default_code">normal</field> | ||
<field name="type">service</field> | ||
<field name="categ_id" ref="delivery.product_category_deliveries"/> | ||
<field name="sale_ok" eval="False"/> | ||
<field name="purchase_ok" eval="False"/> | ||
<field name="list_price">0.0</field> | ||
</record> | ||
|
||
<record id="express_delivery_product" model="product.product"> | ||
<field name="name">Express Delivery (Gelato)</field> | ||
<field name="default_code">express</field> | ||
<field name="type">service</field> | ||
<field name="categ_id" ref="delivery.product_category_deliveries"/> | ||
<field name="sale_ok" eval="False"/> | ||
<field name="purchase_ok" eval="False"/> | ||
<field name="list_price">0.0</field> | ||
</record> | ||
|
||
</odoo> |
Oops, something went wrong.