# coding: utf-8 from unittest.mock import patch from odoo.addons.base.tests.common import TransactionCaseWithUserPortal from odoo.addons.website_sale.controllers.main import WebsiteSale, PaymentPortal from odoo.addons.website.tools import MockRequest from odoo.addons.website_sale.models.product_template import ProductTemplate from odoo.exceptions import UserError from odoo.tests.common import tagged from odoo.fields import Command @tagged('post_install', '-at_install') class WebsiteSaleCart(TransactionCaseWithUserPortal): @classmethod def setUpClass(cls): super(WebsiteSaleCart, cls).setUpClass() cls.website = cls.env['website'].browse(1) cls.WebsiteSaleController = WebsiteSale() cls.public_user = cls.env.ref('base.public_user') def test_add_cart_deleted_product(self): # Create a published product then unlink it product = self.env['product.product'].create({ 'name': 'Test Product', 'sale_ok': True, 'website_published': True, }) product_id = product.id product.unlink() with self.assertRaises(UserError): with MockRequest(product.with_user(self.public_user).env, website=self.website.with_user(self.public_user)): self.WebsiteSaleController.cart_update_json(product_id=product_id, add_qty=1) def test_add_cart_unpublished_product(self): # Try to add an unpublished product product = self.env['product.product'].create({ 'name': 'Test Product', 'sale_ok': True, }) with self.assertRaises(UserError): with MockRequest(product.with_user(self.public_user).env, website=self.website.with_user(self.public_user)): self.WebsiteSaleController.cart_update_json(product_id=product.id, add_qty=1) # public but remove sale_ok product.sale_ok = False product.website_published = True with self.assertRaises(UserError): with MockRequest(product.with_user(self.public_user).env, website=self.website.with_user(self.public_user)): self.WebsiteSaleController.cart_update_json(product_id=product.id, add_qty=1) def test_add_cart_archived_product(self): # Try to add an archived product product = self.env['product.product'].create({ 'name': 'Test Product', 'sale_ok': True, }) product.active = False with self.assertRaises(UserError): with MockRequest(product.with_user(self.public_user).env, website=self.website.with_user(self.public_user)): self.WebsiteSaleController.cart_update_json(product_id=product.id, add_qty=1) def test_zero_price_product_rule(self): """ With the `prevent_zero_price_sale` that we have on website, we can't add free products to our cart. There is an exception for certain product types specified by the `_get_product_types_allow_zero_price` method, so this test ensures that it works by mocking that function to return the "service" product type. """ website_prevent_zero_price = self.env['website'].create({ 'name': 'Prevent zero price sale', 'prevent_zero_price_sale': True, }) product_consu = self.env['product.product'].create({ 'name': 'Cannot be zero price', 'detailed_type': 'consu', 'list_price': 0, 'website_published': True, }) product_service = self.env['product.product'].create({ 'name': 'Can be zero price', 'detailed_type': 'service', 'list_price': 0, 'website_published': True, }) with patch.object(ProductTemplate, '_get_product_types_allow_zero_price', lambda pt: ['service']): with self.assertRaises(UserError, msg="'consu' product type is not allowed to have a 0 price sale"), \ MockRequest(self.env, website=website_prevent_zero_price): self.WebsiteSaleController.cart_update_json(product_id=product_consu.id, add_qty=1) # service types should not raise a UserError with MockRequest(self.env, website=website_prevent_zero_price): self.WebsiteSaleController.cart_update_json(product_id=product_service.id, add_qty=1) def test_update_cart_before_payment(self): product = self.env['product.product'].create({ 'name': 'Test Product', 'sale_ok': True, 'website_published': True, 'lst_price': 1000.0, 'standard_price': 800.0, }) website = self.website.with_user(self.public_user) with MockRequest(product.with_user(self.public_user).env, website=website): self.WebsiteSaleController.cart_update_json(product_id=product.id, add_qty=1) sale_order = website.sale_get_order() sale_order.access_token = 'test_token' old_amount = sale_order.amount_total self.WebsiteSaleController.cart_update_json(product_id=product.id, add_qty=1) # Try processing payment with the old amount with self.assertRaises(UserError): PaymentPortal().shop_payment_transaction(sale_order.id, sale_order.access_token, amount=old_amount) def test_update_cart_zero_qty(self): # Try to remove a product that has already been removed product = self.env['product.product'].create({ 'name': 'Test Product', 'sale_ok': True, 'website_published': True, 'lst_price': 1000.0, 'standard_price': 800.0, }) portal_user = self.user_portal website = self.website.with_user(portal_user) SaleOrderLine = self.env['sale.order.line'] with MockRequest(product.with_user(portal_user).env, website=website): # add the product to the cart self.WebsiteSaleController.cart_update_json(product_id=product.id, add_qty=1) sale_order = website.sale_get_order() self.assertEqual(sale_order.amount_untaxed, 1000.0) # remove the product from the cart self.WebsiteSaleController.cart_update_json(product_id=product.id, line_id=sale_order.order_line.id, set_qty=0) self.assertEqual(sale_order.amount_total, 0.0) self.assertEqual(sale_order.order_line, SaleOrderLine) # removing the product again doesn't add a line with zero quantity self.WebsiteSaleController.cart_update_json(product_id=product.id, set_qty=0) self.assertEqual(sale_order.order_line, SaleOrderLine) self.WebsiteSaleController.cart_update_json(product_id=product.id, add_qty=0) self.assertEqual(sale_order.order_line, SaleOrderLine) def test_unpublished_accessory_product_visibility(self): # Check if unpublished product is shown to public user accessory_product = self.env['product.product'].create({ 'name': 'Access Product', 'is_published': False, }) product = self.env['product.product'].create({ 'name': 'Test Product', 'sale_ok': True, 'website_published': True, 'accessory_product_ids': [Command.link(accessory_product.id)] }) website = self.website.with_user(self.public_user) with MockRequest(product.with_user(self.public_user).env, website=self.website.with_user(self.public_user)): self.WebsiteSaleController.cart_update_json(product_id=product.id, add_qty=1) sale_order = website.sale_get_order() self.assertEqual(len(sale_order._cart_accessories()), 0) def test_remove_archived_product_line(self): """If an order has a line containing an archived product, it is removed when opening the order in the cart.""" # Arrange user = self.public_user website = self.website.with_user(user) product = self.env['product.product'].create({ 'name': 'Product', 'sale_ok': True, 'website_published': True, }) with MockRequest(self.env(user=user), website=website): self.WebsiteSaleController.cart_update_json(product_id=product.id, add_qty=1) order = website.sale_get_order() # pre-condition: the order contains an active product self.assertRecordValues(order.order_line, [{ "product_id": product.id, }]) self.assertTrue(product.active) # Act: archive the product and open the cart product.active = False self.WebsiteSaleController.cart() # Assert: the line has been removed self.assertFalse(order.order_line) def test_keep_note_line(self): """If an order has a line containing a note, it is not removed when opening the order in the cart.""" # Arrange user = self.public_user website = self.website.with_user(user) with MockRequest(self.env(user=user), website=website): order = website.sale_get_order(force_create=True) order.order_line = [ Command.create({ "name": "Note", "display_type": "line_note", }) ] # pre-condition: the order contains only a note line self.assertRecordValues(order.order_line, [{ "display_type": "line_note", }]) # Act: open the cart self.WebsiteSaleController.cart() # Assert: the line is still there self.assertRecordValues(order.order_line, [{ "display_type": "line_note", }])