Search code examples
javascripthtmlformsqwebodoo-12

Add product to cart on a non shop page


We are using the software of Odoo 12 for enterprises.

We want to duplicate the behaviour of the add to cart button on the product pages. So we want to add a button on a different page and when you click the button you add a product to your cart and get redirected to your cart. The product is hardcoded to that button.

This is the form used on the product page template:

       <form t-if="product._is_add_to_cart_possible()" action="/shop/cart/update" method="POST">
          <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
          <div class="js_product js_main_product">
            <t t-placeholder="select">
              <input type="hidden" class="product_id" name="product_id" t-att-value="product_variant.id"/>
              <input type="hidden" class="product_template_id" name="product_template_id" t-att-value="product.id"/>
              <t t-if="first_possible_combination" t-call="sale.variants">
                <t t-set="ul_class" t-value="'flex-column'"/>
                <t t-set="parent_combination" t-value="None"/>
              </t>
              <t t-else="">
                <ul class="d-none js_add_cart_variants" t-att-data-attribute_exclusions="{'exclusions: []'}"/>
              </t>
            </t>
            <t t-call="website_sale.product_price"/>
            <p t-if="True" class="css_not_available_msg alert alert-warning">This combination does not exist.</p>
            <a role="button" id="add_to_cart" class="btn btn-primary btn-lg mt8 js_check_product a-submit" href="#">Add to Cart</a>
          </div>
        </form>

The info of our product: product.id = 135 and product_template.id = 83.

I've found that the javascript responsible for the adding to the cart is called using: /web/content/.../.../web.assets_frontend.js. This is a very large file but you can check an example here: file.

Which qweb/form/js/... should I add on my custom page to add a product to my cart?

Thanks for any help, I've been stuck on this for a long time!

Edit: As @Philippe Pageau pointed out I can use some code to get the correct product already. I've tried implementing it with the form using this code (the simplest version of the form I can think of):

      <t t-set="products" t-value="request.env['product.product'].search([['id', '=', 135]])"/>
        <t t-foreach="products" t-as="product">
          <form action="/shop/cart/update" method="POST">
             <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
             <input type="hidden" class="product_id" name="product_id" value="135"/>
             <input type="hidden" class="product_template_id" name="product_template_id" value="83"/>
             <a role="button" id="add_to_cart" class="btn btn-primary btn-lg mt8 js_check_product a-submit" href="#">Add to Cart</a>
          </form>
      </t>

But this does nothing, what am I missing?

Edit2:

Thanks to @Adan Cortes we are further now but there is still 1 problem.

Now when the user clicks on a button the products gets added to the cart with a specific quantity.

This is my code now:

<t t-set="products" t-value="request.env['product.product'].search([['id', '=', 135]])"/>
      <t t-foreach="products" t-as="product">
        <div id="product_detail" class="oe_website_sale">
          <form action="/shop/cart/update" method="POST">
              <h4 t-esc="product.name"/>
              <h6 t-esc="product.price"/>
              <input class="form-control" data-min="1" name="add_qty" value="1"/>
              <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
              <input type="hidden" class="product_id" name="product_id" value="135"/>
              <a role="button" id="add_to_cart" class="btn btn-primary btn-lg mt8 js_check_product a-submit" href="#">Add to Cart</a>
          </form>
        </div>
      </t> 

But these are my final problems:

  • This code doesn't show the product price. <h6 t-esc="product.price"/> displays 0.00. So how can I display the price?

  • Finally is it possible to add multiple products at once using only 1 button and form?


Solution

  • The following code works:

    <div id="product_detail" class="oe_website_sale">
        <form action="/shop/cart/update" method="POST">
            <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
            <input type="hidden" class="product_id" name="product_id" value="135"/>
            <a role="button" id="add_to_cart" class="btn btn-primary btn-lg mt8 js_check_product a-submit" href="#">Add to Cart</a>
        </form>
    </div>
    

    But beware that using the database id makes your module unusable elsewhere. You better use xmlids.

    The relevant JavaScript you were missing is at:

    <path_to_v12>/addons/website_sale/static/src/js/website_sale.js

    135 sAnimations.registry.WebsiteSale = sAnimations.Class.extend(ProductConfiguratorMixin, {
    136     selector: '.oe_website_sale',
    137     read_events: {
    138         'change form .js_product:first input[name="add_qty"]': '_onChangeAddQuantity',
    139         'mouseup .js_publish': '_onMouseupPublish',
    140         'touchend .js_publish': '_onMouseupPublish',
    141         'change .oe_cart input.js_quantity[data-product-id]': '_onChangeCartQuantity',
    142         'click .oe_cart a.js_add_suggested_products': '_onClickSuggestedProduct',
    143         'click a.js_add_cart_json': '_onClickAddCartJSON',
    144         'click .a-submit': '_onClickSubmit',
    145         'change form.js_attributes input, form.js_attributes select': '_onChangeAttribute',
    146         'mouseup form.js_add_cart_json label': '_onMouseupAddCartLabel',
    147         'touchend form.js_add_cart_json label': '_onMouseupAddCartLabel',
    148         'click .show_coupon': '_onClickShowCoupon',
    149         'submit .o_website_sale_search': '_onSubmitSaleSearch',
    150         'change select[name="country_id"]': '_onChangeCountry',
    151         'change #shipping_use_same': '_onChangeShippingUseSame',
    152         'click .toggle_summary': '_onToggleSummary',
    153         'click input.js_product_change': 'onChangeVariant',
    154         'change .js_main_product [data-attribute_exclusions]': 'onChangeVariant',
    155     },
    

    and <path_to_v12>/addons/website_sale/static/src/js/website_sale_tracking.js

      5 sAnimations.registry.websiteSaleTracking = sAnimations.Class.extend({
      6     selector: '.oe_website_sale',
      7     read_events: {
      8         'click form[action="/shop/cart/update"] a.a-submit': '_onAddProductIntoCart',
      9         'click a[href="/shop/checkout"]': '_onCheckoutStart',
     10         'click div.oe_cart a[href^="/web?redirect"][href$="/shop/checkout"]': '_onCustomerSignin',
     11         'click form[action="/shop/confirm_order"] a.a-submit': '_onOrder',
     12         'click form[target="_self"] button[type=submit]': '_onOrderPayment',
     13     },
    

    Edited to add

    The form data is processed and dispatched by the following controller:

    <path_to_v12>/addons/website_sale/controllers/main.py

    414     @http.route(['/shop/cart/update'], type='http', auth="public", methods=['POST'], website=True, csrf=False)
    415     def cart_update(self, product_id, add_qty=1, set_qty=0, **kw):
    416         """This route is called when adding a product to cart (no options)."""
    418         sale_order = request.website.sale_get_order(force_create=True)
    419         if sale_order.state != 'draft':
    420             request.session['sale_order_id'] = None
    421             sale_order = request.website.sale_get_order(force_create=True)
    422 
    423         product_custom_attribute_values = None
    424         if kw.get('product_custom_attribute_values'):
    425             product_custom_attribute_values = json.loads(kw.get('product_custom_attribute_values'))
    426 
    427         no_variant_attribute_values = None
    428         if kw.get('no_variant_attribute_values'):
    429             no_variant_attribute_values = json.loads(kw.get('no_variant_attribute_values'))
    430 
    431         sale_order._cart_update(
    432             product_id=int(product_id),
    433             add_qty=add_qty,
    434             set_qty=set_qty,
    435             product_custom_attribute_values=product_custom_attribute_values,
    436             no_variant_attribute_values=no_variant_attribute_values
    437         )
    438         return request.redirect("/shop/cart")