Odoo18-Base/addons/website_sale/tests/test_address.py
2025-01-06 10:57:38 +07:00

614 lines
29 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from unittest.mock import patch
from werkzeug.exceptions import Forbidden
from odoo import api
from odoo.fields import Command
from odoo.tests import tagged
from odoo.addons.base.tests.common import BaseUsersCommon
from odoo.addons.website.tools import MockRequest
from odoo.addons.website_sale.controllers.main import WebsiteSale
from odoo.addons.website_sale.tests.common import WebsiteSaleCommon
@tagged('post_install', '-at_install')
class TestCheckoutAddress(BaseUsersCommon, WebsiteSaleCommon):
"""Test the address management part of the checkout process:
* address creation (/shop/address)
* address update (/shop/address)
* address choice (/shop/checkout)
"""
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.country_id = cls.country_be.id
cls.user_internal.partner_id.company_id = cls.env.company
def setUp(self):
super().setUp()
self.WebsiteSaleController = WebsiteSale()
self.default_address_values = {
'name': 'a res.partner address',
'email': 'email@email.email',
'street': 'ooo',
'city': 'ooo',
'zip': '1200',
'country_id': self.country_id,
'phone': '+333333333333333',
'address_type': 'delivery',
}
self.default_billing_address_values = dict(
self.default_address_values, address_type='billing',
)
def _get_last_address(self, partner):
""" Useful to retrieve the last created address (shipping or billing) """
return partner.child_ids.sorted('id', reverse=True)[0]
# TEST WEBSITE
def test_01_create_shipping_address_specific_user_account(self):
''' Ensure `website_id` is correctly set (specific_user_account) '''
p = self.env.user.partner_id
p.active = True
so = self._create_so(partner_id=p.id)
with MockRequest(self.env, website=self.website, sale_order_id=so.id) as req:
req.httprequest.method = "POST"
self.WebsiteSaleController.shop_address_submit(**self.default_address_values)
self.assertFalse(self._get_last_address(p).website_id, "New shipping address should not have a website set on it (no specific_user_account).")
self.website.specific_user_account = True
self.WebsiteSaleController.shop_address_submit(**self.default_address_values)
self.assertEqual(self._get_last_address(p).website_id, self.website, "New shipping address should have a website set on it (specific_user_account).")
# TEST COMPANY
def _setUp_multicompany_env(self):
''' Have 2 companies A & B.
Have 1 website 1 which company is B
Have admin on company A
'''
self.company_a, self.company_b, self.company_c = self.env['res.company'].create([
{'name': 'Company A'},
{'name': 'Company B'},
{'name': 'Company C'},
])
self.website.company_id = self.company_b
self.env.user.company_id = self.company_a
self.demo_user = self.user_internal
self.demo_user.company_ids += self.company_b
self.demo_user.company_id = self.company_b
self.demo_partner = self.demo_user.partner_id
self.portal_user = self.user_portal
self.portal_partner = self.portal_user.partner_id
def test_02_demo_address_and_company(self):
''' This test ensure that the company_id of the address (partner) is
correctly set and also, is not wrongly changed.
eg: new shipping should use the company of the website and not the
one from the admin, and editing a billing should not change its
company.
'''
self._setUp_multicompany_env()
so = self._create_so(partner_id=self.demo_partner.id)
env = api.Environment(self.env.cr, self.demo_user.id, {})
# change also website env for `sale_get_order` to not change order partner_id
with MockRequest(env, website=self.website.with_env(env), sale_order_id=so.id) as req:
req.httprequest.method = "POST"
# 1. Logged in user, new shipping
self.WebsiteSaleController.shop_address_submit(**self.default_address_values)
new_shipping = self._get_last_address(self.demo_partner)
self.assertTrue(new_shipping.company_id != self.env.user.company_id, "Logged in user new shipping should not get the company of the sudo() neither the one from it's partner..")
self.assertEqual(new_shipping.company_id, self.website.company_id, ".. but the one from the website.")
# 2. Logged in user/internal user, should not edit name or email address of billing
self.default_address_values['partner_id'] = self.demo_partner.id
self.WebsiteSaleController.shop_address_submit(**self.default_billing_address_values)
self.assertEqual(self.demo_partner.company_id, self.company_b, "Logged in user edited billing (the partner itself) should not get its company modified.")
self.assertNotEqual(self.demo_partner.name, self.default_address_values['name'], "Employee cannot change their name during the checkout process.")
self.assertNotEqual(self.demo_partner.email, self.default_address_values['email'], "Employee cannot change their email during the checkout process.")
def test_03_public_user_address_and_company(self):
''' Same as test_02 but with public user '''
self._setUp_multicompany_env()
so = self._create_so(partner_id=self.website.user_id.partner_id.id)
env = api.Environment(self.env.cr, self.website.user_id.id, {})
# change also website env for `sale_get_order` to not change order partner_id
with MockRequest(env, website=self.website.with_env(env), sale_order_id=so.id) as req:
req.httprequest.method = "POST"
# 1. Public user, new billing
self.default_address_values['partner_id'] = -1
self.WebsiteSaleController.shop_address_submit(**self.default_address_values)
new_partner = so.partner_id
self.assertNotEqual(new_partner, self.website.user_id.partner_id, "New billing should have created a new partner and assign it on the SO")
self.assertEqual(new_partner.company_id, self.website.company_id, "The new partner should get the company of the website")
# 2. Public user, edit billing
self.default_address_values['partner_id'] = new_partner.id
self.WebsiteSaleController.shop_address_submit(**self.default_billing_address_values)
self.assertEqual(new_partner.company_id, self.website.company_id, "Public user edited billing (the partner itself) should not get its company modified.")
def test_03_carrier_rate_on_shipping_address_change(self):
""" Test that when a shipping address is changed the price of delivery is recalculated
and updated on the order."""
partner = self.env.user.partner_id
order = self._create_so()
order.carrier_id = self.carrier.id # Set the carrier on the order.
shipping_partner_values = {'name': 'dummy', 'parent_id': partner.id, 'type': 'delivery'}
shipping_partner = self.env['res.partner'].create(shipping_partner_values)
order.partner_shipping_id = shipping_partner
with MockRequest(self.env, website=self.website, sale_order_id=order.id), patch(
'odoo.addons.delivery.models.delivery_carrier.DeliveryCarrier.rate_shipment',
return_value={'success': True, 'price': 10, 'warning_message': ''}
) as rate_shipment_mock:
# Change a shipping address of the order in the checkout.
shipping_partner2 = shipping_partner.copy()
self.WebsiteSaleController.shop_update_address(
partner_id=shipping_partner2.id, address_type='delivery'
)
self.assertGreaterEqual(
rate_shipment_mock.call_count,
1,
msg="The carrier rate must be recalculated when shipping address is changed.",
)
self.assertEqual(
order.order_line.filtered(lambda l: l.is_delivery)[0].price_unit,
10,
msg="The recalculated delivery price must be updated on the order.",
)
def test_04_apply_empty_pl(self):
''' Ensure empty pl code reset the applied pl '''
so = self._create_so(partner_id=self.env.user.partner_id.id)
eur_pl = self.env['product.pricelist'].create({
'name': 'EUR_test',
'website_id': self.website.id,
'code': 'EUR_test',
})
with MockRequest(self.env, website=self.website, sale_order_id=so.id):
self.WebsiteSaleController.pricelist('EUR_test')
self.assertEqual(so.pricelist_id, eur_pl, "Ensure EUR_test is applied")
self.WebsiteSaleController.pricelist('')
self.assertNotEqual(so.pricelist_id, eur_pl, "Pricelist should be removed when sending an empty pl code")
def test_04_pl_reset_on_login(self):
"""Check that after login, the SO pricelist is correctly recomputed."""
test_user = self.env['res.users'].create({
'name': 'Toto',
'login': 'long_enough_password',
'password': 'long_enough_password',
})
pl_with_code = self.env['product.pricelist'].create({
'name': 'EUR_test',
'website_id': self.website.id,
'code': 'EUR_test',
})
self.website.user_id.partner_id.property_product_pricelist = self.pricelist
test_user.partner_id.property_product_pricelist = pl_with_code
public_user_env = self.env(user=self.website.user_id)
so = self._create_so(partner_id=public_user_env.user.partner_id.id)
self.assertEqual(so.pricelist_id, self.pricelist)
with MockRequest(
self.env, website=self.website,
sale_order_id=so.id,
website_sale_current_pl=so.pricelist_id.id
):
self.assertEqual(self.website.pricelist_id, self.pricelist)
order = self.website.with_env(public_user_env).sale_get_order()
self.assertEqual(order, so)
self.assertEqual(order.pricelist_id, self.pricelist)
order_b = self.website.with_user(test_user).sale_get_order()
self.assertEqual(order, order_b)
self.assertEqual(order_b.pricelist_id, pl_with_code)
# TEST WEBSITE & MULTI COMPANY
def test_05_create_so_with_website_and_multi_company(self):
''' This test ensure that the company_id of the website set on the order
is the same as the env company or the one set on the order.
'''
self._setUp_multicompany_env()
# No company on the SO
so = self._create_so(partner_id=self.demo_partner.id)
self.assertEqual(so.company_id, self.website.company_id)
# Same company on the SO and the env user company but no website
with self.assertRaises(ValueError, msg="Should not be able to create SO with company different than the website company"):
self._create_so(partner_id=self.demo_partner.id, company_id=self.company_a.id)
# Same company on the SO and the website company
so = self._create_so(partner_id=self.demo_partner.id, company_id=self.company_b.id)
self.assertEqual(so.company_id, self.website.company_id)
# Different company on the SO and the env user company
with self.assertRaises(ValueError, msg="Should not be able to create SO with company different than the website company"):
self._create_so(partner_id=self.demo_partner.id, company_id=self.company_c.id)
def test_06_portal_user_address_and_company(self):
''' Same as test_03 but with portal user '''
self._setUp_multicompany_env()
so = self._create_so(partner_id=self.portal_partner.id)
env = api.Environment(self.env.cr, self.portal_user.id, {})
# change also website env for `sale_get_order` to not change order partner_id
with MockRequest(env, website=self.website.with_env(env), sale_order_id=so.id) as req:
req.httprequest.method = "POST"
# 1. Portal user, new shipping, same with the log in user
self.WebsiteSaleController.shop_address_submit(**self.default_address_values)
new_shipping = self._get_last_address(self.portal_partner)
self.assertTrue(new_shipping.company_id != self.env.user.company_id, "Portal user new shipping should not get the company of the sudo() neither the one from it's partner..")
self.assertEqual(new_shipping.company_id, self.website.company_id, ".. but the one from the website.")
# 2. Portal user, edit billing
self.default_address_values['partner_id'] = self.portal_partner.id
self.WebsiteSaleController.shop_address_submit(**self.default_billing_address_values)
# Name cannot be changed if there are issued invoices
self.assertNotEqual(self.portal_partner.name, self.default_address_values['name'], "Portal User should not be able to change the name if they have invoices under their name.")
def test_07_change_fiscal_position(self):
"""
Check that the sale order is updated when you change fiscal position.
Change fiscal position by modifying address during checkout process.
"""
self.env.company.country_id = self.country_us
be_address_POST, nl_address_POST = [
{
'name': 'Test name', 'email': 'test@email.com', 'street': 'test', 'phone': '+333333333333333',
'city': 'test', 'zip': '3000', 'country_id': self.env.ref('base.be').id, 'submitted': 1,
'partner_id': self.partner.id,
'callback': '/shop/checkout',
},
{
'name': 'Test name', 'email': 'test@email.com', 'street': 'test', 'phone': '+333333333333333',
'city': 'test', 'zip': '3000', 'country_id': self.env.ref('base.nl').id, 'submitted': 1,
'partner_id': self.partner.id,
'callback': '/shop/checkout',
},
]
tax_10_incl, tax_20_excl, tax_15_incl = self.env['account.tax'].create([
{'name': 'Tax 10% incl', 'amount': 10, 'price_include_override': 'tax_included'},
{'name': 'Tax 20% excl', 'amount': 20, 'price_include_override': 'tax_excluded'},
{'name': 'Tax 15% incl', 'amount': 15, 'price_include_override': 'tax_included'},
])
fpos_be, fpos_nl = self.env['account.fiscal.position'].create([
{
'sequence': 1,
'name': 'BE',
'auto_apply': True,
'country_id': self.env.ref('base.be').id,
'tax_ids': [Command.create({'tax_src_id': tax_10_incl.id, 'tax_dest_id': tax_20_excl.id})],
},
{
'sequence': 2,
'name': 'NL',
'auto_apply': True,
'country_id': self.env.ref('base.nl').id,
'tax_ids': [Command.create({'tax_src_id': tax_10_incl.id, 'tax_dest_id': tax_15_incl.id})],
},
])
product = self.env['product.product'].create({
'name': 'Product test',
'list_price': 100,
'website_published': True,
'sale_ok': True,
'taxes_id': [tax_10_incl.id]
})
so = self.env['sale.order'].create({
'partner_id': self.partner.id,
'website_id': self.website.id,
'order_line': [Command.create({
'product_id': product.id,
'name': 'Product test',
})]
})
self.assertEqual(
[so.amount_untaxed, so.amount_tax, so.amount_total],
[90.91, 9.09, 100.0]
)
env = api.Environment(self.env.cr, self.website.user_id.id, {})
with MockRequest(self.env, website=self.website.with_env(env), sale_order_id=so.id) as req:
req.httprequest.method = "POST"
self.WebsiteSaleController.shop_address_submit(**be_address_POST)
self.assertEqual(
so.fiscal_position_id,
fpos_be,
)
self.assertEqual(
[so.amount_untaxed, so.amount_tax, so.amount_total],
[90.91, 18.18, 109.09] # (100 : (1 + 10%)) * (1 + 20%) = 109.09
)
self.WebsiteSaleController.shop_address_submit(**nl_address_POST)
self.assertEqual(
so.fiscal_position_id,
fpos_nl,
)
self.assertEqual(
[so.amount_untaxed, so.amount_tax, so.amount_total],
[90.91, 13.64, 104.55] # (100 : (1 + 10%)) * (1 + 15%) = 104.55
)
def test_08_new_user_address_state(self):
''' Test the billing and shipping addresses creation values. '''
self._setUp_multicompany_env()
so = self._create_so(partner_id=self.demo_partner.id)
env = api.Environment(self.env.cr, self.demo_user.id, {})
# change also website env for `sale_get_order` to not change order partner_id
with MockRequest(env, website=self.website.with_env(env), sale_order_id=so.id) as req:
req.httprequest.method = "POST"
# check the default values
self.assertEqual(self.demo_partner, so.partner_invoice_id)
self.assertEqual(self.demo_partner, so.partner_shipping_id)
# 1. Logged-in user, new shipping
self.WebsiteSaleController.shop_address_submit(**self.default_address_values)
new_shipping = self._get_last_address(self.demo_partner)
msg = "New shipping address should have its type set as 'delivery'"
self.assertTrue(new_shipping.type == 'delivery', msg)
# 2. Logged-in user, new billing
self.WebsiteSaleController.shop_address_submit(**self.default_billing_address_values)
new_billing = self._get_last_address(self.demo_partner)
msg = "New billing should have its type set as 'invoice'"
self.assertTrue(new_billing.type == 'invoice', msg)
self.assertNotEqual(new_billing, self.demo_partner)
# 3. Check that invoice/shipping address of so changed
self.assertEqual(new_billing, so.partner_invoice_id)
self.assertEqual(new_shipping, so.partner_shipping_id)
# 4. Logged-in user, new delivery, use delivery as billing
use_delivery_as_billing = (
self.default_address_values | {'use_delivery_as_billing': 'true'}
)
self.WebsiteSaleController.shop_address_submit(**use_delivery_as_billing)
new_delivery_use_same = self._get_last_address(self.demo_partner)
msg = "New delivery use same should have its type set as 'other'"
self.assertTrue(new_delivery_use_same.type == 'other', msg)
self.assertNotEqual(new_billing, self.demo_partner)
# 5. Check that invoice/shipping address of so changed
self.assertEqual(new_delivery_use_same, so.partner_invoice_id)
self.assertEqual(new_delivery_use_same, so.partner_shipping_id)
# 6. forbid address page opening with wrong partners:
with self.assertRaises(Forbidden):
self.WebsiteSaleController.shop_address_submit(
partner_id=self.env.user.partner_id.id, address_type='billing'
)
with self.assertRaises(Forbidden):
self.WebsiteSaleController.shop_address_submit(
partner_id=self.env.user.partner_id.id, address_type='delivery'
)
def test_09_shop_update_address(self):
self.env['ir.config_parameter'].sudo().set_param('auth_password_policy.minlength', 4)
user = self.env['res.users'].create({
'name': 'test',
'login': 'test',
'password': 'test',
})
user_partner = user.partner_id
partner_company = self.env['res.partner'].create({
'name': 'My company',
'is_company': True,
'child_ids': [Command.link(user_partner.id)],
})
colleague = self.env['res.partner'].create({
'parent_id': partner_company.id,
'name': 'whatever',
})
colleague_shipping = self.env['res.partner'].create({
'parent_id': colleague.id,
'name': 'whatever',
'type': 'delivery',
})
self.assertEqual(partner_company.commercial_partner_id, partner_company)
self.assertEqual(user_partner.commercial_partner_id, partner_company)
invoicing, shipping, bad_invoicing, bad_shipping = self.env['res.partner'].create([
{
'name': 'Invoicing',
'street': '215 Vine St',
'city': 'Scranton',
'zip': '18503',
'country_id': self.country_us.id,
'state_id': self.country_us_state_id,
'phone': '+1 555-555-5555',
'email': 'admin@yourcompany.example.com',
'type': 'invoice',
'parent_id': user_partner.id,
},
{
'name': 'Shipping',
'street': '215 Vine St',
'city': 'Scranton',
'zip': '18503',
'country_id': self.country_us.id,
'state_id': self.country_us_state_id,
'phone': '+1 555-555-5555',
'email': 'admin@yourcompany.example.com',
'type': 'delivery',
'parent_id': user_partner.id,
},
{
'name': 'Invalid billing', # missing email
'street': '215 Vine St',
'city': 'Scranton',
'zip': '18503',
'country_id': self.country_us.id,
'state_id': self.country_us_state_id,
'phone': '+1 555-555-5555',
'type': 'invoice',
'parent_id': user_partner.id,
},
{
'name': 'Invalid Shipping',
'type': 'delivery',
'parent_id': user_partner.id,
},
])
so = self._create_so(partner_id=user_partner.id)
self.assertNotEqual(so.partner_shipping_id, shipping)
self.assertNotEqual(so.partner_invoice_id, invoicing)
self.assertFalse(colleague._can_be_edited_by_current_customer(so, 'billing'))
self.assertFalse(colleague._can_be_edited_by_current_customer(so, 'delivery'))
env = api.Environment(self.env.cr, user.id, {})
# change also website env for `sale_get_order` to not change order partner_id
with MockRequest(env, website=self.website.with_env(env), sale_order_id=so.id):
# Invalid addresses unaccessible to current customer
with self.assertRaises(Forbidden):
# cannot use contact type addresses
self.WebsiteSaleController.shop_update_address(partner_id=colleague.id)
with self.assertRaises(Forbidden):
# unrelated partner
self.WebsiteSaleController.shop_update_address(partner_id=self.env.user.partner_id.id)
# Good addresses
self.WebsiteSaleController.shop_update_address(
partner_id=colleague_shipping.id, address_type='delivery')
self.assertEqual(so.partner_shipping_id, colleague_shipping)
self.WebsiteSaleController.shop_update_address(
partner_id=shipping.id, address_type='delivery',
)
self.assertEqual(so.partner_shipping_id, shipping)
self.WebsiteSaleController.shop_update_address(
partner_id=invoicing.id, address_type='billing',
)
self.assertEqual(so.partner_shipping_id, shipping)
self.assertEqual(so.partner_invoice_id, invoicing)
# Using invalid addresses --> change and the customer is forced to update the address
self.WebsiteSaleController.shop_update_address(
partner_id=bad_invoicing.id, address_type='billing')
self.assertEqual(so.partner_invoice_id, bad_invoicing)
redirection = self.WebsiteSaleController._check_addresses(so)
self.assertTrue(redirection is not None)
self.assertEqual(redirection.location, f'/shop/address?partner_id={bad_invoicing.id}&address_type=billing')
# reset to valid one
self.WebsiteSaleController.shop_update_address(
partner_id=invoicing.id, address_type='billing',
)
self.WebsiteSaleController.shop_update_address(
partner_id=bad_shipping.id, address_type='delivery')
self.assertEqual(so.partner_shipping_id, bad_shipping)
redirection = self.WebsiteSaleController._check_addresses(so)
self.assertTrue(redirection is not None)
self.assertEqual(redirection.location, f'/shop/address?partner_id={bad_shipping.id}&address_type=delivery')
# reset to valid one
self.WebsiteSaleController.shop_update_address(
partner_id=shipping.id, address_type='delivery',
)
# Using commercial partner address
self.WebsiteSaleController.shop_update_address(
partner_id=partner_company.id, address_type='billing',
)
self.assertEqual(so.partner_invoice_id, partner_company)
self.WebsiteSaleController.shop_update_address(
partner_id=partner_company.id, address_type='delivery',
)
self.assertEqual(so.partner_shipping_id, partner_company)
def test_10_addresses_updates(self):
# TODO dispatch test to sale & account
partner_company = self.env['res.partner'].create({
'name': 'My company',
'is_company': True,
'child_ids': [
Command.create({
'name': 'partner_1',
}),
Command.create({
'name': 'partner_2',
}),
Command.create({
'name': 'partner_3',
}),
],
})
partner_1, _partner_2, _partner_3 = partner_company.child_ids
self.assertTrue(partner_company.can_edit_vat())
self.assertTrue(partner_company._can_edit_name())
self.assertTrue(all(not p.can_edit_vat() for p in partner_company.child_ids))
self.assertTrue(all(p._can_edit_name() for p in partner_company.child_ids))
dumb_product = self.env['product.product'].create({'name': 'test'})
invoice = self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': partner_company.id,
'invoice_line_ids': [
Command.create({
'product_id': dumb_product.id,
})
],
})
invoice.action_post()
self.assertEqual(invoice.state, 'posted')
self.assertFalse(partner_company.can_edit_vat())
self.assertFalse(partner_company._can_edit_name())
self.assertTrue(all(p._can_edit_name() for p in partner_company.child_ids))
invoice = self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': partner_1.id,
'invoice_line_ids': [
Command.create({
'product_id': dumb_product.id,
})
],
})
invoice.action_post()
self.assertFalse(partner_1._can_edit_name())
def test_11_payment_term_when_address_change(self):
"""Make sure the expected payment terms are set on ecommerce orders"""
self.portal_user = self.user_portal
self.portal_partner = self.portal_user.partner_id
self.assertFalse(self.portal_partner.property_payment_term_id)
so = self._create_so(partner_id=self.portal_partner.id)
self.assertTrue(so.payment_term_id, "A payment term should be set by default on the sale order")
env = api.Environment(self.env.cr, self.portal_user.id, {})
with MockRequest(env, website=self.website.with_env(env).with_context(website_id=self.website.id)) as req:
req.httprequest.method = "POST"
self.default_address_values['partner_id'] = self.portal_partner.id
self.WebsiteSaleController.shop_address_submit(**self.default_billing_address_values)
self.assertTrue(so.payment_term_id, "A payment term should still be set on the sale order")
so.website_id = False
so._compute_payment_term_id()
self.assertFalse(so.payment_term_id, "The website default payment term should not be set on a sale order not coming from the website")