Skip to content

Refactore roulier to be able to choose between multiple implementation for one carrier #140

@florian-dacosta

Description

@florian-dacosta

For some carrier, we may want to manage different services/implementation.
Gls France for instance propose multiple solutions, like GLS-BOX, which return zpl, or GLS Web API.
Laposte fr also have multiple solutions (SOAP XML, the current implementation, or a REST API, not implemented yet)
DPD is also changing its api, the current one should be abandoned soon, etc...

It seems it could be quite usefull to ba able to choose among mulltipe implementation of a service/action.
For example to enjoy new functionalities or during the transition from one system to another, etc...

We currently have the case for GLS, where present implementation is the GLS-BOX and we want to also implementent the GLS Web API one : #138.

Since one carrier may have a propose different solution depending on the country (typlically, the implemented GLS-BOX is only for France and won't work for other countries), we had previously decided to add a suffix depending the country to be able to manage the carrier in multiple countries.
So, the gls_eu carrier type proposed in #138 is really confusing (unless it work for multiple european countries, but I doubt it..not sure though.

I'd like then to introduce a system allowing to choose between 2 implementation, while having a default one (so the user that do not care about which implementation is used to get a label don't need to care about that).

For this, we could modify the factory sytem to have something like that :

class RoulierFactory(object):
    def __init__(self):
        self._carrier_action = {}

    def register_builder(self, carrier_type, action, Carrierclass, ttype="default"):
        self._carrier_action[(carrier_type, action)] = {ttype: Carrierclass}

    def get(self, carrier_type, action, ttype="default, **kwargs):
        carrierclass = self._carrier_action.get((carrier_type, action), {}).get(ttype)
        if not carrierclass:
            raise ValueError((carrier_type, action))
        return carrierclass(carrier_type, action, **kwargs)

def get(carrier_type, action, *args, **kwargs):
    carrier_obj = factory.get(carrier_type, action)
    ttype = kwargs.pop('ttype', 'default')
    return getattr(carrier_obj, action)(carrier_type, action, *args, **kwargs)

And on carrier side :

class GlsFrBoxGetLabel(CarrierGetLabel):
...

factory.register_builder("gls_fr", "get_label", GlsFrBoxGetLabel, ttype="gls-box")

class GlsWebGetLabel(CarrierGetLabel):
...

factory.register_builder("gls_fr", "get_label", GlsWebGetLabel)

This way, calling roulier.get('gls_fr', 'get_label', payload) will return a gls label using the WEB api
and calling roulier.get('gls_fr', 'get_label', payload, ttype="gls-box") will return a gls label using the GLS-BOX solution.

Any comment about such a change ?
@DylannCordel I'd appreciate your opinion about this

cc @hparfr @bealdav

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions