diff --git a/shopinvader_anonymous_partner/models/res_partner.py b/shopinvader_anonymous_partner/models/res_partner.py
index 4400851144..4bebb32e25 100644
--- a/shopinvader_anonymous_partner/models/res_partner.py
+++ b/shopinvader_anonymous_partner/models/res_partner.py
@@ -3,6 +3,7 @@
import secrets
import typing
+from datetime import datetime
from odoo import _, api, fields, models
@@ -16,6 +17,7 @@ def set_cookie(
key: str,
value: str,
max_age: int,
+ expires: datetime | str | int,
secure: bool,
httponly: bool,
samesite: typing.Literal["lax", "strict", "none"],
@@ -72,6 +74,18 @@ def _create_anonymous_partner__cookie(self, response: Response):
)
return partner
+ @api.model
+ def _delete_anonymous_partner__cookie(self, cookies: Cookies, response: Response):
+ """
+ Delete anonymous partner and cookie
+ """
+ self._get_anonymous_partner__cookie(cookies).unlink()
+ response.set_cookie(
+ key=COOKIE_NAME,
+ max_age=0,
+ expires=0,
+ )
+
@api.model
def _get_anonymous_partner__token(self, token: str):
return (
diff --git a/shopinvader_anonymous_partner/tests/test_anonymous_partner.py b/shopinvader_anonymous_partner/tests/test_anonymous_partner.py
index b59b99f669..ddec37f24a 100644
--- a/shopinvader_anonymous_partner/tests/test_anonymous_partner.py
+++ b/shopinvader_anonymous_partner/tests/test_anonymous_partner.py
@@ -34,6 +34,14 @@ def anonymous_partner_get(self):
return str(partner.id)
return ""
+ @route("/test/anonymous_partner_delete", type="http", auth="none")
+ def anonymous_partner_delete(self):
+ request.env["res.partner"].with_user(
+ SUPERUSER_ID
+ )._delete_anonymous_partner__cookie(
+ request.httprequest.cookies, request.future_response
+ )
+
class TestShopinvaderAnonymousPartner(TransactionCase):
def test_create(self):
@@ -69,9 +77,19 @@ def test_get(self):
)
self.assertEqual(len(partner2), 0)
+ def test_delete(self):
+ partner = self.env["res.partner"]._create_anonymous_partner__cookie(
+ mock.MagicMock()
+ )
+ self.assertTrue(partner.exists())
+ self.env["res.partner"]._delete_anonymous_partner__cookie(
+ cookies={COOKIE_NAME: partner.anonymous_token}, response=mock.MagicMock()
+ )
+ self.assertFalse(partner.exists())
+
class TestShopinvaderAnonymousPartnerEndToEnd(HttpCase):
- def test_create_and_get(self):
+ def test_create_and_get_and_delete(self):
resp = self.url_open("/test/anonymous_partner_create")
resp.raise_for_status()
token = resp.cookies.get(COOKIE_NAME)
@@ -89,3 +107,7 @@ def test_create_and_get(self):
)
resp.raise_for_status()
self.assertEqual(int(resp.text), partner_id)
+ # delete cookie
+ resp = self.url_open("/test/anonymous_partner_delete")
+ resp.raise_for_status()
+ self.assertFalse(resp.cookies.get(COOKIE_NAME))
diff --git a/shopinvader_api_signin_jwt/README.rst b/shopinvader_api_signin_jwt/README.rst
index 3bf6f61b41..0127f41706 100644
--- a/shopinvader_api_signin_jwt/README.rst
+++ b/shopinvader_api_signin_jwt/README.rst
@@ -7,7 +7,7 @@ Shopinvader Api Signin JWT
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- !! source digest: sha256:75ace7db3bf1d327ad236aa12212ec10ad5363f81a8d3fd9896afe3f4d195fc4
+ !! source digest: sha256:335295feb8193e9691d56e3537300ec06022d9a6abe43a72a0639e1ce6e3fc68
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
@@ -24,6 +24,7 @@ Shopinvader Api Signin JWT
This addon adds a web API to signin into the application and create a partner
if the email in the jwt payload is unknown.
+If we had an anonymous partner, transfer his cart to the loggedin partner and delete it.
**Table of contents**
@@ -33,7 +34,6 @@ if the email in the jwt payload is unknown.
Known issues / Roadmap
======================
-* Manage anonymous cart (see https://github.com/shopinvader/odoo-shopinvader/issues/1428)
* Use ``fastapi_auth_jwt.auth_jwt_authenticated_odoo_env`` dependency for the env (see https://github.com/OCA/rest-framework/issues/406)
Bug Tracker
diff --git a/shopinvader_api_signin_jwt/__manifest__.py b/shopinvader_api_signin_jwt/__manifest__.py
index c84506a719..a51247e489 100644
--- a/shopinvader_api_signin_jwt/__manifest__.py
+++ b/shopinvader_api_signin_jwt/__manifest__.py
@@ -8,7 +8,11 @@
"license": "AGPL-3",
"author": "ACSONE SA/NV",
"website": "https://github.com/shopinvader/odoo-shopinvader",
- "depends": ["fastapi_auth_jwt"],
+ "depends": [
+ "fastapi_auth_jwt",
+ "shopinvader_anonymous_partner",
+ "shopinvader_sale_cart",
+ ],
"data": [
"security/res_groups.xml",
"security/acl_res_partner.xml",
diff --git a/shopinvader_api_signin_jwt/readme/DESCRIPTION.rst b/shopinvader_api_signin_jwt/readme/DESCRIPTION.rst
index 9d807c0111..3c60d139e1 100644
--- a/shopinvader_api_signin_jwt/readme/DESCRIPTION.rst
+++ b/shopinvader_api_signin_jwt/readme/DESCRIPTION.rst
@@ -1,2 +1,3 @@
This addon adds a web API to signin into the application and create a partner
if the email in the jwt payload is unknown.
+If we had an anonymous partner, transfer his cart to the loggedin partner and delete it.
diff --git a/shopinvader_api_signin_jwt/readme/ROADMAP.rst b/shopinvader_api_signin_jwt/readme/ROADMAP.rst
index 945ce1163b..0bb1134142 100644
--- a/shopinvader_api_signin_jwt/readme/ROADMAP.rst
+++ b/shopinvader_api_signin_jwt/readme/ROADMAP.rst
@@ -1,2 +1 @@
-* Manage anonymous cart (see https://github.com/shopinvader/odoo-shopinvader/issues/1428)
* Use ``fastapi_auth_jwt.auth_jwt_authenticated_odoo_env`` dependency for the env (see https://github.com/OCA/rest-framework/issues/406)
diff --git a/shopinvader_api_signin_jwt/routers/signin.py b/shopinvader_api_signin_jwt/routers/signin.py
index 0b9b688b40..723c8040a6 100644
--- a/shopinvader_api_signin_jwt/routers/signin.py
+++ b/shopinvader_api_signin_jwt/routers/signin.py
@@ -4,7 +4,7 @@
import logging
from typing import Annotated, Union
-from fastapi import APIRouter, Depends, Response, status
+from fastapi import APIRouter, Depends, Request, Response, status
from odoo import api, models
@@ -28,17 +28,28 @@ def signin(
partner: Annotated[Partner, Depends(auth_jwt_optionally_authenticated_partner)],
payload: Annotated[Payload, Depends(auth_jwt_authenticated_payload)],
response: Response,
+ request: Request,
) -> None:
"""
Authenticate the partner based on a JWT token or a session cookie.
Set the session cookie if allowed.
Return HTTP code 201 if res.partner created (case of the first signin).
+ Transfer anonymous cart and delete anonymous partner if any.
"""
if not partner:
- env[
+ partner = env[
"shopinvader_api_signin_jwt.signin_router.helper"
]._create_partner_from_payload(payload)
response.status_code = status.HTTP_201_CREATED
+ anonymous_partner = env["res.partner"]._get_anonymous_partner__cookie(
+ request.cookies
+ )
+ if anonymous_partner:
+ anonymous_cart = env["sale.order"].sudo()._find_open_cart(anonymous_partner.id)
+ if anonymous_cart:
+ anonymous_cart._transfer_cart(partner.id)
+ anonymous_cart.unlink()
+ env["res.partner"]._delete_anonymous_partner__cookie(request.cookies, response)
@signin_router.post("/signout")
diff --git a/shopinvader_api_signin_jwt/security/acl_res_partner.xml b/shopinvader_api_signin_jwt/security/acl_res_partner.xml
index 64f0f24fab..a41b91a5f8 100644
--- a/shopinvader_api_signin_jwt/security/acl_res_partner.xml
+++ b/shopinvader_api_signin_jwt/security/acl_res_partner.xml
@@ -9,7 +9,7 @@
This addon adds a web API to signin into the application and create a partner -if the email in the jwt payload is unknown.
+if the email in the jwt payload is unknown. +If we had an anonymous partner, transfer his cart to the loggedin partner and delete it.Table of contents