javascriptpythonodooe-commerceodoo-13

Programmatically add products to a cart – Odoo 13


I have a custom module that creates a form. Based on the answers inside this form I’m generating order line. After user sends this form I’m creating sale order with all products from the generated order line.

So from JavaScript I’m sending an JSON with products to buy:

order_data = [{product_id: 1, amount: 10, …},{product_id: 2, …}, …];
note = '';
this._rpc({
        route: '/api/create_order',
        params: { order_products: order_data, note: note }
    }).then((data) => {
        window.location = '/contactus-thank-you';
    }).catch((error) => {
        console.error(error);
    });

And then inside Python I’m creating sale order based on the JSON:

@http.route('/api/create_order', type='json', auth='user', website=True)
def create_order(self, **kw):
    uid = http.request.env.context.get('uid')
    partner_id = http.request.env['res.users'].search([('id','=',uid)]).partner_id.id
    
    order_products = kw.get('order_products', [])
    note = kw.get('note', '')
    order_line = []

    for product in order_products:

        amount = 0
        if 'custom_amount' in product:
            amount = product['custom_amount']
        else:
            amount = product['amount']

        if amount > 0:
            order_line.append(
                (0, 0, {
                    'product_id': product['product_id'],
                    'product_uom_qty': amount,
                }))

    order_data = {
        'name': http.request.env['ir.sequence'].with_user(SUPERUSER_ID).next_by_code('sale.order') or _('New'),
        'partner_id': partner_id,
        'order_line': order_line,
        'note': note,
    }

    result_insert_record = http.request.env['sale.order'].with_user(SUPERUSER_ID).create(order_data)
    return result_insert_record.id

But instead of generating sale order directly I need to use workflow from Odoo’s eCommerce addon. That way user can for example edit delivery address, choose payment etc. So I think I just need to programmatically put all the product inside a cart and then rest will be taken care of by Odoo built-in functionality. But how? I’ve tried to find something inside Odoo source code but it is quite hard to grasp anything.


Solution

  • Odoo uses a typical Sale Order for handling products inside a cart. But the process isn't as simple as just creating Sale Order with some products. Odoo needs to know which order is linked with which cart etc.

    Luckily Odoo has a method for dealing with it. There is a sale_get_order() method that lets you get an order that is currently linked with a cart or create new one if there isn't any.

    I'm not sure if it is documented anywhere outside the source code so here is a slice from the code (/addons/website_sale/models/website.py):

    def sale_get_order(self, force_create=False, code=None, update_pricelist=False, force_pricelist=False):
        """ Return the current sales order after mofications specified by params.
        :param bool force_create: Create sales order if not already existing
        :param str code: Code to force a pricelist (promo code)
                            If empty, it's a special case to reset the pricelist with the first available else the default.
        :param bool update_pricelist: Force to recompute all the lines from sales order to adapt the price with the current pricelist.
        :param int force_pricelist: pricelist_id - if set,  we change the pricelist with this one
        :returns: browse record for the current sales order
        """
    # ...
    

    I'm using it alongside another method _cart_update() that lets me easily update products inside this order. There is also sale_reset() and I'm using it just to be sure that current session will be updated with particular sale order every time.

    sale_order = request.website.sale_get_order(force_create=True)
    request.website.sale_reset()
    sale_order.write({'order_line':[(5, 0, 0)]})
    
    for product in order_products:
        sale_order._cart_update(product_id=product['product_id'], line_id=None, add_qty=None, set_qty=product['amount'])