laravel-geis maintained by beziworld
Laravel Geis
Laravel client for the Geis GService REST API, the integration interface of Geis Polska (also Geis CZ and Geis SK):
- expeditions (shipments from your warehouse) and orders (collection from a third party) through a typed, validating builder
- pallets and other packing types, sub-items, COD, insurance, SMS and phone notifications, B2B / HDS / HDP categories
- labels (PDF, PDFO, ZPL, EPL, BMP) and the pickup list (handover protocol)
- pickups: creation and the list of pickups planned for a day
- tracking: latest status of up to 200 shipments per call and the full Track and Trace record per shipment
- deleting shipments, own number ranges, routing table and delivery routing for self-printed labels
- dictionaries: additional services, packing types, statuses, currencies
- multiple accounts and instances (pl, cz, sk), runtime credentials,
php artisan geis:check
Why this package
Packagist has no client for the Geis REST API and nothing for Geis Polska: the only Geis packages are a generated SOAP
client for the Czech service (goetas-webservices/geis-group-cz-client) and a GeisPoint pickup point client
(ondrejd/geis-point-service). The GService manual (v6.2) recommends REST for new integrations; this package follows
the public OpenAPI document of the Polish test instance, validates the schema rules before sending and handles the
documented limits (200 shipments per call, call limits per method, HTTP 429).
Installation
composer require beziworld/laravel-geis
php artisan vendor:publish --tag=geis-config # optional
GEIS_CUSTOMER_CODE=... # customer code and password from your Geis business manager
GEIS_PASSWORD=...
GEIS_COUNTRY=pl # pl, cz or sk
GEIS_SANDBOX=false # true = gservicetest.geis.pl (separate credentials)
GEIS_LABEL_FORMAT=PDF # PDF, PDFO, ZPL, EPL, BMP
GEIS_SENDER_NAME="ACME Sp. z o.o." # default collection address of orders
GEIS_SENDER_STREET="ul. Prosta 1"
GEIS_SENDER_CITY=Warszawa
GEIS_SENDER_ZIP_CODE=00-001
GEIS_SENDER_CONTACT_NAME="Jan Nowak"
GEIS_SENDER_CONTACT_PHONE="+48 500 600 700"
GEIS_SENDER_CONTACT_EMAIL=magazyn@example.com
Check the credentials and see your packing types and services:
php artisan geis:check --country=PL
Expeditions
An expedition leaves from the address of your customer account. A pickup must exist for the pickup date (Geis may
create it automatically; otherwise use createPickup()).
use Beziworld\Geis\Data\Address;
use Beziworld\Geis\Data\Contact;
use Beziworld\Geis\Facades\Geis;
$created = Geis::expedition()
->to(
new Address('Hurtownia Kowalski', 'ul. Długa 5', 'Kraków', '30-001'),
new Contact('Anna Kowalska', '+48 600 700 800', 'anna@example.com'),
)
->pickupDate(now())
->units('FP', weight: 150, count: 1, description: 'Books', length: 1.2, width: 0.8, height: 1.5) // metres
->units('HP', weight: 80)
->cashOnDelivery('1499.90', 'PLN', variableSymbol: '20261105', iban: 'PL61 1090 1014 0000 0712 1981 2874')
->insurance(2000, 'PLN')
->sms('+48 600 700 800')
->reference('ORDER-1')
->send();
$created->packNumber; // 13-digit shipment number
homeDelivery() sets the HDS category, personalPickup() and exWorks() set the matching flags and
shipmentNumber() uses a number from your own range (assignRange()). Packing type codes (FP, HP, ...) come
from Geis::packingTypes(); services enabled for a destination from Geis::services('DE').
Orders
An order is collected from another address, at the earliest on the next business day. The configured sender is the default collection address.
Geis::order()
->from(new Address('Supplier', 'ul. Fabryczna 2', 'Łódź', '90-001'), new Contact('Piotr', '+48 601 000 000'))
->to(new Address('ACME Sp. z o.o.', 'ul. Prosta 1', 'Warszawa', '00-001'))
->pickupDate(now()->addWeekday())
->units('FP', weight: 300, count: 2)
->totals(weight: 300, volume: 1.5)
->send();
build() returns the validated Shipment without sending it; pass it to Geis::create() later.
Labels and pickup list
use Beziworld\Geis\Enums\LabelFormat;
$labels = Geis::labels(['1234567890123', '9876543210987']); // configured format, PDF position 1
$labels = Geis::labels('1234567890123', LabelFormat::Zpl, resolution: 300);
Storage::put($labels[0]->filename(), $labels[0]->content); // label-1234567890123.pdf
$list = Geis::pickupList(now()); // handover protocol (PDF) for all expeditions of the day
Labels are available for expeditions created through the API.
Pickups
use Beziworld\Geis\Data\PickupItem;
use Beziworld\Geis\Data\PickupRequest;
Geis::createPickup(new PickupRequest(
date: now(), // same day only until 10:00
contact: new Contact('Jan Nowak', '+48 500 600 700', 'magazyn@example.com'),
count: 3,
totalWeight: 420,
items: [new PickupItem('FP', 3, 420)],
));
Geis::pickups(now(), isOrder: false); // pickups planned for the day
Tracking
$status = Geis::status('1234567890123'); // latest status: code and name
$statuses = Geis::statuses($numbers); // any number of shipments, 200 per request
$detail = Geis::track('1234567890123');
$detail->latest()?->name;
foreach ($detail->history as $event) {
$event->occurredAt; $event->code; $event->name; $event->depot;
}
$detail->colli('123456789012301'); // events of one handling unit
$detail->services; // charged services with decimal string prices
Geis::trackBy(reference: 'ORDER-1');
Geis::shipments(pickupDate: now()); // what was created for a day
Deleting shipments
foreach (Geis::delete(['1234567890123']) as $result) {
$result->deleted; // false when the shipment already has an operational status
$result->errorMessage;
}
Multiple accounts
// config/geis.php
'connections' => [
'default' => [],
'cz' => ['customer_code' => env('GEIS_CZ_CUSTOMER_CODE'), 'password' => env('GEIS_CZ_PASSWORD'), 'country' => 'cz'],
],
Geis::connection('cz')->statuses($numbers);
Geis::using(['customer_code' => $tenant->geis_code, 'password' => $tenant->geis_password])->packingTypes();
Errors
| Exception | When |
|---|---|
InvalidShipment |
A schema rule is broken; nothing is sent. |
ApiException |
HTTP 400, 404, 409, 415 or 5xx: errorCode() (for example 2000, 2003, 2015, 2096), apiMessage(), httpStatus(). |
AuthenticationFailed |
HTTP 401. |
RateLimited |
HTTP 429 (error 2064); retryAfter() when the service sends Retry-After. |
ConnectionFailed |
The service cannot be reached. Reads are retried first (GEIS_READ_RETRIES, default 2). |
InvalidConfiguration |
Missing credentials, unsupported country or label settings, unknown connection. |
All exceptions extend GeisException. Creating shipments, pickups, number ranges and deletions is never retried; after
a timeout check Geis::shipments() before sending again. Any endpoint can be called with
Geis::request('GET', '/api/Status', read: true).
Notes
- Before going live Geis requires integration testing on the test instance and approval of sample labels and pickup lists by the business manager.
- The REST API has no price calculation;
ShipmentDetail::$servicesshows charged services after the fact.
Development
composer install
composer ci # pint --test, phpstan (level 8), pest
Author
Created and maintained by Kamil Ćwiertnia, beziworld.eu.
- E-mail: biuro@beziworld.eu
- Issues: GitHub issues
Need an integration? Get in touch through beziworld.eu.
Other packages by the author
laravel-ambro · laravel-dpd · laravel-poczta-polska · laravel-inpost · laravel-gls
License
MIT. See LICENSE.md. This package is not affiliated with Geis Group or Geis PL.