Skip to content

Commit

Permalink
feat(WIP): raw mappers implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
danh91 committed Jun 27, 2024
1 parent 4a390a2 commit 7b3f18e
Show file tree
Hide file tree
Showing 13 changed files with 584 additions and 121 deletions.
7 changes: 6 additions & 1 deletion modules/cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,17 @@ def add_features(
def create_tree(
module: str = typer.Option(..., prompt=True),
class_name: str = typer.Option(..., prompt=True),
module_alias: str = typer.Option("", prompt=False),
):
if not module or not class_name:
print("module and class_name are required")
raise typer.Abort()

output = utils.instantiate_class_from_module(module, class_name)
output = utils.instantiate_class_from_module(
module,
class_name,
module_alias=module_alias,
)
typer.echo(output)


Expand Down
38 changes: 28 additions & 10 deletions modules/cli/commands/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,7 @@
)

MAPPER_METADATA_TEMPLATE = Template(
"""
from karrio.core.metadata import Metadata
"""from karrio.core.metadata import Metadata
from karrio.mappers.{{id}}.mapper import Mapper
from karrio.mappers.{{id}}.proxy import Proxy
Expand Down Expand Up @@ -506,7 +505,10 @@ def create_manifest(self, request: lib.Serializable) -> lib.Deserializable[str]:
class Settings(provider_utils.Settings):
"""{{name}} connection settings."""
# required carrier specific properties
# Add carrier specific API connection properties here
# username: str
# passowrd: str
# account_number: str = None
# generic properties
id: str = None
Expand All @@ -520,7 +522,7 @@ class Settings(provider_utils.Settings):
)

PROVIDER_IMPORTS_TEMPLATE = Template(
"""
'''"""Karrio {{name}} provider imports."""
from karrio.providers.{{id}}.utils import Settings{% if "rating" in features %}
from karrio.providers.{{id}}.rate import parse_rate_response, rate_request{% endif %}{% if "shipping" in features %}
from karrio.providers.{{id}}.shipment import (
Expand Down Expand Up @@ -550,11 +552,12 @@ class Settings(provider_utils.Settings):
create_manifest_request,
){% endif %}
"""
'''
)

PROVIDER_ERROR_TEMPLATE = Template(
'''"""Karrio {{name}} error parser."""
import typing
import karrio.lib as lib
import karrio.core.models as models
Expand Down Expand Up @@ -583,7 +586,11 @@ def parse_error_response(
)

PROVIDER_RATE_TEMPLATE = Template(
"""
'''"""Karrio {{name}} rating API implementation."""
# import karrio.schemas.{{id}}.rating_request as {{id}}
# import karrio.schemas.{{id}}.rating_response as rating
import typing
import karrio.lib as lib
import karrio.core.units as units
Expand Down Expand Up @@ -642,11 +649,15 @@ def rate_request(
return lib.Serializable(request, {% if is_xml_api %}lib.to_xml{% else %}lib.to_dict{% endif %})
"""
'''
)

PROVIDER_TRACKING_TEMPLATE = Template(
"""
'''"""Karrio {{name}} rating API implementation."""
# import karrio.schemas.{{id}}.tracking_request as {{id}}
# import karrio.schemas.{{id}}.tracking_response as tracking
import typing
import karrio.lib as lib
import karrio.core.units as units
Expand Down Expand Up @@ -709,7 +720,7 @@ def tracking_request(
return lib.Serializable(request, {% if is_xml_api %}lib.to_xml{% else %}lib.to_dict{% endif %})
"""
'''
)

PROVIDER_UNITS_TEMPLATE = Template(
Expand Down Expand Up @@ -784,7 +795,10 @@ class TrackingStatus(lib.Enum):
class Settings(core.Settings):
"""{{name}} connection settings."""
# username: str # carrier specific api credential key
# Add carrier specific api connection properties here
# username: str
# passowrd: str
# account_number: str = None
@property
def carrier_name(self):
Expand All @@ -798,6 +812,10 @@ def server_url(self):
else "https://sandbox.carrier.api"
)
# @property
# def tracking_url(self):
# return "https://www.carrier.com/tracking?tracking-id={}"
'''
)

Expand Down
41 changes: 28 additions & 13 deletions modules/cli/commands/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import importlib
import pydoc
import importlib
import karrio.lib as lib


Expand Down Expand Up @@ -32,31 +32,46 @@ def format_dimension(code, dim):
)


def instantiate_tree(cls, indent=0):
tree = f"{cls.__name__}(\n"
def instantiate_tree(cls, indent=0, alias=""):
tree = f"{alias}{cls.__name__}(\n"
indent += 1
for name, typ in cls.__annotations__.items():
items = cls.__annotations__.items() if hasattr(cls, "__annotations__") else []

for name, typ in items:
if typ.__name__ == "Optional" and hasattr(typ, "__args__"):
typ = typ.__args__[0]
if typ.__name__ == "List" and hasattr(typ, "__args__"):
typ = typ.__args__[0]
if hasattr(typ, "__annotations__"):
tree += (
" " * indent * 4
+ f"{name}=[\n"
+ " " * (indent + 1) * 4
+ f"{instantiate_tree(typ, indent + 1, alias=alias)}\n"
+ " " * indent * 4
+ "],\n"
)
else:
tree += " " * indent * 4 + f"{name}=[],\n"
elif hasattr(typ, "__annotations__"):
tree += (
" " * indent * 4
+ f"{name}=[\n"
+ " " * indent * 5
+ f"{instantiate_tree(typ, indent + 1)}\n"
+ " " * indent * 4
+ "],\n"
+ f"{name}={instantiate_tree(typ, indent, alias=alias)},\n"
)
elif hasattr(typ, "__annotations__"):
tree += " " * indent * 4 + f"{name}={instantiate_tree(typ, indent)},\n"
else:
tree += " " * indent * 4 + f"{name}=None,\n"

tree += " " * (indent - 1) * 4 + ")"
return tree


def instantiate_class_from_module(module_name: str, class_name: str):
def instantiate_class_from_module(
module_name: str,
class_name: str,
module_alias: str = "",
):
module = importlib.import_module(module_name)
cls = getattr(module, class_name)
return instantiate_tree(cls)
alias = f"{module_alias}." if module_alias != "" else ""

return instantiate_tree(cls, alias=alias)
1 change: 1 addition & 0 deletions modules/connectors/mydhl/karrio/mappers/mydhl/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Settings(provider_utils.Settings):
username: str
password: str
api_key: str
account_number: str = None

# generic properties
id: str = None
Expand Down
2 changes: 0 additions & 2 deletions modules/connectors/mydhl/karrio/providers/mydhl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from karrio.providers.mydhl.utils import Settings
from karrio.providers.mydhl.rate import parse_rate_response, rate_request
from karrio.providers.mydhl.shipment import (
parse_shipment_cancel_response,
parse_shipment_response,
shipment_cancel_request,
shipment_request,
)
from karrio.providers.mydhl.pickup import (
Expand Down
117 changes: 109 additions & 8 deletions modules/connectors/mydhl/karrio/providers/mydhl/rate.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

import datetime
import karrio.schemas.mydhl.rating_request as mydhl
import karrio.schemas.mydhl.rating_response as rating
import typing
import karrio.lib as lib
import karrio.core.units as units
Expand All @@ -13,28 +15,50 @@ def parse_rate_response(
settings: provider_utils.Settings,
) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]:
response = _response.deserialize()
extra = dict(exchangeRate=response.get("exchangeRate", []))

messages = error.parse_error_response(response, settings)
rates = [_extract_details(rate, settings) for rate in response]
rates = [
_extract_details(rate, settings, extra=extra)
for rate in response.get("products", [])
]

return rates, messages


def _extract_details(
data: dict,
settings: provider_utils.Settings,
extra: typing.Optional[dict] = {},
) -> models.RateDetails:
rate = None # parse carrier rate type
rate = lib.to_object(rating.ProductType, data)
service = provider_units.ShippingService.map(rate.productCode)
total_price = lib.identity(rate.totalPrice[0].priceValue)
currency = lib.identity(
lib.failsafe(lambda: extra["exchangeRates"][0]["currency"])
or lib.failsafe(lambda: rate.totalPrice[0].priceCurrency)
or "EUR"
)

return models.RateDetails(
carrier_id=settings.carrier_id,
carrier_name=settings.carrier_name,
service="", # extract service from rate
total_charge=lib.to_money(0.0), # extract the rate total rate cost
currency="", # extract the rate pricing currency
service=service.name_or_key, # extract service from rate
total_charge=lib.to_money(total_price), # extract the rate total rate cost
currency=currency, # extract the rate pricing currency
transit_days=0, # extract the rate transit days
extra_charges=[
models.ChargeDetails(
name=charge.chargeType,
amount=lib.to_money(charge.priceValue),
currency=charge.priceCurrency,
)
for charge in rate.totalPrice[0].charges
],
meta=dict(
service_name="", # extract the rate service human readable name
service_name=rate.productName, # extract the rate service human readable name
pricingDate=rate.pricingDate,
**extra,
),
)

Expand All @@ -45,6 +69,7 @@ def rate_request(
) -> lib.Serializable:
shipper = lib.to_address(payload.shipper)
recipient = lib.to_address(payload.recipient)
billing_address = lib.to_address(payload.billing_address or shipper)
packages = lib.to_packages(payload.parcels)
services = lib.to_services(payload.services, provider_units.ShippingService)
options = lib.to_shipping_options(
Expand All @@ -53,6 +78,82 @@ def rate_request(
)

# map data to convert karrio model to mydhl specific type
request = None
request = mydhl.RatingRequestType(
customerDetails=mydhl.CustomerDetailsType(
shipperDetails=mydhl.ErDetailsType(
postalCode=shipper.postal_code,
cityName=shipper.city,
addressLine1=shipper.address_line1,
addressLine2=shipper.address_line2,
countryCode=shipper.country_code,
addressLine3=None,
),
receiverDetails=mydhl.ErDetailsType(
postalCode=recipient.postal_code,
cityName=recipient.city,
addressLine1=recipient.address_line1,
addressLine2=recipient.address_line2,
countryCode=recipient.country_code,
addressLine3=None,
),
),
accounts=[
mydhl.AccountType(
typeCode="shipper",
number=settings.account_number,
)
],
productsAndServices=[
mydhl.ProductsAndServiceType(
productCode=service.code,
localProductCode=None,
)
for service in services
],
payerCountryCode=billing_address.country_code,
plannedShippingDateAndTime=lib.fdatetime(
options.shipment_date.state or datetime.datetime.now(),
current_format="%Y-%m-%d",
output_format="%Y-%m-%dT%H:%M:%SGMT%z",
),
unitOfMeasurement="metric",
isCustomsDeclarable=not packages.is_document,
monetaryAmount=(
[
mydhl.MonetaryAmountType(
typeCode="declaredValue",
value=options.declared_value.amount,
currency=options.currency.state or "EUR",
)
]
if options.declared_value.state
else []
),
estimatedDeliveryDate=mydhl.EstimatedDeliveryDateType(
isRequested=True,
typeCode="QDDC",
),
getAdditionalInformation=[
mydhl.EstimatedDeliveryDateType(
isRequested=True,
typeCode="allValueAddedServices",
)
],
returnStandardProductsOnly=False,
nextBusinessDay=True,
productTypeCode="all",
packages=[
mydhl.PackageType(
typeCode=provider_units.PackagingType.map(package.packaging).value,
weight=package.weight.KG,
dimensions=mydhl.DimensionsType(
length=package.length.CM,
width=package.width.CM,
height=package.height.CM,
),
)
for package in packages
],
)

return lib.Serializable(request, lib.to_dict)
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@

from karrio.providers.mydhl.shipment.create import (
parse_shipment_response,
shipment_request,
)
from karrio.providers.mydhl.shipment.cancel import (
parse_shipment_cancel_response,
shipment_cancel_request,
)
Loading

0 comments on commit 7b3f18e

Please sign in to comment.