In this approach, we leverage Odoo's controller functionality to establish a connection between a URL and a webpage.

Adding a QR Code to the Sale Order PDF

First, we extend the sale order report template to embed a QR code in the generated PDF:

xml

HTML / XML
1<template id="sales_report" inherit_id="sale.report_saleorder_document">
2 <xpath expr="//div[@id='informations']" position="replace">
3 <div class="row mt-4 mb-4" id="informations">
4 <div t-if="doc.client_order_ref" class="col-auto col-3 mw-100 mb-2" name="informations_reference">
5 <strong>Your Reference:</strong>
6 <p class="m-0" t-field="doc.client_order_ref"/>
7 </div>
8 <div t-if="doc.date_order" class="col-auto col-3 mw-100 mb-2" name="informations_date">
9 <strong t-if="doc.state in ['draft', 'sent']">Quotation Date:</strong>
10 <strong t-else="">Order Date:</strong>
11 <p class="m-0" t-field="doc.date_order" t-options='{"widget": "date"}'/>
12 </div>
13 <div t-if="doc.validity_date and doc.state in ['draft', 'sent']" class="col-auto col-3 mw-100 mb-2" name="expiration_date">
14 <strong>Expiration:</strong>
15 <p class="m-0" t-field="doc.validity_date"/>
16 </div>
17 <div t-if="doc.user_id.name" class="col-auto col-3 mw-100 mb-2">
18 <strong>Salesperson:</strong>
19 <p class="m-0" t-field="doc.user_id"/>
20 </div>
21 <t t-set="qr_code_url" t-value="doc._get_qr_code_link_to_report()"/>
22 <div class="col-2 align-items-center">
23 <div>
24 <img t-att-src="'data:image/png;base64,%s' % qr_code_url" style="width:150px;height:150px;"/>
25 </div>
26 </div>
27 </div>
28 </xpath>
29</template>

The QR code will contain a dynamically generated URL based on the sale order's state:

  • If the sale order is in the "Quotation Sent" state, the QR code will link to a custom webpage.
  • For other states, scanning the QR code will redirect to the sale order form view.

Generating the QR Code in Odoo

We extend the sale.order model to generate QR codes dynamically:

python

Python
1from odoo import api, fields, models, _
2import qrcode
3import base64
4from io import BytesIO
5
6class SaleOrderInherit(models.Model):
7 _inherit = 'sale.order'
8
9 def generate_qr(self, txt=''):
10 qr_code = qrcode.QRCode(version=4, box_size=4, border=1)
11 qr_code.add_data(txt)
12 qr_code.make(fit=True)
13 qr_img = qr_code.make_image()
14 im = qr_img._img.convert("RGB")
15 buffered = BytesIO()
16 im.save(buffered, format="JPEG")
17 img_str = base64.b64encode(buffered.getvalue()).decode('ascii')
18 return img_str
19
20 def _get_qr_code_link_to_report(self):
21 base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
22 current_id = self.id
23 action_id = self.env.ref('sale.action_orders')
24 menu_id = self.env.ref('sale.sale_menu_root')
25 cids = self.env.company
26
27 if self.state != 'sent':
28 base_url = f"{base_url}/web#id={current_id}&cids={cids.id}&menu_id={menu_id.id}&action={action_id.id}&model=sale.order&view_type=form"
29 else:
30 base_url = f"{base_url}/sale-order?{self.name}"
31
32 base64_qr = self.generate_qr(base_url)
33 return base64_qr

Handling QR Code Redirection via Controller

When the QR code is scanned and the URL contains /sale-order, a controller will be triggered to update the sale order's state:

python

Python
1from odoo import http
2from odoo.http import request
3
4class SaleOrderController(http.Controller):
5
6 @http.route(['/sale-order'], type='http', auth="user", website=True)
7 def sale_order_state_controller(self, **kw):
8 base_url = http.request.env['ir.config_parameter'].get_param('web.base.url')
9 query_string = http.request.httprequest.query_string
10
11 sale_order = request.env['sale.order'].sudo().search([('name', '=', query_string)])
12 sale_order.state = 'sale' # Update state to 'Sales Order'
13
14 current_id = sale_order.id
15 action_id = request.env.ref('sale.action_orders')
16 menu_id = request.env.ref('sale.sale_menu_root')
17 cids = request.env.company
18
19 values = {
20 'so_name': sale_order,
21 'so_url': f"{base_url}/web#id={current_id}&cids={cids.id}&menu_id={menu_id.id}&action={action_id.id}&model=sale.order&view_type=form"
22 }
23 return request.render("testmodule.controller_template", values)

Custom Web Page for Sale Order State Update

The following template displays a confirmation message when the sale order state is updated and provides a redirection button:

xml

HTML / XML
1<template id="controller_template">
2 <t t-call="website.layout">
3 <div id="wrap">
4 <div class="oe_structure">
5 <section data-snippet-id="text-block" class="mb16">
6 <div class="container">
7 <div class="row">
8 <div class="col-md-12 text-center mb16 message" data-snippet-id="colmd">
9 <style>
10 .message { margin-top: 100px; }
11 .button a {
12 background-color: #714B67;
13 padding: 0.5rem 2rem;
14 border-radius: 10px;
15 text-decoration: none;
16 color: white;
17 }
18 </style>
19 <p><strong>Your Sale Order </strong>
20 <span style="color:red" t-esc="so_name.name"/>
21 has been moved to <strong t-esc="so_name.state"></strong>
22 </p>
23 <p>Do you want to redirect to the Sale Order?</p>
24 <div class="button">
25 <t t-set="url" t-value="so_url"/>
26 <a t-attf-href="{{url}}">Yes</a>
27 </div>
28 </div>
29 </div>
30 </div>
31 </section>
32 </div>
33 </div>
34 </t>
35</template>

How It Works

  1. When a user scans the QR code from the PDF, it redirects to a webpage based on the sale order state.
  2. If the sale order is in the "Quotation Sent" state, the user is taken to a confirmation page.
  3. Clicking "Yes" on the confirmation page redirects to the sale order form view in Odoo.
  4. The sale order state is updated to "Sales Order" automatically.

This implementation enables seamless state updates and navigation for sales orders via QR code scanning.