Scheduled Actions or commonly known as Cron Job is an action that will run automatically at a certain time, it could be every few minutes, every few hours, or every few days. Usually Scheduled Actions are used for work that is executed routinely but does not require user action, for example for creating a report at the end of the month, sending email to customer if their invoices are not paid after a few days, processing old transactions etc. In this tutorial I will discuss about how to create a Scheduled Actions to cancel a Sales Order if it is more than 7 days old.
Scheduled Actions are stored in the ir.cron model. Therefore, to create Scheduled Actions we need to create a record from the ir.cron model. This is an example of how to create Scheduled Actions or ir.cron record.
<?xml version='1.0' encoding='utf-8'?> <odoo> <record id="cancel_sales_order_scheduler" model="ir.cron"> <field name="name">Cancel Sales Order</field> <field name="user_id" ref="base.user_root" /> <field name="interval_number">1</field> <field name="interval_type">days</field> <field name="numbercall">-1</field> <field name="doall">0</field> <field name="model_id" ref="model_sale_order"/> <field name="code">model.cancel_old_sales_order()</field> <field name="priority">10</field> </record> </odoo>
Fill the id with any words, usually each word is separated by an underscore. Whereas in the model attribute, fill with the model of Scheduled Actions, namely ir.cron.
Fill the name field with any words. This is the name of the Scheduled Actions that we want to create.
Fill the user_id field with base.user_root. base.user_root is the odoo’s default user namely OdooBot. You can use another user, but I don’t recommend it, because it can bring you to get stuck with access rights.
Fill the interval_type field with the following choice : minutes, hours, days, weeks, or months. This field is used to set the Scheduled Actions time unit.
Fill the interval_number field with an integer with any values. This field when combined with the interval_type field will be used to set how often Scheduled Actions will be run. In the sample code above, Scheduled Actions will run once a day.
Fill the numbercall field with an integer with a any value. This field is used to set the limit on the number of times Scheduled Actions will be run. If the value is negative it means that Scheduled Actions are not restricted. Scheduled Actions will able to be executed at any time.
Fill the doall field with a value of 0 for False or 1 for True. This field is used to control whether missed Scheduled Actions, for example due to technical problems, will be re-executed after the server returns to normal or not.
Fill the model_id field with the model name where we write python code that will be run by Scheduled Actions. Pay attention to the way how I write the value.
Fill the code field with the name of the method or function that the Scheduled Actions will call. Here is an example of the code, which I created in the sale.order model.
# -*- coding: utf-8 -*- from odoo import api, fields, models, _ from datetime import datetime, timedelta class SalesOrder(models.Model): _inherit = 'sale.order' def cancel_old_sales_order(self): # days limit limit = 7 # today date date_today = datetime.today() # the date that should have been canceled cancel_date = date_today - timedelta(days = limit) # look for sales orders whose dates match and have not been confirmed old_order = self.env['sale.order'].search([('date_order', '<', cancel_date), ('state','in', ['draft','sent'])]) # cancel sales order that fits the criteria old_order.action_cancel()
Fill the priority field with an integer with any value. Scheduled Actions with a smaller priority value will be executed first.
Import both the .xml and .py files then install the module.
To see the list of Scheduled Actions, go to Settings >> Technical >> Automation >> Scheduled Actions menu. If we open one of the Scheduled Actions, the Next Execution Date field will display the date and time when the Scheduled Actions will be executed again. You can change this field to make Scheduled Actions to be executed earlier or later.
IMPORTANT !!!
If your user activity is quite busy and your Scheduled Actions process a lot of data, for example when doing a write action, make sure the Scheduled Actions are not executed during peak hours, by set up the Next Execution Date field. Because it can cause a concurrence upate error, which is an error in postgre sql where one record is changed by multiple processes.
You can also force Scheduled Actions to be executed immediately, outside of his schedule, by pressing the Run Manually button.
TIPS
In the code above, we set the limit that sales orders that are older than 7 days will be canceled by hardcode. So, how if the user suddenly think about to change it to 2 days ?
So that we don’t have to change the code all the time, we can use function parameters. Here is the cancel_old_sales_order method above which has been modified by adding a function parameter.
# -*- coding: utf-8 -*- from odoo import api, fields, models, _ from datetime import datetime, timedelta class SalesOrder(models.Model): _inherit = 'sale.order' def cancel_old_sales_order(self, force_limit=None): # days limit limit = 7 # is user fill the force_limit parameter or not if force_limit: limit = force_limit # today date date_today = datetime.today() # the date that should have been canceled cancel_date = date_today - timedelta(days = limit) # look for sales orders whose dates match and have not been confirmed old_order = self.env['sale.order'].search([('date_order', '<', cancel_date), ('state','in', ['draft','sent'])]) # cancel sales order that fits the criteria old_order.action_cancel()
If user does not fill the force_limit parameter in Scheduled Actions, Scheduled Actions will only cancel sales orders that are 7 days old. But if the user fills the force_limit as shown below, Scheduled Actions will only cancel sales orders whose age matches the value of force_limit parameter that entered by user.
Or you can also use the system parameter if you want.