odoo/odoo#163055

Created by Meet Gandhi (mega)
label
odoo-dev:16.0-sentry-5119007021-website-sale-loyalty-attribute-error-mega
head
988bf4fc7079cad56d86739825e5a8d2d574b94e
target
16.0
merged
3 weeks ago by Meet Gandhi (mega)
forward-ports

[FIX] sale_loyalty: prevent error while remove all product quantities from cart

Currently, an error is generated when removing all product quantities from the cart after a claiming a reward(discount).

Step to produce:

- Install a 'website_sale_loyalty' module.
- Navigate to the website / eCommerce / Loyalty / Discount & Loyalty to create a record.
- Set the Loyalty Program name and Program Type as 'Loyalty Cards'.(Ensure it's available on sale and the website.)
- And add 'Rewards' and set a Reward Type as 'Discount' which is applied to on Cheapest Product.
- Go to the website shop add any product on a card, Open a cart increase the quantity of the product, and claim the discount reward.
- Again go to Loyalty Program and open Loyalty Card, Open a record and add a Balance(greater than 200 as default reward points are 200) and copy 'Code'.
- Again go to the website shop and apply this code to claim a discount after a claim discount.
- Now remove all product quantity from a cart.

See Traceback:

```
AttributeError: 'bool' object has no attribute 'price_unit'
File "odoo/http.py", line 2252, in __call__
response = request._serve_db()
File "odoo/http.py", line 1828, in _serve_db
return self._transactioning(_serve_ir_http, readonly=ro)
File "odoo/http.py", line 1848, in _transactioning
return service_model.retrying(func, env=self.env)
File "odoo/service/model.py", line 134, in retrying
result = func()
File "odoo/http.py", line 1826, in _serve_ir_http
return self._serve_ir_http(rule, args)
File "odoo/http.py", line 1833, in _serve_ir_http
response = self.dispatcher.dispatch(rule.endpoint, args)
File "odoo/http.py", line 2058, in dispatch
result = self.request.registry['ir.http']._dispatch(endpoint)
File "odoo/addons/base/models/ir_http.py", line 222, in _dispatch
result = endpoint(**request.params)
File "odoo/http.py", line 740, in route_wrapper
result = endpoint(self, *args, **params_ok)
File "addons/website_sale_loyalty/controllers/main.py", line 126, in cart_update_json
return super().cart_update_json(*args, set_qty=set_qty, **kwargs)
File "odoo/http.py", line 740, in route_wrapper
result = endpoint(self, *args, **params_ok)
File "addons/website_sale/controllers/main.py", line 817, in cart_update_json
values = order._cart_update(
File "addons/website_sale_loyalty/models/sale_order.py", line 174, in _cart_update
self._update_programs_and_rewards()
File "addons/website_sale_loyalty/models/sale_order.py", line 60, in _update_programs_and_rewards
return super()._update_programs_and_rewards()
File "addons/sale_loyalty/models/sale_order.py", line 802, in _update_programs_and_rewards
values_list = self._get_reward_line_values(reward, coupon, product=reward_key[3])
File "addons/sale_loyalty_delivery/models/sale_order.py", line 64, in _get_reward_line_values
return super()._get_reward_line_values(reward, coupon, **kwargs)
File "addons/sale_loyalty/models/sale_order.py", line 573, in _get_reward_line_values
return self._get_reward_values_discount(reward, coupon, **kwargs)
File "addons/sale_loyalty/models/sale_order.py", line 321, in _get_reward_values_discount
discountable, discountable_per_tax = self._discountable_cheapest(reward)
File "addons/sale_loyalty/models/sale_order.py", line 211, in _discountable_cheapest
discountable = cheapest_line.price_unit * (1 - (cheapest_line.discount or 0) / 100)

```

The issue occurs when attempting to remove all product quantities from a cart. At this point [1], a bool value 'False' is returned, and the system attempts to get a value of 'price_unit' from it [2].

link [1]: https://github.com/odoo/odoo/blob/499056a82db26f7d9caa86314e666e2bd49cc79c/addons/sale_loyalty/models/sale_order.py#L187-L195

link [2]: https://github.com/odoo/odoo/blob/499056a82db26f7d9caa86314e666e2bd49cc79c/addons/sale_loyalty/models/sale_order.py#L205

This commit resolves the issue, If the _cheapest_line() method returns False then also returns False from _discountable_cheapest(), To raise an error at [3].

link [3]: https://github.com/odoo/odoo/blob/cbc40eccf576c499709f7825edad9a3b3ce7a22d/addons/sale_loyalty/models/sale_order.py#L317-L333

sentry-5119007021

---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr