ernadoo/mondial-relay
Framework-agnostic PHP client for Mondial Relay: create shipment labels via the V2 REST API and search relay points via the V1 SOAP API. Supports sandbox testing, tracking URLs, and label PDFs.
MondialRelayClient, RestShipmentClient, and SoapParcelShopClient remain the integration seams, while ParcelShopSearchRequest::around($countryCode, $latitude, $longitude) and the new latitude/longitude arguments let a TPM support map/geolocation relay-point pickers as well as postcode search. ParcelShop::schedule() with OpeningHours (on($isoDay), isOpenOn(), isAlwaysOpen(), isEmpty()) removes ad hoc parsing of "0930-1300 1400-1900", and ParcelShop::$locker / $directions let the UI distinguish lockers from staffed counters and show access instructions. PSR-3 logging and the shared MondialRelayException hierarchy are unchanged.openingHours raw values, and all v4.1.0 credential names (apiLogin, apiPassword, brandCode, privateKey) are untouched, so the v4.1.0 named-argument migration remains the only outstanding breaking change to manage. New behaviour is opt-in: teams can adopt coordinate search, schedule(), locker, and directions independently. Note that local validation now rejects a request with no postcode and no coordinates, a single coordinate, or out-of-range coordinates via \InvalidArgumentException before the remote call — this replaces an API-side rejection, so error handling paths shift from ApiException to a local exception.\InvalidArgumentException is not part of the MondialRelayException hierarchy, so catch blocks built around configuration/transport/API failures will not intercept it — map it to a form-validation error instead; (2) schedule() introduces day-of-week semantics via ISO days, so display must be timezone- and locale-aware, and isEmpty()/isAlwaysOpen() must be handled explicitly rather than treated as parse failures. locker and directions are optional/nullable and must not be assumed present. Existing risks persist: external API/network dependency, getErrors() integer keys for numeric codes, and app-side log/PII review.\InvalidArgumentException be caught and surfaced in the search form? How will opening hours be rendered across timezones and locales, and is schedule() the only consumer or does any downstream system read raw openingHours? Do we surface locker vs pickup-point filtering, and are directions safe to display verbatim? Are composer PHP/Laravel constraints still satisfied? Are production credentials and brand activation confirmed with sandbox parity for the new coordinate path? How will label creation be queued, retried, and made idempotent? Is relay-point search cached, and by what key (postcode, coordinate grid)? Are TransportException retries and alerts defined?setLogger(), binding shipping clients in the container and wrapping calls in a domain service. Continue using ConfigurationException for deploy/config failures, TransportException for transient/infrastructure failures, and ApiException for business/validation rejections; add \InvalidArgumentException as an input-validation failure at the controller/form-request boundary. Relay-point search (postcode or coordinates) belongs in checkout; label creation belongs in order fulfilment and may be queued. A small presenter/view-model around ParcelShop (schedule(), locker, directions) keeps Blade/Inertia templates free of Mondial Relay vocabulary.openingHours retains raw values, so existing parsers keep working alongside schedule(). New arguments are additions to ParcelShopSearchRequest; positional callers of existing constructors are unaffected, but new optional arguments should be passed by name to avoid re-auditing later. Confirm composer constraints for PHP/Laravel, and verify framework auto-discovery/config publishing still behaves. \InvalidArgumentException is a new failure surface for callers that previously relied on ApiException for malformed searches.\InvalidArgumentException into the validation error path; 5) build the ParcelShop presenter for schedule(), locker, directions; 6) run sandbox tests for postcode search, coordinate search, and labels; 7) deploy to staging with monitored real credentials; 8) canary the new search mode and relay-point rendering; 9) monitor rejection, warning, transport, and local-validation rates.isEmpty()/isAlwaysOpen() and null locker/directions cases so upstream parsing changes are caught early.schedule() reduces "opening hours look wrong" tickets caused by bespoke string parsing, and locker lets support explain failed collections at unattended points. Keep the existing exception taxonomy triage (ConfigurationException = config, TransportException = infrastructure, ApiException = Mondial Relay rejection) and add a distinct bucket for local \InvalidArgumentException so malformed search input is not misrouted to the API-failure queue. Logging rules are unchanged: no credentials or bodies, retained and access-controlled, with error-code translation covering integer keys.TransportException. Info-level shipment/search logging may grow if coordinate search is used interactively; tune log levels and avoid logging precise coordinates without a privacy review.\InvalidArgumentException for missing/partial/out-of-range coordinates must be caught and rendered as a validation message, not a generic error page. ConfigurationException still fails fast before the remote call; TransportException means retry/alert; ApiException means validation/business rejection; warnings log but do not block. Test the boundary between "no postcode" and "no coordinates", the single-coordinate case, out-of-range values, empty schedules, always-open points, and shops without directions. Sandbox/prod differences, timeout behaviour, and PDF retrieval failures remain in scope. Monitor API rejection codes, local validation error rate, transport error rate, and label creation success.ParcelShop presenter, before committing to delivery dates.How can I help you explore Laravel packages today?