Skip to main content

DPD/BRT Integration - Phase 1 Completion

βœ… What Has Been Implemented​

1. Core API Client (DpdApi.php)​

Location: src/CoreBundle/Api/DpdApi.php

Features:

  • βœ… REST API client for DPD/BRT shipment API
  • βœ… Create shipment with label generation (PDF)
  • βœ… Confirm shipment (for explicit confirmation mode)
  • βœ… Delete shipment
  • βœ… Calculate routing
  • βœ… Get tracking information by parcel ID
  • βœ… Error handling with detailed logging
  • βœ… Comprehensive PHPDoc comments

Key Methods:

// Create shipment and get PDF labels
$response = $dpdApi->createShipment($createData, true);

// Get tracking info
$tracking = $dpdApi->getTrackingByParcelId($parcelId);

// Get tracking URL for customers
$url = $dpdApi->getTrackingUrl($parcelId);

// Extract labels from response
$labels = $dpdApi->extractLabels($response);

2. Business Logic Service (DpdService.php)​

Location: src/CoreBundle/Services/DpdService.php

Features:

  • βœ… Create shipments for sale products
  • βœ… Save PDF labels to disk (/web/pdf_dpd/)
  • βœ… Update SaleProduct with generic fields (Geodis pattern):
    • carrier = 'DPD'
    • tracking_id = parcel ID
    • shipment_infos = JSON response
    • expedition_ticket_files = PDF paths
    • track_links = tracking URLs
  • βœ… Use ShipmentTrackingSynchronizer for consistency
  • βœ… Event dispatching (SaleProductsShippedEvent, etc.)
  • βœ… Comprehensive error handling
  • βœ… Tracking synchronization support

Key Method:

$dpdService = $container->get('CoreBundle\Services\DpdService');
$dpdService->createSaleProductShipment(
$saleProductIds, // Array of SaleProduct IDs
$userId, // User creating shipment
false, // Log changes
true // Send notifications
);

3. Service Registration​

Location: src/CoreBundle/Resources/config/services.yml

Added:

parameters:
mz.dpd.api.class: CoreBundle\Api\DpdApi
mz.dpd.service.class: CoreBundle\Services\DpdService

services:
mz.dpd.api:
class: "%mz.dpd.api.class%"
arguments:
- "@logger"
- "%dpd.api_url%"
- "%dpd.user_id%"
- "%dpd.password%"
tags:
- { name: monolog.logger, channel: logidav_dpd }

CoreBundle\Services\DpdService:
class: "%mz.dpd.service.class%"
autowire: true
lazy: true

4. Configuration Parameters​

Location: app/config/parameters.yml.dist

Added:

dpd:
api_url: 'https://api.brt.it'
user_id: 'YOUR_DPD_USER_ID'
password: 'YOUR_DPD_PASSWORD'
customer_code: 123456 # Your BRT customer code
departure_depot: 123 # Your departure depot code
operating_mode: 'auto' # 'auto' or 'explicit'

πŸ”§ Setup Instructions​

Step 1: Copy Configuration​

Copy parameters.yml.dist to parameters.yml (if not already done):

cp app/config/parameters.yml.dist app/config/parameters.yml

Step 2: Configure DPD Credentials​

Edit app/config/parameters.yml and update the DPD section with your credentials:

dpd:
api_url: 'https://api.brt.it' # Production URL
user_id: 'your_actual_user_id'
password: 'your_actual_password'
customer_code: 456789 # Your actual customer code
departure_depot: 123 # Your actual depot code
operating_mode: 'auto'

Step 3: Create PDF Directory​

Create the directory for storing DPD labels:

mkdir -p web/pdf_dpd
chmod 755 web/pdf_dpd

Step 4: Clear Symfony Cache​

php bin/console cache:clear

πŸ§ͺ Testing​

Test 1: Verify Service Registration​

php bin/console debug:container mz.dpd.api
php bin/console debug:container CoreBundle\Services\DpdService

Expected output: Service definitions should be displayed.

Test 2: Test API Connection (Create Test Script)​

Create scripts/test_dpd_api.php:

<?php
require __DIR__ . '/../vendor/autoload.php';

use Symfony\Component\DependencyInjection\ContainerBuilder;

$kernel = new AppKernel('dev', true);
$kernel->boot();
$container = $kernel->getContainer();

/** @var \CoreBundle\Api\DpdApi $dpdApi */
$dpdApi = $container->get('mz.dpd.api');

// Test tracking (use a real parcel ID if you have one)
try {
$parcelId = 'TEST123456789012'; // Replace with real parcel ID
$tracking = $dpdApi->getTrackingByParcelId($parcelId);
print_r($tracking);
echo "βœ… API Connection successful!\n";
} catch (\Exception $e) {
echo "❌ API Error: " . $e->getMessage() . "\n";
}

Run:

php scripts/test_dpd_api.php

Test 3: Test Shipment Creation (Manual Test)​

// Get service
$dpdService = $container->get('CoreBundle\Services\DpdService');

// Create shipment for a sale product
$saleProductIds = [123]; // Replace with actual SaleProduct ID
$userId = 1; // Your user ID

$result = $dpdService->createSaleProductShipment(
$saleProductIds,
$userId,
false,
false // Don't send notifications during testing
);

if ($result) {
echo "βœ… Shipment created successfully!\n";
} else {
echo "❌ Shipment creation failed\n";
}

πŸ“Š Data Flow​

User Action (Phase 2)
↓
DpdService::createSaleProductShipment()
↓
DpdApi::createShipment() β†’ DPD REST API
↓
Response with parcelID + PDF label (base64)
↓
Save PDF to /web/pdf_dpd/
↓
Update SaleProduct:
- carrier = 'DPD'
- tracking_id = parcelID
- shipment_infos = JSON response
- expedition_ticket_files = ['/pdf_dpd/xxx.pdf']
- track_links = ['https://www.brt.it/tracking?parcelID=xxx']
↓
ShipmentTrackingSynchronizer::sync()
↓
Dispatch Events:
- SaleProductsShippedEvent
- SaleProductsAfterTicketPrintedEvent

πŸ” Logging​

All DPD operations are logged to the logidav_dpd channel.

Check logs:

tail -f var/logs/dev.log | grep DPD

πŸ“ API Response Examples​

Create Shipment Response​

{
"createResponse": {
"executionMessage": {
"code": 0,
"severity": "INFO",
"message": "Success"
},
"parcelNumberFrom": "1234567",
"parcelNumberTo": "1234567",
"arrivalDepot": "123",
"deliveryZone": "01",
"labels": {
"label": [{
"parcelID": "ABC123DEF456789012",
"stream": "JVBERi0xLjQKJeLj...", // base64 PDF
"trackingByParcelID": "ABC123DEF456"
}]
}
}
}

Tracking Response​

{
"ttParcelIdResponse": {
"executionMessage": {
"code": 0,
"severity": "INFO"
},
"esito": 0,
"bolla": {
"dati_spedizione": {
"spedizione_id": "1234567890"
},
"dati_consegna": {
"data_consegna_merce": "2025-10-24",
"firmatario_consegna": "John Doe"
}
},
"lista_eventi": [{
"data": "2025-10-23",
"ora": "14:30",
"descrizione": "Pacco ricevuto"
}]
}
}

🚨 Error Codes​

Common DPD API error codes:

  • -1: Generic error
  • -3: Database connection problems
  • -5: Invalid parameter
  • -10: Shipment number required
  • -11: Shipment not found
  • -21: Customer code required
  • -22: Non-unique reference
  • -30: Parcel ID required

βœ… Phase 1 Checklist​

  • Create DpdApi.php with REST client
  • Create DpdService.php with business logic
  • Register services in services.yml
  • Add parameters to parameters.yml.dist
  • Use generic SaleProduct fields (no new DB columns)
  • Implement PDF label saving
  • Add comprehensive error handling
  • Add logging support
  • Follow Geodis pattern for consistency

πŸ“‹ Next Steps (Phase 2)​

  1. Create DpdController.php for /dpd/ dashboard
  2. Update processingNotPrinted.html.twig to add "Send to DPD" action
  3. Create dashboard views
  4. Add JavaScript handlers
  5. Test end-to-end workflow

πŸ“š References​

  • API Documentation: BrtRestApi-EN/RestShipmentProd.en/Index.html
  • Swagger Specs:
    • BrtRestApi-EN/RestShipmentProd.en/SwaggerViewerShipment.json
    • BrtRestApi-EN/RestShipmentProd.en/SwaggerViewerTracking.json
  • Support: cedvas@brt.it

🎯 Success Criteria​

Phase 1 is complete when:

  • βœ… Services are registered and accessible
  • βœ… DPD API can be called successfully
  • βœ… Shipments can be created programmatically
  • βœ… PDF labels are saved correctly
  • βœ… SaleProduct entities are updated with shipment data
  • βœ… Tracking synchronization works
  • βœ… Events are dispatched correctly