forked from Mapan/odoo17e
160 lines
6.7 KiB
Python
160 lines
6.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from unittest.mock import patch
|
|
|
|
from odoo.exceptions import AccessError
|
|
from odoo.tests import tagged, JsonRpcException
|
|
from odoo.tools import mute_logger
|
|
|
|
from odoo.addons.payment.tests.http_common import PaymentHttpCommon
|
|
from odoo.addons.sale.controllers.portal import CustomerPortal as SaleCustomerPortal
|
|
from odoo.addons.sale_subscription.tests.test_sale_subscription import TestSubscriptionCommon
|
|
from odoo.addons.website.tools import MockRequest
|
|
|
|
|
|
@tagged('post_install', '-at_install')
|
|
class TestSubscriptionPaymentFlows(TestSubscriptionCommon, PaymentHttpCommon):
|
|
|
|
@classmethod
|
|
def setUpClass(cls, **kwargs):
|
|
super().setUpClass(**kwargs)
|
|
cls.order = cls.env['sale.order'].create({
|
|
'partner_id': cls.partner.id,
|
|
})
|
|
cls.user_with_so_access = cls.env['res.users'].create({
|
|
'groups_id': [(6, 0, [cls.env.ref('base.group_portal').id])],
|
|
'login': 'user_a_pouet',
|
|
'password': 'user_a_pouet', # may the min password length burn in hell
|
|
'name': 'User A',
|
|
})
|
|
cls.user_without_so_access = cls.env['res.users'].create({
|
|
'groups_id': [(6, 0, [cls.env.ref('base.group_portal').id])],
|
|
'login': 'user_b_pouet',
|
|
'password': 'user_b_pouet',
|
|
'name': 'User B',
|
|
})
|
|
# Portal access rule currently relies on mail follower(s) of the order
|
|
cls.order._message_subscribe(partner_ids=[cls.user_with_so_access.partner_id.id])
|
|
|
|
def test_tokenization_support_is_required(self):
|
|
""" Test that tokenization support is required from both payment providers and payment
|
|
methods when paying for a subscription on the portal. """
|
|
if self.env['ir.module.module']._get('website').state != 'installed':
|
|
self.skipTest("The website module is required to run this test with a request mock.")
|
|
|
|
with MockRequest(self.env), patch(
|
|
'odoo.addons.payment.models.payment_method.PaymentMethod'
|
|
'._get_compatible_payment_methods'
|
|
) as patched:
|
|
SaleCustomerPortal()._get_payment_values(self.subscription)
|
|
self.assertTrue(patched.call_args.kwargs.get('force_tokenization'))
|
|
|
|
def _my_sub_assign_token(self, **values):
|
|
url = self._build_url(f"/my/subscriptions/assign_token/{self.order.id}")
|
|
with mute_logger('odoo.addons.base.models.ir_rule', 'odoo.http'):
|
|
return self.make_jsonrpc_request(url, params=values)
|
|
|
|
def test_assign_token_route_with_so_access(self):
|
|
"""Test Assign Token Route with a user allowed to access the SO."""
|
|
self.authenticate(self.user_with_so_access.login, self.user_with_so_access.login)
|
|
dumb_token_so_user = self._create_token(
|
|
partner_id=self.user_with_so_access.partner_id.id
|
|
)
|
|
_response = self._my_sub_assign_token(token_id=dumb_token_so_user.id)
|
|
self.assertEqual(
|
|
self.order.payment_token_id, dumb_token_so_user,
|
|
"Logged Customer wasn't able to assign their token to their subscription."
|
|
)
|
|
|
|
def test_assign_token_without_so_access(self):
|
|
"""Test Assign Token Route with a user without access to the SO."""
|
|
self.authenticate(
|
|
self.user_without_so_access.login,
|
|
self.user_without_so_access.login,
|
|
)
|
|
|
|
# 1) with access token
|
|
own_token = self._create_token(
|
|
partner_id=self.user_without_so_access.partner_id.id
|
|
)
|
|
response = self._my_sub_assign_token(
|
|
token_id=own_token.id,
|
|
access_token=self.order._portal_ensure_token(),
|
|
)
|
|
self.assertEqual(
|
|
self.order.payment_token_id, own_token,
|
|
"User wasn't able to assign their token to the subscription of another customer,"
|
|
" even with the right access token.",
|
|
)
|
|
|
|
# 2) Without access token
|
|
with self._assertNotFound():
|
|
self._my_sub_assign_token(token_id=own_token.id)
|
|
|
|
# 3) With wrong access token
|
|
with self._assertNotFound():
|
|
self._my_sub_assign_token(
|
|
token_id=own_token.id,
|
|
access_token="hohoho",
|
|
)
|
|
|
|
def test_assign_token_payment_token_access(self):
|
|
self.authenticate(self.user_with_so_access.login, self.user_with_so_access.login)
|
|
|
|
# correct token
|
|
dumb_token_so_user = self._create_token(
|
|
payment_details=f'token {self.user_with_so_access.name}',
|
|
partner_id=self.user_with_so_access.partner_id.id,
|
|
)
|
|
_response = self._my_sub_assign_token(token_id=dumb_token_so_user.id)
|
|
self.assertEqual(
|
|
self.order.payment_token_id, dumb_token_so_user,
|
|
"Logged Customer wasn't able to assign their token to their subscription."
|
|
)
|
|
|
|
# token of other user --> forbidden
|
|
other_user_token = self._create_token(
|
|
payment_details=f'token {self.user_without_so_access.name}',
|
|
partner_id=self.user_without_so_access.partner_id.id,
|
|
)
|
|
with self.assertRaises(AccessError):
|
|
# Make sure the test correctly tests what it should be testing
|
|
# i.e. assigning a token not belonging to the user of the request
|
|
other_user_token.with_user(self.user_with_so_access).read()
|
|
|
|
with self._assertNotFound():
|
|
self._my_sub_assign_token(token_id=other_user_token.id)
|
|
|
|
# archived token --> forbidden
|
|
archived_token = self._create_token(
|
|
payment_details=f"archived token {self.user_with_so_access.name}",
|
|
partner_id=self.user_with_so_access.partner_id.id,
|
|
)
|
|
archived_token.action_archive()
|
|
with self._assertNotFound():
|
|
self._my_sub_assign_token(token_id=archived_token.id)
|
|
|
|
other_user_token.unlink()
|
|
deleted_token_id = other_user_token.id
|
|
|
|
with self._assertNotFound():
|
|
self._my_sub_assign_token(token_id=deleted_token_id)
|
|
|
|
self.assertEqual(
|
|
self.order.payment_token_id, dumb_token_so_user,
|
|
"Previous forbidden operations shouldn't have modified the SO token"
|
|
)
|
|
|
|
@mute_logger('odoo.http')
|
|
def test_transaction_route_rejects_unexpected_kwarg(self):
|
|
url = self._build_url(f'/my/subscriptions/{self.order.id}/transaction')
|
|
route_kwargs = {
|
|
'access_token': self.order._portal_ensure_token(),
|
|
'partner_id': self.partner.id, # This should be rejected.
|
|
}
|
|
with mute_logger("odoo.http"), self.assertRaises(
|
|
JsonRpcException, msg='odoo.exceptions.ValidationError'
|
|
):
|
|
self.make_jsonrpc_request(url, route_kwargs)
|