Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[14.0] [ADD] shopinvader unit management (members and request) #1512

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# generated from manifests external_dependencies
cerberus
extendable_pydantic>=1.0.0
fastapi
locomotivecms
pydantic>=2.0.0
python-magic
python-slugify
python-stdnum
Expand Down
6 changes: 6 additions & 0 deletions setup/shopinvader_api_unit_member/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
6 changes: 6 additions & 0 deletions setup/shopinvader_api_unit_request/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
6 changes: 6 additions & 0 deletions setup/shopinvader_unit_management/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
2 changes: 2 additions & 0 deletions shopinvader_api_unit_member/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import routers
from . import schemas
27 changes: 27 additions & 0 deletions shopinvader_api_unit_member/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2024 Akretion (http://www.akretion.com).
# @author Florian Mounier <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Shopinvader Api Unit Member",
"summary": "This module adds a service to shopinvader to manage units members: "
"managers and collaborators.",
"version": "16.0.1.0.0",
"license": "AGPL-3",
"author": "Akretion",
"website": "https://github.com/shopinvader/odoo-shopinvader",
"depends": [
"extendable",
"extendable_fastapi",
"fastapi",
"shopinvader_unit_management",
],
"data": [
"security/res_groups.xml",
"security/res_partner.xml",
],
"external_dependencies": {
"python": ["fastapi", "extendable_pydantic>=1.0.0", "pydantic>=2.0.0"]
},
"installable": True,
}
1 change: 1 addition & 0 deletions shopinvader_api_unit_member/routers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .unit_members import unit_member_router
88 changes: 88 additions & 0 deletions shopinvader_api_unit_member/routers/unit_members.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Copyright 2024 Akretion (http://www.akretion.com).
# @author Florian Mounier <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from typing import Annotated, List

from fastapi import APIRouter, Depends

from odoo import _
from odoo.exceptions import AccessError

from odoo.addons.base.models.res_partner import Partner as ResPartner
from odoo.addons.fastapi.dependencies import authenticated_partner

from ..schemas import UnitMember, UnitMemberCreate, UnitMemberUpdate

# create a router
unit_member_router = APIRouter(tags=["unit"])


def authenticated_manager(
partner: Annotated[ResPartner, Depends(authenticated_partner)],
) -> ResPartner:
if partner.unit_profile != "manager":
raise AccessError(_("Only a manager can perform this action."))
return partner


@unit_member_router.get("/unit/members")
async def get_unit_members(
partner: Annotated[ResPartner, Depends(authenticated_manager)],
) -> List[UnitMember]:
"""
Get list of unit members
"""
members = partner._get_shopinvader_unit_members()
return [UnitMember.from_res_partner(rec) for rec in members]


@unit_member_router.get("/unit/members/{id}")
async def get_unit_member(
partner: Annotated[ResPartner, Depends(authenticated_manager)],
id: int,
) -> UnitMember:
"""
Get a specific unit member
"""
member = partner._get_shopinvader_unit_member(id)
return UnitMember.from_res_partner(member)


@unit_member_router.post("/unit/members", status_code=201)
async def create_unit_member(
data: UnitMemberCreate,
partner: Annotated[ResPartner, Depends(authenticated_manager)],
) -> UnitMember:
"""
Create a new unit member (manager or collaborator) as manager
"""
vals = data.to_res_partner_vals()
member = partner._create_shopinvader_unit_member(vals)
return UnitMember.from_res_partner(member)


@unit_member_router.post("/unit/members/{id}")
async def update_unit_member(
data: UnitMemberUpdate,
partner: Annotated[ResPartner, Depends(authenticated_manager)],
id: int,
) -> UnitMember:
"""
Update a specific unit member (manager or collaborator) as manager
"""
vals = data.to_res_partner_vals()
member = partner._update_shopinvader_unit_member(id, vals)
return UnitMember.from_res_partner(member)


@unit_member_router.delete("/unit/members/{id}")
async def delete_unit_member(
partner: Annotated[ResPartner, Depends(authenticated_manager)],
id: int,
) -> UnitMember:
"""
Delete a specific unit member (manager or collaborator) as manager
"""
member = partner._delete_shopinvader_unit_member(id)
return UnitMember.from_res_partner(member)
89 changes: 89 additions & 0 deletions shopinvader_api_unit_member/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Copyright 2024 Akretion (http://www.akretion.com).
# @author Florian Mounier <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from extendable_pydantic import StrictExtendableBaseModel


class UnitMember(StrictExtendableBaseModel):
id: int
name: str | None = None
street: str | None = None
street2: str | None = None
zip: str | None = None
city: str | None = None
phone: str | None = None
email: str | None = None
state_id: int | None = None
country_id: int | None = None

@classmethod
def from_res_partner(cls, odoo_rec):
return cls.model_construct(
id=odoo_rec.id,
name=odoo_rec.name or None,
street=odoo_rec.street or None,
street2=odoo_rec.street2 or None,
zip=odoo_rec.zip or None,
city=odoo_rec.city or None,
phone=odoo_rec.phone or None,
email=odoo_rec.email or None,
state_id=odoo_rec.state_id.id or None,
country_id=odoo_rec.country_id.id or None,
)


class UnitMemberCreate(StrictExtendableBaseModel, extra="ignore"):
type: str | None = "collaborator"
name: str | None = None
street: str | None = None
street2: str | None = None
zip: str | None = None
city: str | None = None
phone: str | None = None
email: str | None = None
state_id: int | None = None
country_id: int | None = None

def to_res_partner_vals(self) -> dict:
vals = {
"unit_profile": self.type,
"name": self.name,
"street": self.street,
"street2": self.street2,
"zip": self.zip,
"city": self.city,
"phone": self.phone,
"email": self.email,
"state_id": self.state_id,
"country_id": self.country_id,
}

return vals


class UnitMemberUpdate(StrictExtendableBaseModel, extra="ignore"):
name: str | None = None
street: str | None = None
street2: str | None = None
zip: str | None = None
city: str | None = None
phone: str | None = None
email: str | None = None
state_id: int | None = None
country_id: int | None = None

def to_res_partner_vals(self) -> dict:
fields = [
"name",
"street",
"street2",
"zip",
"city",
"phone",
"email",
"state_id",
"country_id",
]
values = self.model_dump(exclude_unset=True)
return {f: values[f] for f in fields if f in values}
19 changes: 19 additions & 0 deletions shopinvader_api_unit_member/security/res_groups.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2024 Akretion (http://www.akretion.com).
@author Florian Mounier <[email protected]>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="shopinvader_unit_management_user_group" model="res.groups">
<field name="name">Shopinvader Unit Management user</field>
<field
name="implied_ids"
eval="[
(4, ref('fastapi.group_fastapi_endpoint_runner')),
]"
/>

</record>

</odoo>
33 changes: 33 additions & 0 deletions shopinvader_api_unit_member/security/res_partner.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2024 Akretion (http://www.akretion.com).
@author Florian Mounier <[email protected]>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="shopinvader_unit_management_res_partner_rule" model="ir.rule">
<field
name="name"
>Shopinvader Unit Management Endpoint rule: res partner</field>
<field name="model_id" ref="base.model_res_partner" />
<field
name="groups"
eval="[(4, ref('shopinvader_api_unit_member.shopinvader_unit_management_user_group'))]"
/>
<field name="domain_force">[('parent_id','=',authenticated_partner_id)]</field>

</record>

<record id="shopinvader_unit_management_res_partner_access" model="ir.model.access">
<field
name="name"
>Shopinvader Unit Management: user read/write/create partners</field>
<field name="model_id" ref="base.model_res_partner" />
<field name="group_id" ref="shopinvader_unit_management_user_group" />
<field name="perm_read" eval="True" />
<field name="perm_write" eval="True" />
<field name="perm_create" eval="True" />
<field name="perm_unlink" eval="False" />
</record>

</odoo>
1 change: 1 addition & 0 deletions shopinvader_api_unit_member/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_shopinvader_api_unit_members
Loading
Loading