# NGauge Delivery – Palletforce

Yii2 module for integrating with the **Palletforce Alliance REST API** to create, manage, track and label pallet consignments.

## Requirements

| Dependency | Version |
|-----------|---------|
| PHP | ≥ 8.0 |
| Yii2 | ~2.0 |
| Guzzle | ^7.0 |

> **API credentials** (base URL + access key) are **not** in the public documentation.  
> They are issued by Palletforce IT only after full testing sign-off.

---

## Module Structure

```
src/
├── Module.php                         Bootstrap, URL rules, component registration
├── components/
│   └── PalletforceClient.php          REST API wrapper (all 9 endpoints)
├── controllers/
│   ├── ConfigController.php           Web UI for settings & connection test
│   └── ConsignmentController.php      Create, accept, cancel, track, labels, ETA
├── jobs/
│   └── ConsignmentJob.php             Async queue job for consignment dispatch
├── models/
│   ├── ConfigForm.php                 Settings form + params-local.php persistence
│   └── ConsignmentForm.php            Consignment validation + API payload builder
└── views/
    ├── config/index.php               Config UI
    └── consignment/create.php         New consignment form
```

---

## Installation

### 1. Add to `composer.json`

```json
{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://dev.azure.com/PortalPeopleUK/NGauge_Modules/_git/ngauge-delivery-palletforce"
        }
    ],
    "require": {
        "portalpeople/ngauge-delivery-palletforce": "^1.0"
    }
}
```

### 2. Register the module

In `backend/config/main.php`:

```php
'modules' => [
    'palletforce' => [
        'class' => \PortalPeople\palletforce\Module::class,
    ],
],
'bootstrap' => ['palletforce'],
```

### 3. Configure credentials

In `backend/config/params-local.php`:

```php
'plugins' => [
    'palletforce' => [
        'enabled'       => true,
        'apiUrl'        => 'https://api.palletforce.com',   // provided by Palletforce IT
        'accessKey'     => Security::encryptSensitiveData('YOUR_KEY'),
        'accountNumber' => 'XXXXXXX',
        'depotCode'     => '000',
        'debug'         => false,
    ],
],
```

**Never commit plain-text credentials.** Use `Security::encryptSensitiveData()` or equivalent.

---

## API Endpoints Covered

| Method | Description |
|--------|-------------|
| `uploadManifest` | Create/update a consignment |
| `acceptConsignments` | Accept pending consignments |
| `deleteConsignment` | Cancel a consignment before acceptance |
| `downloadManifest` | Fetch consignments from Alliance |
| `downloadShippingInfo` | Full shipping details for a consignment |
| `downloadTrackingData` | Tracking events + POD image (Base64) |
| `downloadETATimes` | ETA windows for consignments |
| `downloadHubBuilding` | Resolve Hub vs postcode |
| `printLabels` | Retrieve Base64 thermal label images |

---

## Rate Limit

Palletforce enforces **one API call maximum every 30 minutes**. Error code `-6` is returned when the limit is exceeded. If using the queue, configure a suitable delay between jobs.

---

## Service Codes

| Code | Description |
|------|-------------|
| A | 24 Hours |
| B | 48 Hours |
| C | 72 Hours |
| D | 3–5 Days |

## Pallet Types

| Code | Name | Max Height | Max Weight |
|------|------|-----------|-----------|
| F | Full | 2.44 m | 1250 kg |
| H | Half | 2.0 m | 500 kg |
| Q | Quarter | 1.0 m | 250 kg |
| O | Oversize | >2.44 m | > 1250 kg |

---

## Error Codes

| Code | Description |
|------|-------------|
| -1 | Invalid Access Key |
| -2 | Consignment Not Found |
| -3 | Invalid Consignment |
| -6 | Rate Limit Reached |
| -10 | Invalid Date Format |
| -999 | Generic Error |

_See `docs/API Intergration.pdf` for the full error code reference._
