Skip to content

Commit

Permalink
[16.0][MIG] shopinvader_delivery_pickup: Migration to 16.0 (FastAPI)
Browse files Browse the repository at this point in the history
  • Loading branch information
chafique-delli committed May 17, 2024
1 parent 2f9264a commit 6170e7f
Show file tree
Hide file tree
Showing 35 changed files with 979 additions and 411 deletions.
2 changes: 2 additions & 0 deletions setup/.setuptools-odoo-make-default-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# addons listed in this file are ignored by
# setuptools-odoo-make-default (one addon per line)
2 changes: 2 additions & 0 deletions setup/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
To learn more about this directory, please visit
https://pypi.python.org/pypi/setuptools-odoo
6 changes: 6 additions & 0 deletions setup/shopinvader_api_delivery_pickup/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,
)
80 changes: 80 additions & 0 deletions shopinvader_api_delivery_pickup/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
===========================
Shopinvader Delivery Pickup
===========================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:d1c0d9ae60c51081ab91a8e029129c55cea1cc48162865c0fa7ae2bee91e9c05
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-shopinvader%2Fodoo--shopinvader--carrier-lightgray.png?logo=github
:target: https://github.com/shopinvader/odoo-shopinvader-carrier/tree/16.0/shopinvader_api_delivery_pickup
:alt: shopinvader/odoo-shopinvader-carrier

|badge1| |badge2| |badge3|

Expose pickup sites to shopinvader API

**Table of contents**

.. contents::
:local:

Known issues / Roadmap
======================

For now the module only implement a fastapi for setting the dropoffsite.

TODO:
- add the possibility to search a dropoff_site with geo location

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/shopinvader/odoo-shopinvader-carrier/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/shopinvader/odoo-shopinvader-carrier/issues/new?body=module:%20shopinvader_api_delivery_pickup%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Akretion
* ACSONE SA/NV

Contributors
~~~~~~~~~~~~

* Sebastien BEAU <[email protected]>
* Laurent Mignon <[email protected]>
* Raphaël Reverdy <[email protected]>
* Chafique DELLI <[email protected]>

Other credits
~~~~~~~~~~~~~

The development of this module has been financially supported by:

* Akretion
* ACSONE SA/NV

Maintainers
~~~~~~~~~~~

This module is part of the `shopinvader/odoo-shopinvader-carrier <https://github.com/shopinvader/odoo-shopinvader-carrier/tree/16.0/shopinvader_api_delivery_pickup>`_ project on GitHub.

You are welcome to contribute.
1 change: 1 addition & 0 deletions shopinvader_api_delivery_pickup/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import routers
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
# Copyright 2019 Akretion (http://www.akretion.com)
# Copyright 2019-2024 Akretion (http://www.akretion.com)
# Sébastien BEAU <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
"name": "Shopinvader Delivery pickup",
"name": "Shopinvader Delivery Pickup",
"summary": "Allows to deliver sale order to pickup site",
"version": "12.0.1.0.0",
"version": "16.0.1.0.0",
"category": "e-commerce",
"website": "https://github.com/shopinvader/odoo-shopinvader-carrier",
"author": "Akretion, ACSONE SA/NV",
"license": "AGPL-3",
"application": False,
"installable": True,
"external_dependencies": {"python": [], "bin": []},
"depends": ["shopinvader_delivery_carrier", "delivery_dropoff_site"],
"data": [],
"depends": ["shopinvader_api_delivery_carrier", "delivery_dropoff_site"],
"data": [
"security/acl_delivery_pickup.xml",
"security/groups.xml",
],
"demo": [],
"qweb": [],
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
* Sebastien BEAU <[email protected]>
* Laurent Mignon <[email protected]>
* Raphaël Reverdy <[email protected]>
* Chafique DELLI <[email protected]>
4 changes: 4 additions & 0 deletions shopinvader_api_delivery_pickup/readme/ROADMAP.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
For now the module only implement a fastapi for setting the dropoffsite.

TODO:
- add the possibility to search a dropoff_site with geo location
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from . import abstract_sale
from . import cart
from . import delivery_pickup
from . import delivery_carrier
82 changes: 82 additions & 0 deletions shopinvader_api_delivery_pickup/routers/cart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright 2019 Akretion (http://www.akretion.com).
# @author Sébastien BEAU <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from typing import Annotated

from fastapi import Depends

from odoo import _, api, models
from odoo.exceptions import UserError

from odoo.addons.base.models.res_partner import Partner as ResPartner
from odoo.addons.fastapi.dependencies import (
authenticated_partner,
authenticated_partner_env,
)
from odoo.addons.sale.models.sale_order import SaleOrder
from odoo.addons.shopinvader_api_cart.routers import cart_router
from odoo.addons.shopinvader_api_cart.schemas import CartTransaction
from odoo.addons.shopinvader_schema_sale.schemas import Sale

from ..schemas import DeliveryPickupInput


@cart_router.post("/set_delivery_pickup")
@cart_router.post("/{uuid}/set_delivery_pickup")
@cart_router.post("/current/set_delivery_pickup")
def set_delivery_pickup(
env: Annotated[api.Environment, Depends(authenticated_partner_env)],
partner: Annotated["ResPartner", Depends(authenticated_partner)],
data: DeliveryPickupInput,
uuid: str | None = None,
) -> Sale | None:
"""
If cart is found, set the pickup site on it.
"""
cart = env["sale.order"]._find_open_cart(partner.id, uuid)
if not cart:
raise UserError(_("There is no cart"))
env["shopinvader_api_cart.cart_router.helper"]._set_delivery_pickup(cart, data)
return Sale.from_sale_order(cart) if cart else None


class ShopinvaderApiCartRouterHelper(models.AbstractModel):
_inherit = "shopinvader_api_cart.cart_router.helper"

# Set delivery pickup
@api.model
def _set_delivery_pickup(self, cart, data):
pickup_site_id = data.pickup_site_id
pickup_site_obj = self.env["dropoff.site"]
pickup_site = pickup_site_obj.search([("id", "=", pickup_site_id.id)])
if not pickup_site:
raise UserError(_("Invalid code for pickup site"))
self._set_carrier(cart, pickup_site)
vals = {"partner_shipping_id": pickup_site.partner_id.id}
if not cart.final_shipping_partner_id:
vals["final_shipping_partner_id"] = cart.partner_shipping_id.id
cart.sudo().write(vals)

@api.model
def _reset_delivery_pickup(self, cart):
if cart.final_shipping_partner_id:
cart.partner_shipping_id = cart.final_shipping_partner_id
cart.final_shipping_partner_id = None

@api.model
def _set_carrier(self, cart, data):
self._reset_delivery_pickup(cart)
return super()._set_carrier(cart, data)

@api.model
def _sync_cart(
self,
partner: ResPartner,
cart: SaleOrder,
uuid: str,
transactions: list[CartTransaction],
):
cart = super()._sync_cart(partner, cart, uuid, transactions)
if transactions:
self._reset_delivery_pickup(cart)
return cart
13 changes: 13 additions & 0 deletions shopinvader_api_delivery_pickup/routers/delivery_carrier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, models


class ShopinvaderApiDeliveryRouterHelper(models.AbstractModel):
_inherit = "shopinvader_api_delivery_carrier.delivery_carrier_router.helper"

@api.model
def _available_carriers(self, cart):
available_carriers = super()._available_carriers(cart)
return available_carriers.filtered(lambda c: c.with_dropoff_site)
74 changes: 74 additions & 0 deletions shopinvader_api_delivery_pickup/routers/delivery_pickup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright 2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from typing import Annotated

from fastapi import APIRouter, Depends

from odoo import api, models
from odoo.osv.expression import FALSE_DOMAIN

from odoo.addons.base.models.res_partner import Partner as ResPartner
from odoo.addons.delivery_dropoff_site.models.dropoff_site import DropoffSite
from odoo.addons.fastapi.dependencies import (
authenticated_partner,
authenticated_partner_env,
)

from ..schemas import DeliveryPickup as DeliveryPickupSchema, DeliveryPickupSearch

delivery_pickup_router = APIRouter(tags=["delivery_pickups"])


@delivery_pickup_router.get("/delivery_pickups")
def search(
data: Annotated[DeliveryPickupSearch, Depends()],
env: Annotated[api.Environment, Depends(authenticated_partner_env)],
partner: Annotated[ResPartner, Depends(authenticated_partner)],
) -> list[DeliveryPickupSchema]:
"""
Returns the list of all available pickup sites.
If cart, the list will be limited to the
pickup sites linked to carriers applying to the current cart.
If you don't provide a carrier_id, the service will return all the
pickup sites linked to carriers available for this site.
If you provide a carrier_id, only the pickup sites linked to the given
carrier are returned except if the carrier is not available for this
site.
"""
delivery_pickups = (
env["shopinvader_api_delivery_pickup.delivery_pickup_router.helper"]
.new({"partner": partner})
._search(data, cart=None)
)
return [
DeliveryPickupSchema.from_delivery_pickup(delivery_pickup)
for delivery_pickup in delivery_pickups
]


class ShopinvaderApiDeliveryRouterHelper(models.AbstractModel):
_name = "shopinvader_api_delivery_pickup.delivery_pickup_router.helper"
_description = "ShopInvader API Delivery Pickup Router Helper"

def _search(self, params, cart=None) -> DropoffSite:
"""
Search for delivery pickup sites
:return: a list of dropoff.site
"""
cart.ensure_one()
if cart and cart.shopinvader_available_carrier_ids:
available_carriers = cart.shopinvader_available_carrier_ids
domain = self._get_domain_dropoff_site(params, available_carriers)
return self.env["dropoff.site"].search(domain)
return self.env["dropoff.site"].search([])

def _get_domain_dropoff_site(self, params, available_carriers):
carrier_id = params.carrier_id
if carrier_id:
if carrier_id not in available_carriers.ids:
return FALSE_DOMAIN
return [("carrier_id", "=", carrier_id)]
return [("carrier_id", "in", available_carriers.ids)]
2 changes: 2 additions & 0 deletions shopinvader_api_delivery_pickup/schemas/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import delivery_pickup
from . import resource_calendar_attendance
78 changes: 78 additions & 0 deletions shopinvader_api_delivery_pickup/schemas/delivery_pickup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Copyright 2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from typing import Annotated, Field, List

from extendable_pydantic import StrictExtendableBaseModel

from odoo import api

from ..schemas import ResourceCalendarAttendance


class DeliveryPickupInput(StrictExtendableBaseModel):
pickup_site_id: int


class DeliveryPickupSearch(StrictExtendableBaseModel):
name: Annotated[
str | None,
Field(
description="When used, the search look for any delivery pickup where name "
"contains the given value case insensitively."
),
] = None
carrier_id: Annotated[
int | None,
Field(
description="When used, the search look for any delivery pickup where carrier "
"contains the given value case insensitively."
),
] = None

def to_odoo_domain(self, env: api.Environment):
domain = []
if self.name:
domain.append(("name", "ilike", self.name))
if self.carrier_id:
domain.append(("carrier_id", "ilike", self.carrier_id.id))
return domain


class DeliveryPickup(StrictExtendableBaseModel):
id: int
name: str
code: str | None = None
partner_id: int
street: str | None = None
street2: str | None = None
zip: str | None = None
city: str | None = None
phone: str | None = None
state_id: int | None = None
country_id: int
carrier_id: int
calendar_id: int | None = None
attendance_ids: List[ResourceCalendarAttendance] | None = None

@classmethod
def from_delivery_pickup(cls, odoo_rec):
return cls.model_construct(
id=odoo_rec.id,
name=odoo_rec.name,
code=odoo_rec.code or None,
partner_id=odoo_rec.partner_id.id,
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,
state_id=odoo_rec.state_id.id or None,
country_id=odoo_rec.country_id.id,
carrier_id=odoo_rec.carrier_id.id,
calendar_id=odoo_rec.calendar_id.id or None,
attendance_ids=[
ResourceCalendarAttendance.from_resource_calendar_attendance(attendance)
for attendance in odoo_rec.attendance_ids
]
or None,
)
Loading

0 comments on commit 6170e7f

Please sign in to comment.