From adcf16ed33f3fc71022c3636129224f656758e48 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:12:10 +0000 Subject: [PATCH 1/3] Initial plan From bf718eda91429cfb5d84802b0177984fa7af39db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:28:18 +0000 Subject: [PATCH 2/3] Add comprehensive GLS Action documentation with corrected events model Co-authored-by: Knerio <96529060+Knerio@users.noreply.github.com> --- README.md | 41 +- docs/Actions/GLS/configs.md | 113 ++++- docs/Actions/GLS/events.md | 174 ++++++++ docs/Actions/GLS/functions.md | 653 ++++++++++++++++++++++++++++ docs/Actions/GLS/meta.json | 14 + docs/Actions/GLS/overview.md | 96 ++++ docs/Actions/GLS/quick-start.md | 134 ++++++ docs/Actions/GLS/troubleshooting.md | 220 ++++++++++ docs/Actions/GLS/types.md | 423 ++++++++++++++++++ docs/Actions/GLS/use-cases.md | 429 ++++++++++++++++++ docs/Guides/installation.md | 117 ++++- docs/index.mdx | 36 +- 12 files changed, 2414 insertions(+), 36 deletions(-) create mode 100644 docs/Actions/GLS/events.md create mode 100644 docs/Actions/GLS/functions.md create mode 100644 docs/Actions/GLS/meta.json create mode 100644 docs/Actions/GLS/overview.md create mode 100644 docs/Actions/GLS/quick-start.md create mode 100644 docs/Actions/GLS/troubleshooting.md create mode 100644 docs/Actions/GLS/types.md create mode 100644 docs/Actions/GLS/use-cases.md diff --git a/README.md b/README.md index fb0813d..4a7ac22 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,47 @@ # centaurus -The "central" place for all actions -# ENV +The "central" place for all actions — a monorepo containing integrations provided by [code0](https://github.com/code0-tech) for the **Hercules** automation platform. + +## Available Actions + +| Action | Description | +|--------|-------------| +| [GLS](docs/Actions/GLS/overview.md) | GLS ShipIT integration for creating and managing shipments | + +## ENV + +All actions share the following base environment variables, which connect them to the Hercules/Aquila infrastructure: + | ENV Variable | Description | Default Value | |------------------------|------------------------------------------------|---------------------| | `HERCULES_AUTH_TOKEN` | Authentication token for connecting to Aquila. | `""` (empty string) | | `HERCULES_AQUILA_URL` | URL of the Aquila server to connect to. | `"localhost:50051"` | | `HERCULES_ACTION_ID` | Identifier for the action being registered. | `""` | | `HERCULES_SDK_VERSION` | Version of the Hercules SDK being used. | `"0.0.0"` | + +## Quick Start + +1. Clone the repository +2. Navigate to the action directory: `cd actions/` +3. Copy the example env file: `cp .example.env .env` +4. Fill in your credentials and Hercules connection details in `.env` +5. Start the action: `docker compose up -d` + +See the [Installation Guide](docs/Guides/installation.md) for detailed steps. + +## Documentation + +Full documentation is located in the [`docs/`](docs/) folder: + +- [Installation Guide](docs/Guides/installation.md) +- [GLS Action Overview](docs/Actions/GLS/overview.md) +- [GLS Configuration](docs/Actions/GLS/configs.md) +- [GLS Functions](docs/Actions/GLS/functions.md) +- [GLS Types](docs/Actions/GLS/types.md) +- [GLS Events](docs/Actions/GLS/events.md) +- [Common Use Cases](docs/Actions/GLS/use-cases.md) +- [Troubleshooting & Community Support](docs/Actions/GLS/troubleshooting.md) + +## Contributing + +Contributions are welcome! See [Troubleshooting & Community Support](docs/Actions/GLS/troubleshooting.md#contributing) for guidelines. diff --git a/docs/Actions/GLS/configs.md b/docs/Actions/GLS/configs.md index ec367e0..5b2cac2 100644 --- a/docs/Actions/GLS/configs.md +++ b/docs/Actions/GLS/configs.md @@ -1,21 +1,110 @@ --- title: Action Configuration +description: All configuration options for the GLS Action, including how to obtain credentials from the GLS Developer Portal. --- -The GLS action provides following configurations: +# GLS Action Configuration -| Config Name | Description | Type | Required | -|-----------------|------------------------------------------------------------------|-------------|----------| -| contact_id | The contact id used in some requests | string | No | -| client_id | The client id used for auth purposes | string | Yes | -| client_secret | The client secret used for auth purposes | string | Yes | -| ship_it_api_url | Gls provides multiple ship it urls, provide yours | string | No | -| auth_url | Gls provides multiple auth urls, provide yours ending in /token | string | No | -| shipper | And default shipper which is replaced in the request if provided | GLS_SHIPPER | No | +The GLS action requires a few credentials to authenticate with the GLS ShipIT API. These are set as **configuration values** in the Hercules admin panel (not as environment variables). +--- + +## Configuration reference + +| Config Name | Type | Required | Default | Description | +|-----------------|-------------|----------|---------|-------------| +| `client_id` | string | **Yes** | — | OAuth2 client ID for authenticating with the GLS API | +| `client_secret` | string | **Yes** | — | OAuth2 client secret for authenticating with the GLS API | +| `contact_id` | string | No | `""` | GLS contact ID used in some API requests (see note below) | +| `ship_it_api_url` | string | No | `https://api.gls-group.net/shipit-farm/v1/backend/rs` | GLS ShipIT API base URL | +| `auth_url` | string | No | `https://api.gls-group.net/oauth2/v2/token` | GLS OAuth2 token endpoint — must end in `/token` | +| `shipper` | GLS_SHIPPER | No | — | Default shipper address used when no shipper is provided in the shipment data | + +> **`contact_id`:** This identifier is required for certain shipment operations (e.g. end-of-day reports and some services). It is issued by GLS support — contact them directly to request it. + +--- + +## How to obtain your credentials + +### Step 1 — Create a GLS Developer account + +1. Go to [https://dev-portal.gls-group.net/get-started](https://dev-portal.gls-group.net/get-started) +2. Click **Sign In** and register a new account, or log in with an existing GLS account +3. Complete the registration and verify your email address + +### Step 2 — Create an application + +1. After logging in, navigate to **My Apps** in the top navigation +2. Click **Create App** (or **New Application**) +3. Fill in the application name and description +4. Select the required API scopes (typically **ShipIT**) +5. Submit the form + +### Step 3 — Retrieve your credentials + +1. Open the application you just created in **My Apps** +2. Copy the **Client ID** — this is your `client_id` +3. Copy the **Client Secret** — this is your `client_secret` + +> Keep the `client_secret` confidential. Do not commit it to source control. + +### Step 4 — Get your Contact ID (optional) + +The `contact_id` is not available in the developer portal. You must contact **GLS support** directly and ask them to provide you with a Contact ID linked to your GLS contract. + +--- + +## API endpoints + +GLS provides different API endpoints depending on your region and environment. The defaults point to the global production API: + +| Setting | Default URL | +|---------|-------------| +| `ship_it_api_url` | `https://api.gls-group.net/shipit-farm/v1/backend/rs` | +| `auth_url` | `https://api.gls-group.net/oauth2/v2/token` | + +If you are using a regional or sandbox endpoint, update these values accordingly. Always ensure `auth_url` ends with `/token`. + +--- + +## Authentication flow + +The GLS Action authenticates using **OAuth2 client credentials**: + +``` +GLS Action + │ + ├── POST {auth_url} + │ body: grant_type=client_credentials + │ client_id= + │ client_secret= + │ + │◄── { access_token, expires_in } + │ + └── All subsequent API calls include: + Authorization: Bearer +``` + +Tokens are **cached** and automatically refreshed 60 seconds before they expire. You do not need to manage token lifecycle manually. + +--- + +## Default shipper + +The optional `shipper` config allows you to set a **default sender address** that is applied to all shipments when no shipper is explicitly provided in the shipment data. This is useful when all your shipments originate from the same address. -For you to receive that credentials you need to follow this guide: https://dev-portal.gls-group.net/get-started#sign-in +The value must be a valid `GLS_SHIPPER` object: -You can receive the client id and secret under "My Apps" after creating one. +```json +{ + "Address": { + "Name1": "My Company GmbH", + "CountryCode": "DE", + "City": "Berlin", + "Street": "Hauptstrasse", + "ZIPCode": "10115" + } +} +``` -The Contact id needs to be retrieved from GLS support, so you need to contact them and ask for it. \ No newline at end of file +See [Types — GLS_SHIPPER](./types#GLS_SHIPPER) for the full field reference. diff --git a/docs/Actions/GLS/events.md b/docs/Actions/GLS/events.md new file mode 100644 index 0000000..7f648bf --- /dev/null +++ b/docs/Actions/GLS/events.md @@ -0,0 +1,174 @@ +--- +title: GLS Action Events +description: Events emitted by the GLS Action — what they are, how they trigger flows in Aquila, and what future events are planned. +--- + +# GLS Action Events + +In the Hercules platform, **events** are notifications emitted **by an action** that trigger flows in Aquila. They are the opposite of functions: instead of a flow calling the action, the action pushes data to Aquila, which starts any flows that are listening for that event type. + +--- + +## How events work + +``` +External world (e.g. GLS webhook / polling) + │ + │ something happens (parcel delivered, shipment arrived, ...) + ▼ + GLS Action + │ + │ sdk.dispatchEvent(eventType, projectId, payload) + ▼ + Aquila + │ + │ routes event to all flows listening for eventType + ▼ + Your Flow starts + │ + │ event payload available as flow input + ▼ + Flow nodes execute (functions, conditions, etc.) +``` + +An event carries a **payload** — the data associated with what happened (e.g. shipment details, tracking ID, status). Flows that subscribe to an event type receive this payload as their starting input. + +--- + +## Current status + +> **The GLS Action does not currently emit any events.** +> +> The GLS action presently only exposes **functions** (called by flows) and registers **data types** and **configuration**. Event support — where the action proactively notifies Aquila of changes — is **planned for a future release**. + +--- + +## Planned events + +The following events are candidates for future implementation. Once added, each will allow you to build flows that react automatically to GLS shipment lifecycle changes. + +### `gls.shipment.arrived` + +Emitted when a parcel arrives at a GLS depot or is scanned into the GLS network. + +**Trigger mechanism:** The action would periodically poll the GLS tracking API (or receive a GLS webhook) and emit this event for each new scan. + +**Payload type (planned):** `GLS_TRACKING_EVENT` + +``` +GLS Action (polling / webhook listener) + │ + │ detects new scan for tracked parcel + ▼ +sdk.dispatchEvent("gls.shipment.arrived", projectId, { + TrackID: "12345678", + Status: "IN_TRANSIT", + Location: "MUC-HUB", + Timestamp: "2025-06-01T10:30:00Z" +}) + │ + ▼ +Aquila → triggers all flows subscribed to "gls.shipment.arrived" +``` + +--- + +### `gls.shipment.delivered` + +Emitted when a parcel is confirmed delivered to the recipient. + +**Payload type (planned):** `GLS_TRACKING_EVENT` + +``` +sdk.dispatchEvent("gls.shipment.delivered", projectId, { + TrackID: "12345678", + Status: "DELIVERED", + DeliveredAt: "2025-06-02T14:15:00Z", + SignedBy: "J. Doe" +}) +``` + +--- + +### `gls.shipment.failed` + +Emitted when a delivery attempt fails (e.g. recipient not home, address problem). + +**Payload type (planned):** `GLS_TRACKING_EVENT` + +``` +sdk.dispatchEvent("gls.shipment.failed", projectId, { + TrackID: "12345678", + Status: "DELIVERY_FAILED", + Reason: "RECIPIENT_NOT_HOME", + NextAttempt: "2025-06-03" +}) +``` + +--- + +### `gls.shipment.returned` + +Emitted when a parcel is returned to sender after failed delivery attempts. + +--- + +## How events are implemented (SDK reference) + +When events are added to the GLS Action, they will follow this pattern from the Hercules SDK: + +### 1. Register the flow type (event definition) + +```typescript +sdk.registerFlowTypes({ + identifier: "gls.shipment.arrived", + editable: false, + inputType: "GLS_TRACKING_EVENT", + linkedDataTypes: ["GLS_TRACKING_EVENT"], + name: [{ code: "en-US", content: "GLS Shipment Arrived" }], + description: [{ + code: "en-US", + content: "Triggered when a GLS parcel arrives at a depot or is scanned." + }] +}) +``` + +### 2. Dispatch the event when it occurs + +```typescript +sdk.dispatchEvent( + "gls.shipment.arrived", // must match registered flow type identifier + projectId, // which project to notify + payload // data payload (must match inputType) +) +``` + +### 3. User builds a flow triggered by the event + +In the Hercules UI, users create a flow with **"GLS Shipment Arrived"** as the trigger. When the GLS action dispatches this event, Aquila starts the flow and provides the payload (e.g. `TrackID`, `Status`, `Location`) as the flow's input. + +--- + +## Flow type settings + +Flow types can expose **settings** that allow users to configure how an event filters or behaves. For example, a future `gls.shipment.arrived` event might let users specify: + +| Setting | Type | Description | +|---------|------|-------------| +| `trackId` | string | Only trigger for a specific parcel | +| `statusFilter` | string[] | Only trigger for specific status codes | + +Settings are defined in the `settings` array of `HerculesFlowType` and are configurable per-flow in the Hercules UI. + +--- + +## Difference between events and functions + +| | Events | Functions | +|-|--------|-----------| +| **Direction** | Action → Aquila | Flow → Action | +| **Who initiates** | The action (proactively) | The flow (on demand) | +| **Purpose** | React to something that happened externally | Perform an operation and return a result | +| **SDK method** | `registerFlowTypes` + `dispatchEvent` | `registerFunctionDefinitions` | +| **Example** | Parcel delivered → trigger notification flow | Create a shipment and return the label | +| **Current GLS status** | ❌ Not yet implemented | ✅ 26 functions available | diff --git a/docs/Actions/GLS/functions.md b/docs/Actions/GLS/functions.md new file mode 100644 index 0000000..f332c3c --- /dev/null +++ b/docs/Actions/GLS/functions.md @@ -0,0 +1,653 @@ +--- +title: GLS Action Functions +description: All functions available in the GLS Action with detailed descriptions, parameters, and data flow diagrams. +--- + +# GLS Action Functions + +The GLS Action exposes **26 functions** grouped into three categories: + +- **Builder functions** — Construct data objects (no API call) +- **Shipment functions** — Create different types of GLS shipments (calls GLS API) +- **API functions** — Query or modify shipments (calls GLS API) + +--- + +## Builder functions + +### `createAddress` + +Creates a GLS address object (`GLS_ADDRESS`) for use in shipments as consignee, shipper, or return address. + +**Signature:** +``` +createAddress( + Name1: string, + CountryCode: string, + City: string, + Street: string, + ZIPCode: string, + Name2?: string, + Name3?: string, + Province?: string, + StreetNumber?: string, + ContactPerson?: string, + FixedLinePhonenumber?: string, + MobilePhonenumber?: string, + Email?: string +): GLS_ADDRESS +``` + +**Parameters:** + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `Name1` | string (max 40) | **Yes** | Primary name (recipient or company name) | +| `CountryCode` | string (max 2) | **Yes** | ISO alpha-2 country code (e.g. `DE`, `FR`, `GB`) | +| `City` | string (max 40) | **Yes** | City name | +| `Street` | string (min 4) | **Yes** | Street name | +| `ZIPCode` | string (max 10) | **Yes** | Postal/ZIP code | +| `Name2` | string (max 40) | No | Additional name line (e.g. department) | +| `Name3` | string (max 40) | No | Additional name line (e.g. c/o) | +| `Province` | string (max 40) | No | State or province | +| `StreetNumber` | string (max 40) | No | House/building number | +| `ContactPerson` | string (min 6, max 40) | No | Contact person at this address | +| `FixedLinePhonenumber` | string (min 4, max 35) | No | Landline phone number | +| `MobilePhonenumber` | string (min 4, max 35) | No | Mobile phone number | +| `eMail` | string (max 80) | No | Email address | + +**Returns:** [`GLS_ADDRESS`](./types#GLS_ADDRESS) + +--- + +### `createConsignee` + +Creates a GLS consignee (recipient) object for use in shipments. + +**Signature:** +``` +createConsignee( + consigneeId: string, + costCenter: string, + Address: GLS_ADDRESS, + Category: "BUSINESS" | "PRIVATE" +): GLS_CONSIGNEE +``` + +**Parameters:** + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `consigneeId` | string (max 40) | **Yes** | Unique ID for the consignee (your internal customer ID) | +| `costCenter` | string (max 80) | **Yes** | Cost center for billing purposes | +| `Address` | GLS_ADDRESS | **Yes** | The delivery address for this consignee | +| `Category` | `"BUSINESS"` \| `"PRIVATE"` | **Yes** | Whether the consignee is a business or private recipient | + +**Returns:** [`GLS_CONSIGNEE`](./types#GLS_CONSIGNEE) + +--- + +### `createShipmentUnit` + +Creates a GLS shipment unit (an individual parcel within a shipment). + +**Signature:** +``` +createShipmentUnit( + weight: number, + shipmentUnitReference?: string, + partnerParcelNumber?: string, + note1?: string, + note2?: string, + shipmentUnitService: GLS_UNIT_SERVICE +): GLS_SHIPMENT_UNIT +``` + +**Parameters:** + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `weight` | number (0.10–99) | **Yes** | Weight of the parcel in kilograms | +| `shipmentUnitReference` | string (max 40) | No | Your internal reference for this parcel | +| `partnerParcelNumber` | string (max 50) | No | Partner-assigned parcel number | +| `note1` | string (max 50) | No | Additional note printed on the label (line 1) | +| `note2` | string (max 50) | No | Additional note printed on the label (line 2) | +| `shipmentUnitService` | GLS_UNIT_SERVICE | No | Unit-level services (Cash, AddonLiability, HazardousGoods, etc.) | + +**Returns:** [`GLS_SHIPMENT_UNIT`](./types#GLS_SHIPMENT_UNIT) + +--- + +### `createPrintingOptions` + +Creates GLS printing options that control how labels are generated. + +**Signature:** +``` +createPrintingOptions(returnLabels: RETURN_LABELS): GLS_PRINTING_OPTIONS +``` + +**Parameters:** + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `returnLabels` | RETURN_LABELS | **Yes** | Label format configuration | + +`RETURN_LABELS` fields: + +| Field | Values | Description | +|-------|--------|-------------| +| `TemplateSet` | `NONE`, `D_200`, `PF_4_I`, `ZPL_200`, `ZPL_300`, ... | Label template set | +| `LabelFormat` | `PDF`, `ZEBRA`, `INTERMEC`, `DATAMAX`, `TOSHIBA`, `PNG` | Output format | + +**Returns:** [`GLS_PRINTING_OPTIONS`](./types#GLS_PRINTING_OPTIONS) + +--- + +### `createCustomContent` + +Creates custom content settings for GLS labels, including logos and barcodes. + +**Signature:** +``` +createCustomContent( + barcodeContentType: "TRACK_ID" | "GLS_SHIPMENT_REFERENCE", + customerLogo: string, + hideShipperAddress?: boolean, + barcodeType?: "EAN_128" | "CODE_39", + barcode?: string +): GLS_CUSTOM_CONTENT +``` + +**Parameters:** + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `barcodeContentType` | `"TRACK_ID"` \| `"GLS_SHIPMENT_REFERENCE"` | **Yes** | What the barcode encodes | +| `customerLogo` | string | **Yes** | Base64-encoded customer logo image | +| `hideShipperAddress` | boolean | No | Hide the shipper address on the label | +| `barcodeType` | `"EAN_128"` \| `"CODE_39"` | No | Barcode symbology | +| `barcode` | string | No | Custom barcode value | + +**Returns:** [`GLS_CUSTOM_CONTENT`](./types#GLS_CUSTOM_CONTENT) + +--- + +## Shipment functions + +All shipment functions accept a common set of parameters in addition to their type-specific parameters. They call the GLS ShipIT API (`POST /rs/shipments`) and return a `GLS_CREATE_PARCELS_RESPONSE`. + +**Common parameters for all shipment functions:** + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `shipment` | GLS_SHIPMENT_WITHOUT_SERVICES | **Yes** | Shipment data (consignee, shipper, units, product) | +| `printingOptions` | GLS_PRINTING_OPTIONS | **Yes** | Label format settings | +| `returnOptions` | GLS_RETURN_OPTIONS | No | Whether to return print data and routing info | +| `customContent` | GLS_CUSTOM_CONTENT | No | Custom logo and barcode settings | + +--- + +### `createShopDeliveryShipment` + +Delivers a parcel to a GLS Parcel Shop where the recipient can collect it. + +**Signature:** +``` +createShopDeliveryShipment( + parcelShopId: string, + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT +): GLS_CREATE_PARCELS_RESPONSE +``` + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `parcelShopId` | string | **Yes** | ID of the target GLS Parcel Shop | + +**Data flow:** +``` +createShopDeliveryShipment + │ + ├── Service: [{ ShopDelivery: { ParcelShopID } }] + │ + └── POST /rs/shipments → GLS_CREATE_PARCELS_RESPONSE +``` + +--- + +### `createShopReturnShipment` + +Creates a return shipment from a GLS Parcel Shop (customer drops off parcel at a shop). + +**Signature:** +``` +createShopReturnShipment( + numberOfLabels: number, + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT, + returnQR?: "PDF" | "PNG" | "ZPL" +): GLS_CREATE_PARCELS_RESPONSE +``` + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `numberOfLabels` | number | **Yes** | Number of return labels to generate | +| `returnQR` | `"PDF"` \| `"PNG"` \| `"ZPL"` | No | Format of the QR code for the return | + +--- + +### `createExchangeShipment` + +Delivers a new parcel while simultaneously picking up an existing one (exchange). + +**Signature:** +``` +createExchangeShipment( + address: GLS_ADDRESS, + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT, + expectedWeight?: number +): GLS_CREATE_PARCELS_RESPONSE +``` + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `address` | GLS_ADDRESS | **Yes** | Address for the exchange pickup | +| `expectedWeight` | number (min 1) | No | Expected weight of the parcel being returned | + +--- + +### `createDeliveryAtWorkShipment` + +Delivers a parcel to a specific location within a workplace (building, floor, room). + +**Signature:** +``` +createDeliveryAtWorkShipment( + recipientName: string, + building: string, + floor: number, + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT, + alternateRecipientName?: string, + room?: number, + phonenumber?: string +): GLS_CREATE_PARCELS_RESPONSE +``` + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `recipientName` | string (max 40) | **Yes** | Name of the recipient at work | +| `building` | string (max 40) | **Yes** | Building name or number | +| `floor` | number | **Yes** | Floor number | +| `alternateRecipientName` | string (max 40) | No | Alternate recipient if primary is unavailable | +| `room` | number | No | Room number | +| `phonenumber` | string (max 35) | No | Contact phone number | + +--- + +### `createDepositShipment` + +Delivers a parcel to a designated deposit location (e.g. a garage or shed) without requiring a signature. + +**Signature:** +``` +createDepositShipment( + placeOfDeposit: string, + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT +): GLS_CREATE_PARCELS_RESPONSE +``` + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `placeOfDeposit` | string (max 121) | **Yes** | Description of where to deposit the parcel | + +--- + +### `createIdentShipment` + +Delivers a parcel with identity verification — the driver checks the recipient's ID document. + +**Signature:** +``` +createIdentShipment( + birthDate: string, + firstName: string, + lastName: string, + nationality: string, + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT +): GLS_CREATE_PARCELS_RESPONSE +``` + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `birthDate` | ISO date string | **Yes** | Recipient's date of birth | +| `firstName` | string (max 40) | **Yes** | Recipient's first name | +| `lastName` | string (max 40) | **Yes** | Recipient's last name | +| `nationality` | string (max 2) | **Yes** | ISO alpha-2 nationality code | + +--- + +### `createIdentPinShipment` + +Delivers a parcel with PIN and optional birthdate verification. + +**Signature:** +``` +createIdentPinShipment( + pin: string, + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT, + birthDate?: string +): GLS_CREATE_PARCELS_RESPONSE +``` + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `pin` | string (max 4) | **Yes** | 4-digit PIN to verify with recipient | +| `birthDate` | ISO date string | No | Recipient's date of birth (additional check) | + +--- + +### `createPickAndShipShipment` + +Schedules a pickup from the consignee's address on a given date. + +**Signature:** +``` +createPickAndShipShipment( + pickupDate: string, + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT +): GLS_CREATE_PARCELS_RESPONSE +``` + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `pickupDate` | ISO date string | **Yes** | Date when GLS will pick up the parcel | + +--- + +### `createFlexDeliveryShipment` + +Creates a shipment with flexible delivery — the recipient can redirect or reschedule delivery. + +**Signature:** +``` +createFlexDeliveryShipment( + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT +): GLS_CREATE_PARCELS_RESPONSE +``` + +No additional parameters beyond the common ones. + +--- + +### `createSignatureShipment` + +Creates a shipment that requires a recipient signature upon delivery. + +**Signature:** +``` +createSignatureShipment( + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT +): GLS_CREATE_PARCELS_RESPONSE +``` + +No additional parameters beyond the common ones. + +--- + +### `createGuaranteed24Shipment` + +Creates a shipment with guaranteed delivery within 24 hours. + +**Signature:** +``` +createGuaranteed24Shipment( + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT +): GLS_CREATE_PARCELS_RESPONSE +``` + +No additional parameters beyond the common ones. + +--- + +### `createAddresseeOnlyShipment` + +Creates a shipment that can only be delivered to the named addressee (no neighbor delivery). + +**Signature:** +``` +createAddresseeOnlyShipment( + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT +): GLS_CREATE_PARCELS_RESPONSE +``` + +No additional parameters beyond the common ones. + +--- + +### `createTyreShipment` + +Creates a shipment specifically for tyre/wheel delivery (uses the GLS TyreService). + +**Signature:** +``` +createTyreShipment( + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT +): GLS_CREATE_PARCELS_RESPONSE +``` + +No additional parameters beyond the common ones. + +--- + +### `createDeliveryNextWorkingDayShipment` + +Creates an **EXPRESS** shipment for delivery on the next working day (EOB service). + +> **Requirement:** The shipment's `Product` field must be set to `"EXPRESS"`. Setting it to `"PARCEL"` will throw an `INVALID_PRODUCT` error. + +**Signature:** +``` +createDeliveryNextWorkingDayShipment( + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT +): GLS_CREATE_PARCELS_RESPONSE +``` + +--- + +### `createDeliverySaturdayShipment` + +Creates an **EXPRESS** shipment for Saturday delivery. + +> **Requirement:** The shipment's `Product` field must be set to `"EXPRESS"`. Setting it to `"PARCEL"` will throw an `INVALID_PRODUCT` error. + +**Signature:** +``` +createDeliverySaturdayShipment( + shipment: GLS_SHIPMENT_WITHOUT_SERVICES, + printingOptions: GLS_PRINTING_OPTIONS, + returnOptions?: GLS_RETURN_OPTIONS, + customContent?: GLS_CUSTOM_CONTENT +): GLS_CREATE_PARCELS_RESPONSE +``` + +--- + +## API functions + +### `validateShipment` + +Validates a shipment against the GLS API without creating it. Use this before `createShipment*` functions to catch errors early. + +**Signature:** +``` +validateShipment(data: GLS_VALIDATE_SHIPMENT_REQUEST_DATA): GLS_VALIDATE_SHIPMENT_RESPONSE_DATA +``` + +**Data flow:** +``` +validateShipment + │ + └── POST /rs/shipments/validate + │ + ▼ + GLS_VALIDATE_SHIPMENT_RESPONSE_DATA + ├── success: boolean + └── validationResult.Issues[] +``` + +See [Types — GLS_VALIDATE_SHIPMENT_REQUEST_DATA](./types#GLS_VALIDATE_SHIPMENT_REQUEST_DATA) for the input format. + +--- + +### `cancelShipment` + +Cancels an existing shipment by its Track ID. Only possible if the parcel has not yet been scanned. + +**Signature:** +``` +cancelShipment(data: GLS_CANCEL_SHIPMENT_REQUEST_DATA): GLS_CANCEL_SHIPMENT_RESPONSE_DATA +``` + +**Data flow:** +``` +cancelShipment({ TrackID }) + │ + └── POST /rs/shipments/cancel/{TrackID} + │ + ▼ + GLS_CANCEL_SHIPMENT_RESPONSE_DATA + ├── TrackID + └── result: "CANCELLED" | "CANCELLATION_PENDING" | "SCANNED" | "ERROR" +``` + +--- + +### `getAllowedServices` + +Returns the GLS services available for a given origin/destination country and ZIP code combination. + +**Signature:** +``` +getAllowedServices(data: GLS_ALLOWED_SERVICES_REQUEST_DATA): GLS_ALLOWED_SERVICES_RESPONSE_DATA +``` + +**Data flow:** +``` +getAllowedServices({ Source, Destination, ContactID? }) + │ + └── GET /rs/shipments/allowedservices + │ + ▼ + GLS_ALLOWED_SERVICES_RESPONSE_DATA + └── AllowedServices[]: { ServiceName } | { ProductName } +``` + +--- + +### `getEndOfDayReport` + +Retrieves all shipments dispatched on a given date. Useful for reconciliation and end-of-day processing. + +**Signature:** +``` +getEndOfDayReport(data: GLS_END_OF_DAY_REQUEST_DATA): GLS_END_OF_DAY_RESPONSE_DATA +``` + +**Data flow:** +``` +getEndOfDayReport({ date }) + │ + └── GET /rs/shipments/endofday?date={date} + │ + ▼ + GLS_END_OF_DAY_RESPONSE_DATA + └── Shipments[]: { ShippingDate, Product, Consignee, Shipper, ShipmentUnit[] } +``` + +--- + +### `updateParcelWeight` + +Updates the weight of an already-created parcel. Useful when the final weight is only known after packaging. + +**Signature:** +``` +updateParcelWeight(data: GLS_UPDATE_PARCEL_WEIGHT_REQUEST_DATA): GLS_UPDATE_PARCEL_WEIGHT_RESPONSE_DATA +``` + +**Data flow:** +``` +updateParcelWeight({ TrackID, Weight }) + │ + └── POST /rs/shipments/updateparcelweight + │ + ▼ + GLS_UPDATE_PARCEL_WEIGHT_RESPONSE_DATA + └── UpdatedWeight: string +``` + +--- + +### `reprintParcel` + +Reprints the label for an existing parcel. Use this if the original label is damaged, lost, or needs to be printed in a different format. + +**Signature:** +``` +reprintParcel(data: GLS_REPRINT_PARCEL_REQUEST_DATA): GLS_REPRINT_PARCEL_RESPONSE_DATA +``` + +**Data flow:** +``` +reprintParcel({ TrackID, CreationDate, PrintingOptions }) + │ + └── POST /rs/shipments/reprintparcel + │ + ▼ + GLS_REPRINT_PARCEL_RESPONSE_DATA + └── CreatedShipment + ├── ParcelData[].TrackID + ├── ParcelData[].Barcodes + └── PrintData[].Data ← new base64-encoded label +``` diff --git a/docs/Actions/GLS/meta.json b/docs/Actions/GLS/meta.json new file mode 100644 index 0000000..c1bfe2d --- /dev/null +++ b/docs/Actions/GLS/meta.json @@ -0,0 +1,14 @@ +{ + "title": "GLS Action", + "description": "GLS ShipIT integration for creating and managing shipments", + "pages": [ + "overview", + "quick-start", + "configs", + "events", + "functions", + "types", + "use-cases", + "troubleshooting" + ] +} diff --git a/docs/Actions/GLS/overview.md b/docs/Actions/GLS/overview.md new file mode 100644 index 0000000..01f150e --- /dev/null +++ b/docs/Actions/GLS/overview.md @@ -0,0 +1,96 @@ +--- +title: GLS Action Overview +description: Overview of the GLS ShipIT action — what it does, what you need to get started, and how it fits into your flows. +--- + +# GLS Action + +The **GLS Action** integrates the [GLS ShipIT API](https://api.gls-group.net) into the Hercules automation platform. It lets you create, validate, cancel, and manage GLS parcel shipments directly from your flows — no manual API calls required. + +--- + +## What can the GLS Action do? + +- **Create shipments** of various types: standard delivery, shop delivery, returns, exchanges, Saturday delivery, and more +- **Validate shipments** before committing them to the API +- **Cancel shipments** that haven't been picked up yet +- **Retrieve allowed services** for a given origin/destination combination +- **Get end-of-day reports** summarizing all shipments dispatched on a given date +- **Update parcel weight** after a shipment has been created +- **Reprint parcel labels** in PDF, PNG, or ZPL format + +--- + +## Prerequisites + +Before using the GLS Action you will need: + +### Hercules / Aquila + +| Requirement | Description | +|-------------|-------------| +| Running Aquila server | The action connects to Aquila on startup to register its functions | +| `HERCULES_AUTH_TOKEN` | Auth token issued by your Aquila instance | +| `HERCULES_AQUILA_URL` | Host and port of your Aquila server (e.g. `aquila.example.com:50051`) | +| Docker + Docker Compose | Used to run the action as a container | + +### GLS Developer Portal + +| Requirement | How to obtain | +|-------------|---------------| +| `client_id` | Create an application at [https://dev-portal.gls-group.net](https://dev-portal.gls-group.net) and find it under **My Apps** | +| `client_secret` | Found alongside the `client_id` in **My Apps** on the GLS developer portal | +| `contact_id` *(optional)* | Issued by GLS support — contact them directly to request it | + +> **Note:** The `contact_id` is required for some shipment operations. If you are unsure whether you need it, contact GLS support. + +--- + +## Architecture overview + +``` +Your Flow (Hercules) + │ + ▼ + GLS Action (this action) + │ + ├── Authenticates with GLS via OAuth2 + │ └── GLS Auth API (/oauth2/v2/token) + │ + └── Calls GLS ShipIT API + └── GLS ShipIT API (/shipit-farm/v1/backend/rs/...) +``` + +The action handles OAuth2 token management automatically, including caching and refresh before expiry. You only need to provide the `client_id` and `client_secret` in the action configuration. + +--- + +## Data flow + +``` +Flow Input + │ + ▼ +Builder Functions ← createAddress, createConsignee, createShipmentUnit, ... + │ + ▼ +Shipment Functions ← createShopDeliveryShipment, createExchangeShipment, ... + │ + ▼ +GLS ShipIT API + │ + ▼ +GLS_CREATE_PARCELS_RESPONSE ← tracking IDs, barcode data, print data, routing info +``` + +--- + +## Next steps + +- [Quick Start](./quick-start) — Create your first shipment in a few steps +- [Configuration](./configs) — Full list of configuration options and how to get credentials +- [Functions](./functions) — All available functions with parameter details +- [Types](./types) — All data types used in the GLS Action +- [Events](./events) — Events emitted by the GLS Action +- [Common Use Cases](./use-cases) — Example flows for real-world scenarios +- [Troubleshooting](./troubleshooting) — FAQ and community support diff --git a/docs/Actions/GLS/quick-start.md b/docs/Actions/GLS/quick-start.md new file mode 100644 index 0000000..e273b22 --- /dev/null +++ b/docs/Actions/GLS/quick-start.md @@ -0,0 +1,134 @@ +--- +title: Quick Start — GLS Action +description: Create your first GLS shipment in a few steps. +--- + +# Quick Start + +This guide walks you through creating your first GLS shipment using the GLS Action. By the end, you will have a working flow that creates a parcel and retrieves a shipping label. + +--- + +## Step 1: Install and configure the action + +Follow the [Installation Guide](../../Guides/installation) to deploy the GLS Action, then set the following configuration values in your Hercules admin panel (or `.env` file): + +| Config | Value | +|--------|-------| +| `client_id` | Your GLS OAuth2 client ID | +| `client_secret` | Your GLS OAuth2 client secret | +| `ship_it_api_url` | GLS ShipIT endpoint (default: `https://api.gls-group.net/shipit-farm/v1/backend/rs`) | +| `auth_url` | GLS auth endpoint (default: `https://api.gls-group.net/oauth2/v2/token`) | + +See [Configuration](./configs) for the full list of options and how to obtain credentials. + +--- + +## Step 2: Build your flow + +A basic "create a GLS parcel" flow looks like this: + +``` +[createAddress] → GLS_ADDRESS (recipient) +[createAddress] → GLS_ADDRESS (shipper) +[createShipmentUnit] → GLS_SHIPMENT_UNIT +[createPrintingOptions] → GLS_PRINTING_OPTIONS +[createShopDeliveryShipment] → GLS_CREATE_PARCELS_RESPONSE +``` + +### Flow diagram + +``` +START + │ + ├─ createAddress (recipient) + │ Name1: "John Doe" + │ CountryCode: "DE" + │ City: "Munich" + │ Street: "Musterstrasse" + │ ZIPCode: "80331" + │ │ + │ ▼ GLS_ADDRESS (recipient) + │ + ├─ createAddress (shipper) + │ Name1: "My Company GmbH" + │ CountryCode: "DE" + │ City: "Berlin" + │ Street: "Hauptstrasse" + │ ZIPCode: "10115" + │ │ + │ ▼ GLS_ADDRESS (shipper) + │ + ├─ createShipmentUnit + │ weight: 2.5 + │ │ + │ ▼ GLS_SHIPMENT_UNIT + │ + ├─ createPrintingOptions + │ returnLabels: + │ TemplateSet: "NONE" + │ LabelFormat: "PDF" + │ │ + │ ▼ GLS_PRINTING_OPTIONS + │ + └─ createShopDeliveryShipment + parcelShopId: "12345" + shipment: + Product: "PARCEL" + Consignee: { Address: } + Shipper: { Address: } + ShipmentUnit: [] + printingOptions: + │ + ▼ GLS_CREATE_PARCELS_RESPONSE + { CreatedShipment: { TrackID, PrintData, ... } } +``` + +--- + +## Step 3: Use the response + +The `GLS_CREATE_PARCELS_RESPONSE` contains everything you need: + +```json +{ + "CreatedShipment": { + "ShipmentReference": ["REF-001"], + "ParcelData": [ + { + "TrackID": "12345678", + "ParcelNumber": "00123456789", + "Barcodes": { + "Primary2D": "...", + "Secondary2D": "...", + "Primary1D": "..." + }, + "RoutingInfo": { + "Tour": "MUC-01", + "FinalLocationCode": "MUC", + "HubLocation": "MUC-HUB" + } + } + ], + "PrintData": [ + { + "Data": "", + "LabelFormat": "PDF" + } + ] + } +} +``` + +- **`TrackID`** — Use this to track the parcel or cancel the shipment later +- **`PrintData[].Data`** — Base64-encoded shipping label, decode and print it +- **`RoutingInfo`** — Routing information assigned by GLS + +--- + +## Common next steps + +- [Validate before creating](./functions#validateShipment) — Call `validateShipment` first to catch errors before committing +- [Cancel a shipment](./functions#cancelShipment) — Use `cancelShipment` with the `TrackID` if something changes +- [Reprint a label](./functions#reprintParcel) — Use `reprintParcel` if a label is lost or damaged +- [Common Use Cases](./use-cases) — End-to-end examples for real-world scenarios diff --git a/docs/Actions/GLS/troubleshooting.md b/docs/Actions/GLS/troubleshooting.md new file mode 100644 index 0000000..f313430 --- /dev/null +++ b/docs/Actions/GLS/troubleshooting.md @@ -0,0 +1,220 @@ +--- +title: Troubleshooting & Community Support +description: Frequently asked questions, troubleshooting tips, and community resources for the GLS Action. +--- + +# Troubleshooting & Community Support + +--- + +## FAQ + +### General + +**Q: What is the GLS Action?** + +A: The GLS Action is an integration for the Hercules automation platform that connects to the [GLS ShipIT API](https://api.gls-group.net). It lets you create and manage GLS shipments from within your flows without writing any API code. + +--- + +**Q: What GLS services does this action support?** + +A: The action supports all major GLS shipment types and services, including: +- Standard parcel delivery +- Shop delivery and shop returns +- Exchange shipments +- Delivery at work +- Deposit delivery +- Identity-verified delivery (Ident / IdentPIN) +- Flex delivery, signature, guaranteed 24h +- Tyre service, addressee-only delivery +- Saturday and next-working-day delivery (EXPRESS only) + +See [Functions](./functions) for the complete list. + +--- + +**Q: Do I need a paid GLS account?** + +A: Yes. You need a GLS business account and API access. Register on the [GLS Developer Portal](https://dev-portal.gls-group.net) and create an application to obtain `client_id` and `client_secret`. + +--- + +**Q: What is the `contact_id` and do I need it?** + +A: The `contact_id` is a GLS-assigned identifier linked to your contract. It is required for some advanced operations (e.g. retrieving end-of-day reports with your account data). Contact GLS support to request it. It is **optional** for basic shipment creation. + +--- + +**Q: Can I test the action without a real GLS account?** + +A: GLS provides sandbox/test environments for some regions. Check the [GLS Developer Portal](https://dev-portal.gls-group.net) for sandbox API endpoint URLs and test credentials. Update `ship_it_api_url` and `auth_url` in your configuration to point to the sandbox endpoints. + +--- + +### Installation & configuration + +**Q: The action starts but immediately disconnects. What's wrong?** + +A: Check the following: +1. `HERCULES_AUTH_TOKEN` — is it valid and not expired? +2. `HERCULES_AQUILA_URL` — is the Aquila server reachable from the Docker container? +3. Docker logs: `docker compose logs -f` — look for specific error messages + +--- + +**Q: I get "Failed to register config definitions" on startup. What does that mean?** + +A: This means the action could not register its configuration schema with the Aquila server. Check: +- The Aquila server is running and healthy +- The `HERCULES_AUTH_TOKEN` has sufficient permissions +- The action ID (`HERCULES_ACTION_ID`) is not already registered with a conflicting schema + +--- + +**Q: The action shows "SDK connected successfully" but my functions don't appear in Hercules.** + +A: Wait a few seconds — registration can take a moment. Then refresh the Hercules UI. If functions still don't appear, check that the action's `HERCULES_ACTION_ID` matches what is configured in Hercules. + +--- + +### Authentication & API errors + +**Q: I get a 401 Unauthorized error when the action tries to call the GLS API.** + +A: Your `client_id` or `client_secret` is incorrect, or your GLS application does not have the required API scopes. Verify your credentials on the [GLS Developer Portal](https://dev-portal.gls-group.net) and ensure the **ShipIT** scope is enabled. + +--- + +**Q: I get an `INVALID_PRODUCT` error when creating a Saturday delivery shipment.** + +A: Saturday delivery (and next-working-day delivery) requires the shipment's `Product` to be set to `"EXPRESS"`. Change `Product: "PARCEL"` to `Product: "EXPRESS"` in your shipment data. + +--- + +**Q: I get `ERROR_CREATING_GLS_SHIPMENT` — how do I find out what went wrong?** + +A: Use `validateShipment` first to check your shipment data before creating it. The validation response includes specific `Issues` with `Rule` and `Location` fields pointing to the problematic field. See [Use Cases — Validate before creating](./use-cases#use-case-2-validate-before-creating). + +--- + +**Q: Can I cancel a shipment after it has been picked up by GLS?** + +A: No. Once GLS has scanned the parcel at a depot or delivery vehicle, cancellation is no longer possible. The `cancelShipment` function will return `result: "SCANNED"` in that case. + +--- + +**Q: My token expires frequently. Can I adjust the refresh interval?** + +A: The action automatically refreshes tokens 60 seconds before they expire. This is hard-coded and cannot be changed through configuration. GLS OAuth2 tokens typically have a validity of 1 hour. + +--- + +### Labels & printing + +**Q: What label formats are supported?** + +A: The action supports: `PDF`, `ZEBRA`, `INTERMEC`, `DATAMAX`, `TOSHIBA`, `PNG`. For reprint, additionally `PNG_200`. + +Choose the format that matches your label printer. + +--- + +**Q: The label data returned is base64-encoded. How do I print it?** + +A: Decode `CreatedShipment.PrintData[0].Data` from base64, then: +- **PDF:** Save as a `.pdf` file and send to a PDF-capable printer +- **ZPL (ZEBRA):** Send the raw ZPL string directly to a Zebra label printer +- **PNG:** Save as a `.png` file and print as an image + +--- + +**Q: Can I reprint a label after the parcel has been dispatched?** + +A: Yes, use the `reprintParcel` function with the `TrackID` and the original `CreationDate`. Note that available template sets for reprinting are limited to `NONE`, `ZPL_200`, and `ZPL_300`. + +--- + +## Common error codes + +| Error Code | Cause | Resolution | +|------------|-------|------------| +| `ERROR_CREATING_GLS_SHIPMENT` | API returned an error during shipment creation or management | Check `validateShipment` output for details | +| `INVALID_PRODUCT` | Used `"PARCEL"` product with a service that requires `"EXPRESS"` | Set `Product: "EXPRESS"` in the shipment | + +--- + +## Still stuck? + +If you cannot resolve your issue with the FAQ above: + +1. **Check the action logs:** `docker compose logs -f` in the action directory +2. **Check the GLS API status:** Visit the [GLS Developer Portal](https://dev-portal.gls-group.net) for service announcements +3. **Open an issue** on GitHub (see below) + +--- + +## GitHub + +The source code for the GLS Action and all other Centaurus actions is available on GitHub: + +🔗 **[https://github.com/code0-tech/centaurus](https://github.com/code0-tech/centaurus)** + +Use the GitHub repository to: +- **Report bugs:** Open an [issue](https://github.com/code0-tech/centaurus/issues) +- **Request features:** Open a [discussion](https://github.com/code0-tech/centaurus/discussions) or issue with the `enhancement` label +- **Ask questions:** Use [GitHub Discussions](https://github.com/code0-tech/centaurus/discussions) + +--- + +## Contributing + +Contributions to Centaurus are welcome! Here is how to get started: + +### 1. Fork and clone + +```bash +git clone https://github.com//centaurus.git +cd centaurus +npm install +``` + +### 2. Create a new action (optional) + +Use the scaffolding script to create a new action: + +```bash +npm run create-action -- my-new-action +``` + +This creates a new directory at `actions/my-new-action/` with the standard structure. + +### 3. Make your changes + +- Follow the existing code style (TypeScript, Zod for validation, Hercules SDK patterns) +- Add tests for your changes in `src/index.test.ts` +- Run the test suite: `npm run test` +- Run the linter: `npm run lint` + +### 4. Submit a pull request + +Open a pull request against the `main` branch of [code0-tech/centaurus](https://github.com/code0-tech/centaurus). Include: +- A clear description of what you changed and why +- Test results showing your changes pass + +### Development commands + +| Command | Description | +|---------|-------------| +| `npm run build` | Build all actions | +| `npm run test` | Run the test suite | +| `npm run test:watch` | Run tests in watch mode | +| `npm run lint` | Run ESLint | +| `npm run create-action -- ` | Scaffold a new action | + +### Code conventions + +- All types must use **Zod schemas** with a matching `Schema` suffix (e.g. `AddressSchema` / `Address`) +- All registered types must have identifiers starting with `GLS_` (for the GLS action) +- All function definitions must include `name` and `description` in `en-US` +- Functions that call external APIs must wrap errors in `RuntimeErrorException` diff --git a/docs/Actions/GLS/types.md b/docs/Actions/GLS/types.md new file mode 100644 index 0000000..478a3e7 --- /dev/null +++ b/docs/Actions/GLS/types.md @@ -0,0 +1,423 @@ +--- +title: GLS Action Types +description: All data types registered by the GLS Action — field references and descriptions. +--- + +# GLS Action Types + +The GLS Action registers the following data types with the Hercules platform. These types are used as inputs and outputs of the GLS functions and can be referenced in your flows. + +--- + +## `GLS_ADDRESS` {#GLS_ADDRESS} + +Represents a physical address used for consignee, shipper, and return addresses. + +**Used by:** `GLS_CONSIGNEE`, `GLS_SHIPPER`, `GLS_SHIPMENT_SERVICE` (Exchange, DeliveryAtWork, etc.) + +| Field | Type | Required | Constraints | Description | +|-------|------|----------|-------------|-------------| +| `Name1` | string | **Yes** | max 40 | Primary name (person or company) | +| `Name2` | string | No | max 40 | Additional name line (e.g. department) | +| `Name3` | string | No | max 40 | Additional name line (e.g. c/o) | +| `CountryCode` | string | **Yes** | max 2 | ISO alpha-2 country code (e.g. `DE`, `FR`) | +| `Province` | string | No | max 40 | State or province | +| `City` | string | **Yes** | max 40 | City name | +| `Street` | string | **Yes** | min 4 | Street name | +| `StreetNumber` | string | No | max 40 | House/building number | +| `ContactPerson` | string | No | min 6, max 40 | Contact person name | +| `FixedLinePhonenumber` | string | No | min 4, max 35 | Landline phone number | +| `MobilePhonenumber` | string | No | min 4, max 35 | Mobile phone number | +| `eMail` | string | No | max 80 | Email address | +| `ZIPCode` | string | **Yes** | max 10 | Postal/ZIP code | + +--- + +## `GLS_CONSIGNEE` {#GLS_CONSIGNEE} + +Represents the recipient of a shipment. + +**Used by:** `GLS_SHIPMENT` + +**Linked types:** `GLS_ADDRESS` + +| Field | Type | Required | Constraints | Description | +|-------|------|----------|-------------|-------------| +| `ConsigneeID` | string | No | max 40 | Your internal customer/consignee ID | +| `CostCenter` | string | No | max 80 | Cost center for billing | +| `Category` | `"BUSINESS"` \| `"PRIVATE"` | No | — | Type of recipient | +| `Address` | GLS_ADDRESS | **Yes** | — | Physical delivery address | + +--- + +## `GLS_SHIPPER` {#GLS_SHIPPER} + +Represents the sender of a shipment. + +**Used by:** `GLS_SHIPMENT`, action configuration + +**Linked types:** `GLS_ADDRESS` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `Address` | GLS_ADDRESS | No | Primary shipper address | +| `AlternativeShipperAddress` | GLS_ADDRESS | No | Alternative address to print on the label | + +> **Note:** When used in the configuration (`shipper`), the action automatically includes the `ContactID` from the `contact_id` configuration value. + +--- + +## `GLS_UNIT_SERVICE` {#GLS_UNIT_SERVICE} + +An optional array of value-added services applied to an individual shipment unit (parcel). + +**Used by:** `GLS_SHIPMENT_UNIT` + +Each element is an object with one or more of the following optional fields: + +| Service field | Description | +|---------------|-------------| +| `Cash` | Cash on delivery — `Reason` (max 160), `Amount` (min 1), `Currency` (3 chars) | +| `AddonLiability` | Additional liability insurance — `Amount`, `Currency`, `ParcelContent` (max 255) | +| `HazardousGoods` | Hazardous goods declaration — array of `{ Weight, GLSHazNo (max 8) }` | +| `ExWorks` | Ex-works shipping terms | +| `LimitedQuantities` | Limited quantities of dangerous goods — optional `Weight` | + +--- + +## `GLS_SHIPMENT_UNIT` {#GLS_SHIPMENT_UNIT} + +Represents a single parcel within a shipment. A shipment may contain multiple units. + +**Used by:** `GLS_SHIPMENT`, `GLS_SHIPMENT_WITHOUT_SERVICES` + +**Linked types:** `GLS_UNIT_SERVICE` + +| Field | Type | Required | Constraints | Description | +|-------|------|----------|-------------|-------------| +| `Weight` | number | **Yes** | 0.10–99 kg | Weight of the parcel | +| `ShipmentUnitReference` | string | No | max 40 | Your internal parcel reference | +| `PartnerParcelNumber` | string | No | max 50 | Partner-assigned number | +| `Note1` | string | No | max 50 | Label note line 1 | +| `Note2` | string | No | max 50 | Label note line 2 | +| `Service` | GLS_UNIT_SERVICE | No | — | Unit-level value-added services | + +--- + +## `GLS_SHIPMENT_SERVICE` {#GLS_SHIPMENT_SERVICE} + +An optional array of shipment-level services. Shipment creation functions automatically populate this based on which function you call. + +**Used by:** `GLS_SHIPMENT` + +Each element is an object with one of the following service fields: + +| Service | Parameters | Description | +|---------|------------|-------------| +| `ShopDelivery` | `ParcelShopID` (max 50) | Delivery to a GLS Parcel Shop | +| `ShopReturn` | `NumberOfLabels`, `ReturnQR?` | Return from a Parcel Shop | +| `Exchange` | `Address` (GLS_ADDRESS), `ExpectedWeight?` | Exchange delivery and pickup | +| `DeliveryAtWork` | `RecipientName`, `Building`, `Floor`, `Room?`, `Phonenumber?`, `AlternateRecipientName?` | Workplace delivery | +| `Deposit` | `PlaceOfDeposit` (max 121) | Deposit without signature | +| `IdentPin` | `PIN` (max 4), `Birthdate?` | PIN-based identity check | +| `Ident` | `Birthdate`, `Firstname`, `Lastname`, `Nationality` (max 2) | Full identity check | +| `PickAndShip` | `PickupDate` | GLS picks up from consignee | +| `FlexDeliveryService` | — | Recipient can redirect delivery | +| `SignatureService` | — | Signature required on delivery | +| `Guaranteed24Service` | — | 24-hour guaranteed delivery | +| `AddresseeOnlyService` | — | Delivery to named addressee only | +| `TyreService` | — | Tyre/wheel delivery service | +| `EOB` | — | End of Business (next working day) | +| `SaturdayService` | — | Saturday delivery | +| `Saturday1000Service` | — | Saturday by 10:00 | +| `Saturday1200Service` | — | Saturday by 12:00 | + +--- + +## `GLS_SHIPMENT` {#GLS_SHIPMENT} + +The complete shipment object including all services. + +**Used by:** `GLS_VALIDATE_SHIPMENT_REQUEST_DATA` + +**Linked types:** `GLS_CONSIGNEE`, `GLS_SHIPPER`, `GLS_SHIPMENT_UNIT`, `GLS_SHIPMENT_SERVICE`, `GLS_ADDRESS` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `Product` | `"PARCEL"` \| `"EXPRESS"` | **Yes** | Shipment product type | +| `Consignee` | GLS_CONSIGNEE | **Yes** | Recipient details | +| `Shipper` | GLS_SHIPPER | **Yes** | Sender details | +| `ShipmentUnit` | GLS_SHIPMENT_UNIT[] | **Yes** | Array of parcels (min 1) | +| `Service` | GLS_SHIPMENT_SERVICE | No | Shipment-level services | +| `ShipmentReference` | string (max 40) | No | Your internal shipment reference | +| `ShipmentDate` | date | No | Shipment date (defaults to today) | +| `IncotermCode` | integer (max 99) | No | International commerce terms code | +| `Identifier` | string (max 40) | No | Additional identifier | +| `ExpressAltDeliveryAllowed` | boolean | No | Allow alternative delivery for express shipments | +| `Carrier` | `"ROYALMAIL"` | No | Override carrier (UK only) | +| `Return.Address` | GLS_ADDRESS | No | Address for return shipments | + +--- + +## `GLS_SHIPMENT_WITHOUT_SERVICES` {#GLS_SHIPMENT_WITHOUT_SERVICES} + +The shipment object without the `Service` field. Used as input to all shipment creation functions — the service is added automatically based on which function you call. + +**Linked types:** `GLS_SHIPMENT` + +Same fields as `GLS_SHIPMENT` except `Service` is omitted. + +--- + +## `GLS_PRINTING_OPTIONS` {#GLS_PRINTING_OPTIONS} + +Configures how shipping labels are generated. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `ReturnLabels.TemplateSet` | enum | **Yes** | Label template to use | +| `ReturnLabels.LabelFormat` | enum | **Yes** | Output file format | + +**Template sets:** `NONE`, `D_200`, `PF_4_I`, `PF_4_I_200`, `PF_4_I_300`, `PF_8_D_200`, `T_200_BF`, `T_300_BF`, `ZPL_200`, `ZPL_200_TRACKID_EAN_128`, `ZPL_200_TRACKID_CODE_39`, `ZPL_200_REFNO_EAN_128`, `ZPL_200_REFNO_CODE_39`, `ZPL_300`, `ZPL_300_TRACKID_EAN_128`, `ZPL_300_TRACKID_CODE_39`, `ZPL_300_REFNO_EAN_128`, `ZPL_300_REFNO_CODE_39` + +**Label formats:** `PDF`, `ZEBRA`, `INTERMEC`, `DATAMAX`, `TOSHIBA`, `PNG` + +--- + +## `GLS_RETURN_OPTIONS` {#GLS_RETURN_OPTIONS} + +Controls whether the GLS API includes print data and routing info in the response. + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `ReturnPrintData` | boolean | `true` | Include base64-encoded label in response | +| `ReturnRoutingInfo` | boolean | `true` | Include routing information in response | + +> Set both to `false` if you only need the `TrackID` and don't need the label data immediately. + +--- + +## `GLS_CUSTOM_CONTENT` {#GLS_CUSTOM_CONTENT} + +Customizes what appears on the printed shipping label. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `CustomerLogo` | string | **Yes** | Base64-encoded logo image | +| `BarcodeContentType` | `"TRACK_ID"` \| `"GLS_SHIPMENT_REFERENCE"` | **Yes** | What to encode in the custom barcode | +| `Barcode` | string | No | Custom barcode value | +| `BarcodeType` | `"EAN_128"` \| `"CODE_39"` | No | Barcode symbology | +| `HideShipperAddress` | boolean | No | Hide shipper address on label | + +--- + +## `GLS_CREATE_PARCELS_RESPONSE` {#GLS_CREATE_PARCELS_RESPONSE} + +The response returned by all shipment creation functions. + +| Field | Type | Description | +|-------|------|-------------| +| `CreatedShipment.ShipmentReference` | string[] | Your shipment references | +| `CreatedShipment.ParcelData[].TrackID` | string (8 chars) | GLS tracking ID — use to track or cancel | +| `CreatedShipment.ParcelData[].ParcelNumber` | string | GLS parcel number | +| `CreatedShipment.ParcelData[].Barcodes.Primary2D` | string | 2D barcode data | +| `CreatedShipment.ParcelData[].Barcodes.Secondary2D` | string | Secondary 2D barcode | +| `CreatedShipment.ParcelData[].Barcodes.Primary1D` | string | 1D barcode data | +| `CreatedShipment.ParcelData[].Barcodes.Primary1DPrint` | boolean | Whether to print 1D barcode | +| `CreatedShipment.ParcelData[].RoutingInfo.Tour` | string | Delivery tour identifier | +| `CreatedShipment.ParcelData[].RoutingInfo.FinalLocationCode` | string | Final delivery depot | +| `CreatedShipment.ParcelData[].RoutingInfo.HubLocation` | string | Hub location code | +| `CreatedShipment.ParcelData[].RoutingInfo.LastRoutingDate` | date | Last valid routing date | +| `CreatedShipment.PrintData[].Data` | string | Base64-encoded label | +| `CreatedShipment.PrintData[].LabelFormat` | enum | Format of the label | +| `CreatedShipment.CustomerID` | string | GLS customer identifier | +| `CreatedShipment.PickupLocation` | string | Depot where parcel will be picked up | +| `CreatedShipment.GDPR` | string[] | GDPR-related references | + +--- + +## `GLS_CANCEL_SHIPMENT_REQUEST_DATA` {#GLS_CANCEL_SHIPMENT_REQUEST_DATA} + +Input for the `cancelShipment` function. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `TrackID` | string | **Yes** | GLS tracking ID of the shipment to cancel | + +--- + +## `GLS_CANCEL_SHIPMENT_RESPONSE_DATA` {#GLS_CANCEL_SHIPMENT_RESPONSE_DATA} + +Response from the `cancelShipment` function. + +| Field | Type | Description | +|-------|------|-------------| +| `TrackID` | string | The tracking ID that was cancelled | +| `result` | `"CANCELLED"` \| `"CANCELLATION_PENDING"` \| `"SCANNED"` \| `"ERROR"` | Result of the cancellation | + +--- + +## `GLS_ALLOWED_SERVICES_REQUEST_DATA` {#GLS_ALLOWED_SERVICES_REQUEST_DATA} + +Input for the `getAllowedServices` function. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `Source.CountryCode` | string (max 2) | **Yes** | Origin country code | +| `Source.ZIPCode` | string (max 10) | **Yes** | Origin ZIP/postal code | +| `Destination.CountryCode` | string (max 2) | **Yes** | Destination country code | +| `Destination.ZIPCode` | string (max 10) | **Yes** | Destination ZIP/postal code | +| `ContactID` | string | No | GLS contact ID (overrides config) | + +--- + +## `GLS_ALLOWED_SERVICES_RESPONSE_DATA` {#GLS_ALLOWED_SERVICES_RESPONSE_DATA} + +Response from the `getAllowedServices` function. + +| Field | Type | Description | +|-------|------|-------------| +| `AllowedServices[]` | array | List of services or products available for the route | +| `AllowedServices[].ServiceName` | string | Name of an available service | +| `AllowedServices[].ProductName` | string | Name of an available product | + +Each element contains either `ServiceName` or `ProductName`, not both. + +--- + +## `GLS_END_OF_DAY_REQUEST_DATA` {#GLS_END_OF_DAY_REQUEST_DATA} + +Input for the `getEndOfDayReport` function. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `date` | ISO date string | **Yes** | The date for which to retrieve the report (e.g. `"2025-01-15"`) | + +--- + +## `GLS_END_OF_DAY_RESPONSE_DATA` {#GLS_END_OF_DAY_RESPONSE_DATA} + +Response from the `getEndOfDayReport` function. + +| Field | Type | Description | +|-------|------|-------------| +| `Shipments[].ShippingDate` | ISO date | Date the shipment was dispatched | +| `Shipments[].Product` | `"PARCEL"` \| `"EXPRESS"` | Product type | +| `Shipments[].Consignee.Address` | GLS_ADDRESS | Recipient address | +| `Shipments[].Shipper.ContactID` | string | GLS contact ID of shipper | +| `Shipments[].Shipper.AlternativeShipperAddress` | GLS_ADDRESS | Alternative shipper address | +| `Shipments[].ShipmentUnit[].TrackID` | string | Tracking ID | +| `Shipments[].ShipmentUnit[].Weight` | string | Parcel weight | +| `Shipments[].ShipmentUnit[].ParcelNumber` | string | GLS parcel number | + +--- + +## `GLS_UPDATE_PARCEL_WEIGHT_REQUEST_DATA` {#GLS_UPDATE_PARCEL_WEIGHT_REQUEST_DATA} + +Input for the `updateParcelWeight` function. Provide at least one identifier (`TrackID`, `ParcelNumber`, `ShipmentReference`, `ShipmentUnitReference`, or `PartnerParcelNumber`). + +| Field | Type | Required | Constraints | Description | +|-------|------|----------|-------------|-------------| +| `TrackID` | string | No | max 8 | GLS tracking ID | +| `ParcelNumber` | number | No | max 999999999999 | GLS parcel number | +| `ShipmentReference` | string | No | max 40 | Your shipment reference | +| `ShipmentUnitReference` | string | No | max 40 | Your parcel unit reference | +| `PartnerParcelNumber` | string | No | max 50 | Partner parcel number | +| `Weight` | number | **Yes** | min 0.10 | New weight in kilograms | + +--- + +## `GLS_UPDATE_PARCEL_WEIGHT_RESPONSE_DATA` {#GLS_UPDATE_PARCEL_WEIGHT_RESPONSE_DATA} + +Response from the `updateParcelWeight` function. + +| Field | Type | Description | +|-------|------|-------------| +| `UpdatedWeight` | string | Confirmed updated weight value | + +--- + +## `GLS_REPRINT_PARCEL_REQUEST_DATA` {#GLS_REPRINT_PARCEL_REQUEST_DATA} + +Input for the `reprintParcel` function. Provide at least one identifier. + +| Field | Type | Required | Constraints | Description | +|-------|------|----------|-------------|-------------| +| `TrackID` | string | No | max 8 | GLS tracking ID | +| `ParcelNumber` | number | No | max 999999999999 | GLS parcel number | +| `ShipmentReference` | string | No | max 40 | Your shipment reference | +| `ShipmentUnitReference` | string | No | max 40 | Your parcel unit reference | +| `PartnerParcelNumber` | string | No | max 50 | Partner parcel number | +| `CreationDate` | ISO date string | **Yes** | — | Original shipment creation date | +| `PrintingOptions.ReturnLabels.TemplateSet` | enum | **Yes** | `NONE`, `ZPL_200`, `ZPL_300` | Label template | +| `PrintingOptions.ReturnLabels.LabelFormat` | enum | **Yes** | `PDF`, `ZEBRA`, `PNG`, `PNG_200` | Output format | + +--- + +## `GLS_REPRINT_PARCEL_RESPONSE_DATA` {#GLS_REPRINT_PARCEL_RESPONSE_DATA} + +Response from the `reprintParcel` function. Same structure as `GLS_CREATE_PARCELS_RESPONSE` without the `ShipmentReference` and `GDPR` fields. + +| Field | Type | Description | +|-------|------|-------------| +| `CreatedShipment.ParcelData[].TrackID` | string | Tracking ID | +| `CreatedShipment.ParcelData[].ShipmentUnitReference` | string[] | Unit references | +| `CreatedShipment.ParcelData[].ParcelNumber` | string | Parcel number | +| `CreatedShipment.ParcelData[].Barcodes` | object | Barcode data | +| `CreatedShipment.ParcelData[].RoutingInfo` | object | Routing details | +| `CreatedShipment.PrintData[].Data` | string | Base64-encoded label | +| `CreatedShipment.PrintData[].LabelFormat` | enum | `PDF`, `ZEBRA`, `PNG`, `PNG_200` | +| `CreatedShipment.CustomerID` | string | GLS customer identifier | +| `CreatedShipment.PickupLocation` | string | Depot pickup location | +| `CreatedShipment.GDPR` | string[] | GDPR references | + +--- + +## `GLS_VALIDATE_SHIPMENT_REQUEST_DATA` {#GLS_VALIDATE_SHIPMENT_REQUEST_DATA} + +Input for the `validateShipment` function. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `Shipment` | GLS_SHIPMENT | **Yes** | The complete shipment to validate | + +--- + +## `GLS_VALIDATE_SHIPMENT_RESPONSE_DATA` {#GLS_VALIDATE_SHIPMENT_RESPONSE_DATA} + +Response from the `validateShipment` function. + +| Field | Type | Description | +|-------|------|-------------| +| `success` | boolean | Whether the shipment passed all validation rules | +| `validationResult.Issues[]` | array | List of validation issues (empty if valid) | +| `validationResult.Issues[].Rule` | string | Name of the failed validation rule | +| `validationResult.Issues[].Location` | string | Path in the data where the issue was found | +| `validationResult.Issues[].Parameters` | string[] | Additional details about the issue | + +--- + +## Type dependency diagram + +``` +GLS_SHIPMENT_WITHOUT_SERVICES + ├── Consignee: GLS_CONSIGNEE + │ └── Address: GLS_ADDRESS + ├── Shipper: GLS_SHIPPER + │ ├── Address: GLS_ADDRESS + │ └── AlternativeShipperAddress: GLS_ADDRESS + └── ShipmentUnit[]: GLS_SHIPMENT_UNIT + └── Service: GLS_UNIT_SERVICE + +GLS_PRINTING_OPTIONS + └── ReturnLabels: { TemplateSet, LabelFormat } + +GLS_CUSTOM_CONTENT + └── { CustomerLogo, BarcodeContentType, Barcode, BarcodeType, HideShipperAddress } + +GLS_RETURN_OPTIONS + └── { ReturnPrintData, ReturnRoutingInfo } + +─── Shipment function ────────────────────────────────────────────── +[GLS_SHIPMENT_WITHOUT_SERVICES + GLS_PRINTING_OPTIONS + ...] → GLS_CREATE_PARCELS_RESPONSE +``` diff --git a/docs/Actions/GLS/use-cases.md b/docs/Actions/GLS/use-cases.md new file mode 100644 index 0000000..d53f699 --- /dev/null +++ b/docs/Actions/GLS/use-cases.md @@ -0,0 +1,429 @@ +--- +title: Common Use Cases +description: End-to-end example flows using the GLS Action for real-world shipping scenarios. +--- + +# Common Use Cases + +This page shows complete, real-world examples of flows built with the GLS Action. Each example includes a step-by-step breakdown and the data passed between functions. + +--- + +## Use Case 1: Standard parcel delivery + +**Scenario:** A customer places an order. You want to create a shipping label and send it to your label printer. + +### Flow + +``` +[createAddress] (recipient) + │ GLS_ADDRESS +[createAddress] (shipper) + │ GLS_ADDRESS +[createShipmentUnit] + │ GLS_SHIPMENT_UNIT +[createPrintingOptions] + │ GLS_PRINTING_OPTIONS +[createShopDeliveryShipment] + │ GLS_CREATE_PARCELS_RESPONSE +[send to printer / store TrackID] +``` + +### Step-by-step + +**1. Create recipient address** +``` +createAddress( + Name1: "Jane Smith", + CountryCode: "DE", + City: "Hamburg", + Street: "Reeperbahn", + ZIPCode: "20359", + StreetNumber: "1", + eMail: "jane@example.com" +) +→ GLS_ADDRESS (recipient) +``` + +**2. Create parcel unit** +``` +createShipmentUnit( + weight: 1.2, + shipmentUnitReference: "ORDER-12345", + note1: "Handle with care" +) +→ GLS_SHIPMENT_UNIT +``` + +**3. Set printing options** +``` +createPrintingOptions( + returnLabels: { + TemplateSet: "NONE", + LabelFormat: "PDF" + } +) +→ GLS_PRINTING_OPTIONS +``` + +**4. Create the shipment** (using default shipper from config) +``` +createShopDeliveryShipment( + parcelShopId: "PSH-HH-001", + shipment: { + Product: "PARCEL", + Consignee: { + ConsigneeID: "CUST-5678", + Category: "PRIVATE", + Address: + }, + Shipper: {}, ← uses default shipper from action config + ShipmentUnit: [] + }, + printingOptions: +) +→ GLS_CREATE_PARCELS_RESPONSE +``` + +**5. Use the response** +- Store `CreatedShipment.ParcelData[0].TrackID` in your order database +- Decode `CreatedShipment.PrintData[0].Data` (base64 PDF) and send to printer + +--- + +## Use Case 2: Validate before creating + +**Scenario:** You want to check a shipment for errors before submitting it, to avoid unnecessary API charges or failed deliveries. + +### Flow + +``` +[Build shipment data] → GLS_SHIPMENT + │ +[validateShipment] + │ GLS_VALIDATE_SHIPMENT_RESPONSE_DATA + │ + success? ──Yes──→ [createShopDeliveryShipment] + │ + No + │ + [log errors / notify user] +``` + +### Example + +**1. Validate the shipment** +``` +validateShipment({ + Shipment: { + Product: "PARCEL", + Consignee: { + Address: { + Name1: "Test Recipient", + CountryCode: "DE", + City: "Berlin", + Street: "Hauptstrasse", + ZIPCode: "10115" + } + }, + Shipper: {}, + ShipmentUnit: [{ Weight: 0.5 }] + } +}) +→ GLS_VALIDATE_SHIPMENT_RESPONSE_DATA +``` + +**2. Check the result** +```json +{ + "success": true, + "validationResult": { "Issues": [] } +} +``` + +If `success` is `false`, inspect `validationResult.Issues` for details: +```json +{ + "success": false, + "validationResult": { + "Issues": [ + { + "Rule": "MIN_LENGTH", + "Location": "Shipment.Consignee.Address.Street", + "Parameters": ["4"] + } + ] + } +} +``` + +--- + +## Use Case 3: Return shipment + +**Scenario:** A customer wants to return an item. You generate a return label they can drop off at any GLS Parcel Shop. + +### Flow + +``` +[createAddress] (your warehouse as consignee for return) + │ +[createShipmentUnit] + │ +[createPrintingOptions] + │ +[createShopReturnShipment] + │ GLS_CREATE_PARCELS_RESPONSE + │ +[email PrintData to customer as PDF] +``` + +### Example + +``` +createShopReturnShipment( + numberOfLabels: 1, + shipment: { + Product: "PARCEL", + Consignee: { + Address: { + Name1: "My Warehouse GmbH", + CountryCode: "DE", + City: "Frankfurt", + Street: "Lagerstrasse", + ZIPCode: "60327" + } + }, + Shipper: {}, + ShipmentUnit: [{ Weight: 2.0 }] + }, + printingOptions: { + ReturnLabels: { + TemplateSet: "NONE", + LabelFormat: "PDF" + } + }, + returnQR: "PDF" +) +→ GLS_CREATE_PARCELS_RESPONSE +``` + +**Customer flow:** +1. Receive the PDF label by email +2. Print it (or show QR code on phone) +3. Drop off at any GLS Parcel Shop + +--- + +## Use Case 4: Identity-verified delivery (age-restricted goods) + +**Scenario:** You are shipping age-restricted goods (e.g. alcohol, medication) and need to verify the recipient's identity on delivery. + +### Flow + +``` +[createShipmentUnit] + │ +[createPrintingOptions] + │ +[createIdentShipment] + │ GLS_CREATE_PARCELS_RESPONSE +``` + +### Example + +``` +createIdentShipment( + birthDate: "1990-05-15", + firstName: "Hans", + lastName: "Mueller", + nationality: "DE", + shipment: { + Product: "PARCEL", + Consignee: { + Address: { + Name1: "Hans Mueller", + CountryCode: "DE", + City: "Munich", + Street: "Maximilianstrasse", + ZIPCode: "80333" + } + }, + Shipper: {}, + ShipmentUnit: [{ Weight: 1.8 }] + }, + printingOptions: { + ReturnLabels: { + TemplateSet: "NONE", + LabelFormat: "PDF" + } + } +) +``` + +The GLS driver will verify the recipient's ID against the provided name, birthdate, and nationality before handing over the parcel. + +--- + +## Use Case 5: End-of-day reconciliation + +**Scenario:** At the end of each business day, you want to fetch all shipments dispatched that day and reconcile them with your order management system. + +### Flow + +``` +[getEndOfDayReport({ date: "2025-01-15" })] + │ GLS_END_OF_DAY_RESPONSE_DATA + │ +[for each Shipment in response] + │ +[match TrackID to order / update status] +``` + +### Example + +``` +getEndOfDayReport({ + date: "2025-01-15" +}) +→ GLS_END_OF_DAY_RESPONSE_DATA +``` + +Response: +```json +{ + "Shipments": [ + { + "ShippingDate": "2025-01-15", + "Product": "PARCEL", + "Consignee": { + "Address": { "Name1": "Jane Smith", "City": "Hamburg", ... } + }, + "ShipmentUnit": [ + { "TrackID": "12345678", "Weight": "1.2", "ParcelNumber": "00123456789" } + ] + } + ] +} +``` + +--- + +## Use Case 6: Reprint a lost label + +**Scenario:** A shipping label was damaged in your warehouse. You need to reprint it before the parcel is picked up. + +### Flow + +``` +[reprintParcel({ TrackID, CreationDate, PrintingOptions })] + │ GLS_REPRINT_PARCEL_RESPONSE_DATA + │ +[decode PrintData and send to printer] +``` + +### Example + +``` +reprintParcel({ + TrackID: "12345678", + CreationDate: "2025-01-15", + PrintingOptions: { + ReturnLabels: { + TemplateSet: "NONE", + LabelFormat: "PDF" + } + } +}) +→ GLS_REPRINT_PARCEL_RESPONSE_DATA +``` + +--- + +## Use Case 7: Check available services for a route + +**Scenario:** Before creating a shipment, you want to check which GLS services are available between your depot (Berlin, DE) and a customer in France (Paris, 75001). + +### Flow + +``` +[getAllowedServices({ Source, Destination })] + │ GLS_ALLOWED_SERVICES_RESPONSE_DATA + │ +[filter AllowedServices list / present to user or use in logic] +``` + +### Example + +``` +getAllowedServices({ + Source: { + CountryCode: "DE", + ZIPCode: "10115" + }, + Destination: { + CountryCode: "FR", + ZIPCode: "75001" + } +}) +→ GLS_ALLOWED_SERVICES_RESPONSE_DATA +``` + +Response: +```json +{ + "AllowedServices": [ + { "ProductName": "PARCEL" }, + { "ServiceName": "FlexDeliveryService" }, + { "ServiceName": "SignatureService" } + ] +} +``` + +Use this to dynamically enable/disable delivery options in your checkout flow. + +--- + +## Use Case 8: Saturday express delivery + +**Scenario:** A customer orders on Friday and wants to receive their parcel on Saturday. + +> **Important:** Saturday delivery requires `Product: "EXPRESS"`. Using `"PARCEL"` will throw an error. + +### Flow + +``` +[createShipmentUnit] + │ +[createPrintingOptions] + │ +[createDeliverySaturdayShipment] + │ GLS_CREATE_PARCELS_RESPONSE +``` + +### Example + +``` +createDeliverySaturdayShipment( + shipment: { + Product: "EXPRESS", ← required! + Consignee: { + Address: { + Name1: "Weekend Shopper", + CountryCode: "DE", + City: "Cologne", + Street: "Schildergasse", + ZIPCode: "50667" + } + }, + Shipper: {}, + ShipmentUnit: [{ Weight: 0.8 }] + }, + printingOptions: { + ReturnLabels: { + TemplateSet: "NONE", + LabelFormat: "PDF" + } + } +) +``` diff --git a/docs/Guides/installation.md b/docs/Guides/installation.md index 36787ee..4fd3057 100644 --- a/docs/Guides/installation.md +++ b/docs/Guides/installation.md @@ -4,45 +4,120 @@ title: Installation guide for actions # Cloud edition -# Selfhosted +The cloud edition is managed by code0 and requires no installation. Contact the code0 team for access. -To install the Action on your self-hosted instance, follow these steps: +--- + +# Self-hosted + +To install an action on your self-hosted instance, follow these steps: + +## Prerequisites + +Before you begin, make sure you have the following: + +- **Git** installed on your machine +- **Docker** and **Docker Compose** installed +- A running **Aquila** server (part of the Hercules platform) +- Your `HERCULES_AUTH_TOKEN` from the Aquila admin panel +- Service-specific credentials (e.g. GLS API keys — see [GLS Configuration](../Actions/GLS/configs)) + +--- + +## 1. Clone the repository -## Clone the repository: ```bash git clone https://github.com/code0-tech/centaurus.git +cd centaurus +``` + +--- + +## 2. Navigate to the action directory + +Replace `` with the name of the action you want to deploy (e.g. `gls-action`): + +```bash +cd actions/ ``` -# +--- + +## 3. Create the `.env` file + +Copy the example environment file and fill in your values: -## Navigate to the action directory: ```bash -cd centaurus/actions/ +cp .example.env .env ``` -# +Then open `.env` in your editor and set the required variables: -## Create .env file and set the required environment variables: +### Common ENV variables (all actions) -Possible ENV variables: +| ENV Variable | Description | Default Value | Required | +|------------------------|-----------------------------------------------------|---------------------|----------| +| `HERCULES_AUTH_TOKEN` | Authentication token for connecting to Aquila. | `""` (empty string) | Yes | +| `HERCULES_AQUILA_URL` | URL of the Aquila server to connect to. | `"localhost:50051"` | Yes | +| `HERCULES_ACTION_ID` | Unique identifier for this action in Hercules. | `""` | Yes | +| `HERCULES_SDK_VERSION` | Version of the Hercules SDK being used. | `"0.0.0"` | No | -| ENV Variable | Description | Default Value | -|------------------------|------------------------------------------------|---------------------| -| `HERCULES_AUTH_TOKEN` | Authentication token for connecting to Aquila. | `""` (empty string) | -| `HERCULES_AQUILA_URL` | URL of the Aquila server to connect to. | `"localhost:50051"` | -| `HERCULES_ACTION_ID` | Identifier for the action being registered. | `""` | -| `HERCULES_SDK_VERSION` | Version of the Hercules SDK being used. | `"0.0.0"` | +Example `.env` for the GLS action: -Example (.env): -``` -HERCULES_AUTH_TOKEN=your_auth_token -... +```env +HERCULES_AUTH_TOKEN=your_hercules_auth_token +HERCULES_AQUILA_URL=your-aquila-host:50051 +HERCULES_ACTION_ID=gls-action +HERCULES_SDK_VERSION=1.0.0 ``` -# +For action-specific variables (e.g. GLS API credentials), see the [GLS Configuration](../Actions/GLS/configs) page. + +--- + +## 4. Start with Docker Compose -## Install it via docker: ```bash docker compose up -d ``` +The action will start, connect to your Aquila server, and register its functions and types. You can check the logs with: + +```bash +docker compose logs -f +``` + +A successful startup will show: + +``` +SDK connected successfully +``` + +--- + +## 5. Verify the action is registered + +Open your Hercules/Aquila admin panel and navigate to the **Actions** section. The action should appear in the list with its registered functions and types. + +--- + +## Updating the action + +To update to a newer version: + +```bash +git pull +docker compose up -d --build +``` + +--- + +## Troubleshooting + +If the action fails to start or connect, check: + +- That `HERCULES_AUTH_TOKEN` is valid and not expired +- That `HERCULES_AQUILA_URL` points to the correct host and port +- That Docker has access to the internet (for pulling the base image) +- The service-specific credentials are correct (see [Troubleshooting](../Actions/GLS/troubleshooting.md)) + diff --git a/docs/index.mdx b/docs/index.mdx index cfb4cab..40b68f5 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -6,4 +6,38 @@ template: splash ## What is Centaurus? -Centaurus is a repository with a collection of actions provided by code0. \ No newline at end of file +Centaurus is a monorepo containing a collection of **actions** provided by [code0](https://github.com/code0-tech). Actions are integrations that connect external services to the **Hercules** automation platform, allowing you to build powerful workflows without writing boilerplate code. + +Each action exposes **functions**, **data types**, and **configuration** that can be composed inside flows to automate real-world tasks such as shipping logistics, notifications, payments, and more. + +--- + +## Prerequisites + +Before using any action from Centaurus, make sure you have: + +- **Docker** and **Docker Compose** installed (for self-hosted deployment) +- A running instance of the **Aquila** server (part of the Hercules platform) +- An **auth token** (`HERCULES_AUTH_TOKEN`) for connecting your action to Aquila +- Credentials specific to the external service the action integrates with (e.g. GLS API keys) + +--- + +## Available Actions + +| Action | Description | Status | +|--------|-------------|--------| +| [GLS](./Actions/GLS/overview.md) | GLS ShipIT integration for creating and managing shipments | ✅ Available | + +--- + +## Quick Links + +- [Installation Guide](./Guides/installation.md) — How to deploy an action on your self-hosted instance +- [GLS Action Overview](./Actions/GLS/overview.md) — Get started with the GLS shipping integration +- [GLS Configuration](./Actions/GLS/configs.md) — API keys and configuration options +- [GLS Functions](./Actions/GLS/functions.md) — All available functions and their parameters +- [GLS Types](./Actions/GLS/types.md) — Data types used across the GLS action +- [GLS Events](./Actions/GLS/events.md) — Events emitted by the GLS action +- [Common Use Cases](./Actions/GLS/use-cases.md) — Example workflows using the GLS action +- [Troubleshooting](./Actions/GLS/troubleshooting.md) — FAQ and community support \ No newline at end of file From fd0ea43e88777ceffef38ade415ecacc50a279ea Mon Sep 17 00:00:00 2001 From: Dario Pranjic Date: Thu, 19 Mar 2026 13:51:23 +0100 Subject: [PATCH 3/3] Refine docs --- actions/gls-action/src/helpers.ts | 22 ++-- actions/gls-action/src/types.ts | 2 +- docs/Actions/GLS/configs.md | 2 +- docs/Actions/GLS/events.md | 158 +--------------------------- docs/Actions/GLS/functions.md | 12 +-- docs/Actions/GLS/overview.md | 18 ++-- docs/Actions/GLS/troubleshooting.md | 34 +----- docs/Actions/GLS/types.md | 48 ++++----- docs/Guides/installation.md | 2 +- 9 files changed, 57 insertions(+), 241 deletions(-) diff --git a/actions/gls-action/src/helpers.ts b/actions/gls-action/src/helpers.ts index 591b328..87a4898 100644 --- a/actions/gls-action/src/helpers.ts +++ b/actions/gls-action/src/helpers.ts @@ -245,7 +245,7 @@ export function transformValidateShipmentRequestDataToInternalFormat(data: Valid Shipment: { ...data.Shipment, Middleware: "CodeZeroviaGLS", - Shipper: getShipper(data.Shipment.Shipper, context, contactID), + Shipper: getShipper(context, contactID, data.Shipment.Shipper), Service: InternalShipmentServiceSchema.parse(data.Shipment.Service), ShipmentUnit: InternalShipmentUnitSchema.parse(data.Shipment.ShipmentUnit) } @@ -258,27 +258,31 @@ function transformShipmentRequestDataToInternalFormat(data: ShipmentRequestData, Shipment: { ...data.Shipment, Middleware: "CodeZeroviaGLS", - Shipper: getShipper(data.Shipment.Shipper, context, contactID), + Shipper: getShipper(context, contactID, data.Shipment.Shipper), Service: InternalShipmentServiceSchema.parse(data.Shipment.Service), ShipmentUnit: InternalShipmentUnitSchema.parse(data.Shipment.ShipmentUnit) } } } -function getShipper(shipper: Shipper, context: HerculesFunctionContext | undefined, contactID: string | undefined): InternalShipper { +function getShipper(context: HerculesFunctionContext | undefined, contactID: string | undefined, shipper?: Shipper): InternalShipper { const configShipper = context?.matchedConfig.findConfig("shipper") as Shipper || undefined - if (configShipper) { - return { - ...configShipper, - ContactID: contactID - } - } else { + if (!shipper && !configShipper) { + throw new RuntimeErrorException("MISSING_SHIPPER_INFORMATION", "No shipper information provided in shipment data or configuration.") + } + + if (shipper) { return { ...shipper, ContactID: contactID } } + + return { + ...configShipper, + ContactID: contactID + } } export async function postShipmentHelper(context: HerculesFunctionContext, services: ShipmentService, shipment: ShipmentWithoutServices, printingOptions: PrintingOptions, customContent?: CustomContent, returnOptions?: ReturnOptions): Promise { diff --git a/actions/gls-action/src/types.ts b/actions/gls-action/src/types.ts index e6de0ce..5011450 100644 --- a/actions/gls-action/src/types.ts +++ b/actions/gls-action/src/types.ts @@ -309,7 +309,7 @@ export const ShipmentSchema = z.object({ Product: z.enum(["PARCEL", "EXPRESS"]), ExpressAltDeliveryAllowed: z.boolean().optional(), Consignee: ConsigneeSchema, - Shipper: ShipperSchema, + Shipper: ShipperSchema.optional(), Carrier: z.enum(["ROYALMAIL"]).optional(), ShipmentUnit: ShipmentUnitSchema, Service: ShipmentServiceSchema, diff --git a/docs/Actions/GLS/configs.md b/docs/Actions/GLS/configs.md index 5b2cac2..3381ba0 100644 --- a/docs/Actions/GLS/configs.md +++ b/docs/Actions/GLS/configs.md @@ -107,4 +107,4 @@ The value must be a valid `GLS_SHIPPER` object: } ``` -See [Types — GLS_SHIPPER](./types#GLS_SHIPPER) for the full field reference. +See [Types — GLS_SHIPPER](../types/#GLS_SHIPPER) for the full field reference. diff --git a/docs/Actions/GLS/events.md b/docs/Actions/GLS/events.md index 7f648bf..1aad1ba 100644 --- a/docs/Actions/GLS/events.md +++ b/docs/Actions/GLS/events.md @@ -9,166 +9,10 @@ In the Hercules platform, **events** are notifications emitted **by an action** --- -## How events work - -``` -External world (e.g. GLS webhook / polling) - │ - │ something happens (parcel delivered, shipment arrived, ...) - ▼ - GLS Action - │ - │ sdk.dispatchEvent(eventType, projectId, payload) - ▼ - Aquila - │ - │ routes event to all flows listening for eventType - ▼ - Your Flow starts - │ - │ event payload available as flow input - ▼ - Flow nodes execute (functions, conditions, etc.) -``` - -An event carries a **payload** — the data associated with what happened (e.g. shipment details, tracking ID, status). Flows that subscribe to an event type receive this payload as their starting input. - ---- - ## Current status > **The GLS Action does not currently emit any events.** > > The GLS action presently only exposes **functions** (called by flows) and registers **data types** and **configuration**. Event support — where the action proactively notifies Aquila of changes — is **planned for a future release**. ---- - -## Planned events - -The following events are candidates for future implementation. Once added, each will allow you to build flows that react automatically to GLS shipment lifecycle changes. - -### `gls.shipment.arrived` - -Emitted when a parcel arrives at a GLS depot or is scanned into the GLS network. - -**Trigger mechanism:** The action would periodically poll the GLS tracking API (or receive a GLS webhook) and emit this event for each new scan. - -**Payload type (planned):** `GLS_TRACKING_EVENT` - -``` -GLS Action (polling / webhook listener) - │ - │ detects new scan for tracked parcel - ▼ -sdk.dispatchEvent("gls.shipment.arrived", projectId, { - TrackID: "12345678", - Status: "IN_TRANSIT", - Location: "MUC-HUB", - Timestamp: "2025-06-01T10:30:00Z" -}) - │ - ▼ -Aquila → triggers all flows subscribed to "gls.shipment.arrived" -``` - ---- - -### `gls.shipment.delivered` - -Emitted when a parcel is confirmed delivered to the recipient. - -**Payload type (planned):** `GLS_TRACKING_EVENT` - -``` -sdk.dispatchEvent("gls.shipment.delivered", projectId, { - TrackID: "12345678", - Status: "DELIVERED", - DeliveredAt: "2025-06-02T14:15:00Z", - SignedBy: "J. Doe" -}) -``` - ---- - -### `gls.shipment.failed` - -Emitted when a delivery attempt fails (e.g. recipient not home, address problem). - -**Payload type (planned):** `GLS_TRACKING_EVENT` - -``` -sdk.dispatchEvent("gls.shipment.failed", projectId, { - TrackID: "12345678", - Status: "DELIVERY_FAILED", - Reason: "RECIPIENT_NOT_HOME", - NextAttempt: "2025-06-03" -}) -``` - ---- - -### `gls.shipment.returned` - -Emitted when a parcel is returned to sender after failed delivery attempts. - ---- - -## How events are implemented (SDK reference) - -When events are added to the GLS Action, they will follow this pattern from the Hercules SDK: - -### 1. Register the flow type (event definition) - -```typescript -sdk.registerFlowTypes({ - identifier: "gls.shipment.arrived", - editable: false, - inputType: "GLS_TRACKING_EVENT", - linkedDataTypes: ["GLS_TRACKING_EVENT"], - name: [{ code: "en-US", content: "GLS Shipment Arrived" }], - description: [{ - code: "en-US", - content: "Triggered when a GLS parcel arrives at a depot or is scanned." - }] -}) -``` - -### 2. Dispatch the event when it occurs - -```typescript -sdk.dispatchEvent( - "gls.shipment.arrived", // must match registered flow type identifier - projectId, // which project to notify - payload // data payload (must match inputType) -) -``` - -### 3. User builds a flow triggered by the event - -In the Hercules UI, users create a flow with **"GLS Shipment Arrived"** as the trigger. When the GLS action dispatches this event, Aquila starts the flow and provides the payload (e.g. `TrackID`, `Status`, `Location`) as the flow's input. - ---- - -## Flow type settings - -Flow types can expose **settings** that allow users to configure how an event filters or behaves. For example, a future `gls.shipment.arrived` event might let users specify: - -| Setting | Type | Description | -|---------|------|-------------| -| `trackId` | string | Only trigger for a specific parcel | -| `statusFilter` | string[] | Only trigger for specific status codes | - -Settings are defined in the `settings` array of `HerculesFlowType` and are configurable per-flow in the Hercules UI. - ---- - -## Difference between events and functions - -| | Events | Functions | -|-|--------|-----------| -| **Direction** | Action → Aquila | Flow → Action | -| **Who initiates** | The action (proactively) | The flow (on demand) | -| **Purpose** | React to something that happened externally | Perform an operation and return a result | -| **SDK method** | `registerFlowTypes` + `dispatchEvent` | `registerFunctionDefinitions` | -| **Example** | Parcel delivered → trigger notification flow | Create a shipment and return the label | -| **Current GLS status** | ❌ Not yet implemented | ✅ 26 functions available | +--- \ No newline at end of file diff --git a/docs/Actions/GLS/functions.md b/docs/Actions/GLS/functions.md index f332c3c..6c12769 100644 --- a/docs/Actions/GLS/functions.md +++ b/docs/Actions/GLS/functions.md @@ -56,7 +56,7 @@ createAddress( | `MobilePhonenumber` | string (min 4, max 35) | No | Mobile phone number | | `eMail` | string (max 80) | No | Email address | -**Returns:** [`GLS_ADDRESS`](./types#GLS_ADDRESS) +**Returns:** [`GLS_ADDRESS`](../types#GLS_ADDRESS) --- @@ -83,7 +83,7 @@ createConsignee( | `Address` | GLS_ADDRESS | **Yes** | The delivery address for this consignee | | `Category` | `"BUSINESS"` \| `"PRIVATE"` | **Yes** | Whether the consignee is a business or private recipient | -**Returns:** [`GLS_CONSIGNEE`](./types#GLS_CONSIGNEE) +**Returns:** [`GLS_CONSIGNEE`](../types#GLS_CONSIGNEE) --- @@ -114,7 +114,7 @@ createShipmentUnit( | `note2` | string (max 50) | No | Additional note printed on the label (line 2) | | `shipmentUnitService` | GLS_UNIT_SERVICE | No | Unit-level services (Cash, AddonLiability, HazardousGoods, etc.) | -**Returns:** [`GLS_SHIPMENT_UNIT`](./types#GLS_SHIPMENT_UNIT) +**Returns:** [`GLS_SHIPMENT_UNIT`](../types#GLS_SHIPMENT_UNIT) --- @@ -140,7 +140,7 @@ createPrintingOptions(returnLabels: RETURN_LABELS): GLS_PRINTING_OPTIONS | `TemplateSet` | `NONE`, `D_200`, `PF_4_I`, `ZPL_200`, `ZPL_300`, ... | Label template set | | `LabelFormat` | `PDF`, `ZEBRA`, `INTERMEC`, `DATAMAX`, `TOSHIBA`, `PNG` | Output format | -**Returns:** [`GLS_PRINTING_OPTIONS`](./types#GLS_PRINTING_OPTIONS) +**Returns:** [`GLS_PRINTING_OPTIONS`](../types#GLS_PRINTING_OPTIONS) --- @@ -169,7 +169,7 @@ createCustomContent( | `barcodeType` | `"EAN_128"` \| `"CODE_39"` | No | Barcode symbology | | `barcode` | string | No | Custom barcode value | -**Returns:** [`GLS_CUSTOM_CONTENT`](./types#GLS_CUSTOM_CONTENT) +**Returns:** [`GLS_CUSTOM_CONTENT`](../types#GLS_CUSTOM_CONTENT) --- @@ -536,7 +536,7 @@ validateShipment └── validationResult.Issues[] ``` -See [Types — GLS_VALIDATE_SHIPMENT_REQUEST_DATA](./types#GLS_VALIDATE_SHIPMENT_REQUEST_DATA) for the input format. +See [Types — GLS_VALIDATE_SHIPMENT_REQUEST_DATA](../types#GLS_VALIDATE_SHIPMENT_REQUEST_DATA) for the input format. --- diff --git a/docs/Actions/GLS/overview.md b/docs/Actions/GLS/overview.md index 01f150e..3a06eaa 100644 --- a/docs/Actions/GLS/overview.md +++ b/docs/Actions/GLS/overview.md @@ -5,7 +5,7 @@ description: Overview of the GLS ShipIT action — what it does, what you need t # GLS Action -The **GLS Action** integrates the [GLS ShipIT API](https://api.gls-group.net) into the Hercules automation platform. It lets you create, validate, cancel, and manage GLS parcel shipments directly from your flows — no manual API calls required. +The **GLS Action** integrates the [GLS ShipIT API](https://dev-portal.gls-group.net/docs/shipit-farm/1/overview) as an action. It lets you create, validate, cancel, and manage GLS parcel shipments directly from your flows — no manual API calls required. --- @@ -49,7 +49,7 @@ Before using the GLS Action you will need: ## Architecture overview ``` -Your Flow (Hercules) +Your Flow │ ▼ GLS Action (this action) @@ -87,10 +87,10 @@ GLS_CREATE_PARCELS_RESPONSE ← tracking IDs, barcode data, print data, routing ## Next steps -- [Quick Start](./quick-start) — Create your first shipment in a few steps -- [Configuration](./configs) — Full list of configuration options and how to get credentials -- [Functions](./functions) — All available functions with parameter details -- [Types](./types) — All data types used in the GLS Action -- [Events](./events) — Events emitted by the GLS Action -- [Common Use Cases](./use-cases) — Example flows for real-world scenarios -- [Troubleshooting](./troubleshooting) — FAQ and community support +- [Quick Start](../quick-start) — Create your first shipment in a few steps +- [Configuration](../configs) — Full list of configuration options and how to get credentials +- [Functions](../functions) — All available functions with parameter details +- [Types](../types) — All data types used in the GLS Action +- [Events](../events) — Events emitted by the GLS Action +- [Common Use Cases](../use-cases) — Example flows for real-world scenarios +- [Troubleshooting](../troubleshooting) — FAQ and community support diff --git a/docs/Actions/GLS/troubleshooting.md b/docs/Actions/GLS/troubleshooting.md index f313430..d6ed3fb 100644 --- a/docs/Actions/GLS/troubleshooting.md +++ b/docs/Actions/GLS/troubleshooting.md @@ -30,7 +30,7 @@ A: The action supports all major GLS shipment types and services, including: - Tyre service, addressee-only delivery - Saturday and next-working-day delivery (EXPRESS only) -See [Functions](./functions) for the complete list. +See [Functions](../functions.md) for the complete list. --- @@ -63,29 +63,8 @@ A: Check the following: --- -**Q: I get "Failed to register config definitions" on startup. What does that mean?** - -A: This means the action could not register its configuration schema with the Aquila server. Check: -- The Aquila server is running and healthy -- The `HERCULES_AUTH_TOKEN` has sufficient permissions -- The action ID (`HERCULES_ACTION_ID`) is not already registered with a conflicting schema - ---- - -**Q: The action shows "SDK connected successfully" but my functions don't appear in Hercules.** - -A: Wait a few seconds — registration can take a moment. Then refresh the Hercules UI. If functions still don't appear, check that the action's `HERCULES_ACTION_ID` matches what is configured in Hercules. - ---- - ### Authentication & API errors -**Q: I get a 401 Unauthorized error when the action tries to call the GLS API.** - -A: Your `client_id` or `client_secret` is incorrect, or your GLS application does not have the required API scopes. Verify your credentials on the [GLS Developer Portal](https://dev-portal.gls-group.net) and ensure the **ShipIT** scope is enabled. - ---- - **Q: I get an `INVALID_PRODUCT` error when creating a Saturday delivery shipment.** A: Saturday delivery (and next-working-day delivery) requires the shipment's `Product` to be set to `"EXPRESS"`. Change `Product: "PARCEL"` to `Product: "EXPRESS"` in your shipment data. @@ -104,11 +83,6 @@ A: No. Once GLS has scanned the parcel at a depot or delivery vehicle, cancellat --- -**Q: My token expires frequently. Can I adjust the refresh interval?** - -A: The action automatically refreshes tokens 60 seconds before they expire. This is hard-coded and cannot be changed through configuration. GLS OAuth2 tokens typically have a validity of 1 hour. - ---- ### Labels & printing @@ -212,9 +186,3 @@ Open a pull request against the `main` branch of [code0-tech/centaurus](https:// | `npm run lint` | Run ESLint | | `npm run create-action -- ` | Scaffold a new action | -### Code conventions - -- All types must use **Zod schemas** with a matching `Schema` suffix (e.g. `AddressSchema` / `Address`) -- All registered types must have identifiers starting with `GLS_` (for the GLS action) -- All function definitions must include `name` and `description` in `en-US` -- Functions that call external APIs must wrap errors in `RuntimeErrorException` diff --git a/docs/Actions/GLS/types.md b/docs/Actions/GLS/types.md index 478a3e7..93a5fa0 100644 --- a/docs/Actions/GLS/types.md +++ b/docs/Actions/GLS/types.md @@ -9,7 +9,7 @@ The GLS Action registers the following data types with the Hercules platform. Th --- -## `GLS_ADDRESS` {#GLS_ADDRESS} +## `GLS_ADDRESS` Represents a physical address used for consignee, shipper, and return addresses. @@ -33,7 +33,7 @@ Represents a physical address used for consignee, shipper, and return addresses. --- -## `GLS_CONSIGNEE` {#GLS_CONSIGNEE} +## `GLS_CONSIGNEE` Represents the recipient of a shipment. @@ -50,7 +50,7 @@ Represents the recipient of a shipment. --- -## `GLS_SHIPPER` {#GLS_SHIPPER} +## `GLS_SHIPPER` Represents the sender of a shipment. @@ -67,7 +67,7 @@ Represents the sender of a shipment. --- -## `GLS_UNIT_SERVICE` {#GLS_UNIT_SERVICE} +## `GLS_UNIT_SERVICE` An optional array of value-added services applied to an individual shipment unit (parcel). @@ -85,7 +85,7 @@ Each element is an object with one or more of the following optional fields: --- -## `GLS_SHIPMENT_UNIT` {#GLS_SHIPMENT_UNIT} +## `GLS_SHIPMENT_UNIT` Represents a single parcel within a shipment. A shipment may contain multiple units. @@ -104,7 +104,7 @@ Represents a single parcel within a shipment. A shipment may contain multiple un --- -## `GLS_SHIPMENT_SERVICE` {#GLS_SHIPMENT_SERVICE} +## `GLS_SHIPMENT_SERVICE` An optional array of shipment-level services. Shipment creation functions automatically populate this based on which function you call. @@ -134,7 +134,7 @@ Each element is an object with one of the following service fields: --- -## `GLS_SHIPMENT` {#GLS_SHIPMENT} +## `GLS_SHIPMENT` The complete shipment object including all services. @@ -159,7 +159,7 @@ The complete shipment object including all services. --- -## `GLS_SHIPMENT_WITHOUT_SERVICES` {#GLS_SHIPMENT_WITHOUT_SERVICES} +## `GLS_SHIPMENT_WITHOUT_SERVICES` The shipment object without the `Service` field. Used as input to all shipment creation functions — the service is added automatically based on which function you call. @@ -169,7 +169,7 @@ Same fields as `GLS_SHIPMENT` except `Service` is omitted. --- -## `GLS_PRINTING_OPTIONS` {#GLS_PRINTING_OPTIONS} +## `GLS_PRINTING_OPTIONS` Configures how shipping labels are generated. @@ -184,7 +184,7 @@ Configures how shipping labels are generated. --- -## `GLS_RETURN_OPTIONS` {#GLS_RETURN_OPTIONS} +## `GLS_RETURN_OPTIONS` Controls whether the GLS API includes print data and routing info in the response. @@ -197,7 +197,7 @@ Controls whether the GLS API includes print data and routing info in the respons --- -## `GLS_CUSTOM_CONTENT` {#GLS_CUSTOM_CONTENT} +## `GLS_CUSTOM_CONTENT` Customizes what appears on the printed shipping label. @@ -211,7 +211,7 @@ Customizes what appears on the printed shipping label. --- -## `GLS_CREATE_PARCELS_RESPONSE` {#GLS_CREATE_PARCELS_RESPONSE} +## `GLS_CREATE_PARCELS_RESPONSE` The response returned by all shipment creation functions. @@ -236,7 +236,7 @@ The response returned by all shipment creation functions. --- -## `GLS_CANCEL_SHIPMENT_REQUEST_DATA` {#GLS_CANCEL_SHIPMENT_REQUEST_DATA} +## `GLS_CANCEL_SHIPMENT_REQUEST_DATA` Input for the `cancelShipment` function. @@ -246,7 +246,7 @@ Input for the `cancelShipment` function. --- -## `GLS_CANCEL_SHIPMENT_RESPONSE_DATA` {#GLS_CANCEL_SHIPMENT_RESPONSE_DATA} +## `GLS_CANCEL_SHIPMENT_RESPONSE_DATA` Response from the `cancelShipment` function. @@ -257,7 +257,7 @@ Response from the `cancelShipment` function. --- -## `GLS_ALLOWED_SERVICES_REQUEST_DATA` {#GLS_ALLOWED_SERVICES_REQUEST_DATA} +## `GLS_ALLOWED_SERVICES_REQUEST_DATA` Input for the `getAllowedServices` function. @@ -271,7 +271,7 @@ Input for the `getAllowedServices` function. --- -## `GLS_ALLOWED_SERVICES_RESPONSE_DATA` {#GLS_ALLOWED_SERVICES_RESPONSE_DATA} +## `GLS_ALLOWED_SERVICES_RESPONSE_DATA` Response from the `getAllowedServices` function. @@ -285,7 +285,7 @@ Each element contains either `ServiceName` or `ProductName`, not both. --- -## `GLS_END_OF_DAY_REQUEST_DATA` {#GLS_END_OF_DAY_REQUEST_DATA} +## `GLS_END_OF_DAY_REQUEST_DATA` Input for the `getEndOfDayReport` function. @@ -295,7 +295,7 @@ Input for the `getEndOfDayReport` function. --- -## `GLS_END_OF_DAY_RESPONSE_DATA` {#GLS_END_OF_DAY_RESPONSE_DATA} +## `GLS_END_OF_DAY_RESPONSE_DATA` Response from the `getEndOfDayReport` function. @@ -312,7 +312,7 @@ Response from the `getEndOfDayReport` function. --- -## `GLS_UPDATE_PARCEL_WEIGHT_REQUEST_DATA` {#GLS_UPDATE_PARCEL_WEIGHT_REQUEST_DATA} +## `GLS_UPDATE_PARCEL_WEIGHT_REQUEST_DATA` Input for the `updateParcelWeight` function. Provide at least one identifier (`TrackID`, `ParcelNumber`, `ShipmentReference`, `ShipmentUnitReference`, or `PartnerParcelNumber`). @@ -327,7 +327,7 @@ Input for the `updateParcelWeight` function. Provide at least one identifier (`T --- -## `GLS_UPDATE_PARCEL_WEIGHT_RESPONSE_DATA` {#GLS_UPDATE_PARCEL_WEIGHT_RESPONSE_DATA} +## `GLS_UPDATE_PARCEL_WEIGHT_RESPONSE_DATA` Response from the `updateParcelWeight` function. @@ -337,7 +337,7 @@ Response from the `updateParcelWeight` function. --- -## `GLS_REPRINT_PARCEL_REQUEST_DATA` {#GLS_REPRINT_PARCEL_REQUEST_DATA} +## `GLS_REPRINT_PARCEL_REQUEST_DATA` Input for the `reprintParcel` function. Provide at least one identifier. @@ -354,7 +354,7 @@ Input for the `reprintParcel` function. Provide at least one identifier. --- -## `GLS_REPRINT_PARCEL_RESPONSE_DATA` {#GLS_REPRINT_PARCEL_RESPONSE_DATA} +## `GLS_REPRINT_PARCEL_RESPONSE_DATA` Response from the `reprintParcel` function. Same structure as `GLS_CREATE_PARCELS_RESPONSE` without the `ShipmentReference` and `GDPR` fields. @@ -373,7 +373,7 @@ Response from the `reprintParcel` function. Same structure as `GLS_CREATE_PARCEL --- -## `GLS_VALIDATE_SHIPMENT_REQUEST_DATA` {#GLS_VALIDATE_SHIPMENT_REQUEST_DATA} +## `GLS_VALIDATE_SHIPMENT_REQUEST_DATA` Input for the `validateShipment` function. @@ -383,7 +383,7 @@ Input for the `validateShipment` function. --- -## `GLS_VALIDATE_SHIPMENT_RESPONSE_DATA` {#GLS_VALIDATE_SHIPMENT_RESPONSE_DATA} +## `GLS_VALIDATE_SHIPMENT_RESPONSE_DATA` Response from the `validateShipment` function. diff --git a/docs/Guides/installation.md b/docs/Guides/installation.md index 4fd3057..58747fa 100644 --- a/docs/Guides/installation.md +++ b/docs/Guides/installation.md @@ -64,7 +64,7 @@ Then open `.env` in your editor and set the required variables: Example `.env` for the GLS action: -```env +``` HERCULES_AUTH_TOKEN=your_hercules_auth_token HERCULES_AQUILA_URL=your-aquila-host:50051 HERCULES_ACTION_ID=gls-action