Provider Management Guide

Overview

This guide covers how to add new shipping providers to the ProviderTrack system through the admin interface and management commands, without requiring Docker rebuilds.

Admin Interface: https://track.oklabs.my.id/admin/providers/provider/ Live System: Production deployment on VM

Table of Contents

  1. Adding Providers via Admin UI
  2. Adding Providers via Management Commands
  3. Provider Configuration Examples
  4. API Configuration Guide
  5. Status Mapping Guide
  6. Testing New Providers
  7. Troubleshooting

Adding Providers via Admin UI

Step 1: Access Admin Interface

  1. Navigate to Admin:

    https://track.oklabs.my.id/admin/providers/provider/
    
  2. Login Credentials:

    • Use your Django admin credentials
    • If you don't have access, contact the system administrator
  3. Create New Provider:

    • Click "Add Provider" button
    • Fill in the required fields

Step 2: Basic Provider Information

Required Fields:

Name: JNE Express
Slug: jne
Base API URL: https://apiv2.jne.co.id/tracing/api/list/v1/cnote

Optional Fields:

Schedule Type: interval
Interval Minutes: 60
Schedule Enabled: ✓ (checked)

Step 3: API Configuration

For JNE Express Example:

{
  "auth_method": "none",
  "method": "POST",
  "tracking_path": "",
  "param_name": "cnote",
  "headers": {
    "Content-Type": "application/x-www-form-urlencoded"
  },
  "body_encoding": "FORM",
  "body": {
    "cnote": "{tracking_number}"
  },
  "response_status_path": ["cnote", "pod_status"],
  "timeout": 30
}

Step 4: Status Mapping

JNE Status Mapping Example:

{
  "DELIVERED": "delivered",
  "ON DELIVERY": "out_for_delivery", 
  "ON TRANSIT": "in_transit",
  "PICKUP": "in_transit",
  "SHIPMENT": "label_created",
  "RETURN": "returned",
  "HOLD": "exception",
  "CANCEL": "cancelled"
}

Step 5: Save and Test

  1. Save Provider: Click "Save" button
  2. Test Connection: Use the "Test Connection" feature in admin
  3. Verify: Check that the provider appears in the providers list

Adding Providers via Management Commands

Method 1: SSH into VM and Create Provider

Step 1: Connect to VM

ssh root@core-stack

Step 2: Access Django Shell

docker exec -it track python manage.py shell

Step 3: Create Provider Programmatically

from providers.models import Provider

# Create JNE Provider
jne_provider = Provider.objects.create(
    name='JNE Express',
    slug='jne',
    base_api_url='https://apiv2.jne.co.id/tracing/api/list/v1/cnote',
    api_config={
        'auth_method': 'none',
        'method': 'POST',
        'tracking_path': '',
        'param_name': 'cnote',
        'headers': {
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        'body_encoding': 'FORM',
        'body': {
            'cnote': '{tracking_number}'
        },
        'response_status_path': ['cnote', 'pod_status'],
        'timeout': 30
    },
    status_mapping={
        'DELIVERED': 'delivered',
        'ON DELIVERY': 'out_for_delivery',
        'ON TRANSIT': 'in_transit',
        'PICKUP': 'in_transit',
        'SHIPMENT': 'label_created',
        'RETURN': 'returned',
        'HOLD': 'exception',
        'CANCEL': 'cancelled'
    },
    schedule_type='interval',
    interval_minutes=60,
    schedule_enabled=True
)

print(f"Created provider: {jne_provider.name} (ID: {jne_provider.id})")

Method 2: Create Management Command

Step 1: Copy Management Command to VM

# Create file locally first
cat > add_jne_provider.py << 'EOF'
from django.core.management.base import BaseCommand
from providers.models import Provider

class Command(BaseCommand):
    help = 'Add JNE Express provider'

    def handle(self, *args, **options):
        provider, created = Provider.objects.get_or_create(
            slug='jne',
            defaults={
                'name': 'JNE Express',
                'base_api_url': 'https://apiv2.jne.co.id/tracing/api/list/v1/cnote',
                'api_config': {
                    'auth_method': 'none',
                    'method': 'POST',
                    'tracking_path': '',
                    'param_name': 'cnote',
                    'headers': {
                        'Content-Type': 'application/x-www-form-urlencoded'
                    },
                    'body_encoding': 'FORM',
                    'body': {
                        'cnote': '{tracking_number}'
                    },
                    'response_status_path': ['cnote', 'pod_status'],
                    'timeout': 30
                },
                'status_mapping': {
                    'DELIVERED': 'delivered',
                    'ON DELIVERY': 'out_for_delivery',
                    'ON TRANSIT': 'in_transit',
                    'PICKUP': 'in_transit',
                    'SHIPMENT': 'label_created',
                    'RETURN': 'returned',
                    'HOLD': 'exception',
                    'CANCEL': 'cancelled'
                },
                'schedule_type': 'interval',
                'interval_minutes': 60,
                'schedule_enabled': True
            }
        )

        if created:
            self.stdout.write(f'Successfully created JNE provider (ID: {provider.id})')
        else:
            self.stdout.write(f'JNE provider already exists (ID: {provider.id})')
EOF

# Copy to VM
scp add_jne_provider.py root@core-stack:/tmp/

# Execute on VM
ssh root@core-stack "docker cp /tmp/add_jne_provider.py track:/app/providers/management/commands/ && docker exec track python manage.py add_jne_provider"

Provider Configuration Examples

1. JNE Express (Indonesian Domestic)

Basic Info:

API Config:

{
  "auth_method": "none",
  "method": "POST",
  "tracking_path": "",
  "param_name": "cnote",
  "headers": {
    "Content-Type": "application/x-www-form-urlencoded",
    "User-Agent": "ProviderTrack/1.0"
  },
  "body_encoding": "FORM",
  "body": {
    "cnote": "{tracking_number}"
  },
  "response_status_path": ["cnote", "pod_status"],
  "timeout": 30
}

Status Mapping:

{
  "DELIVERED": "delivered",
  "ON DELIVERY": "out_for_delivery",
  "ON TRANSIT": "in_transit",
  "PICKUP": "in_transit",
  "SHIPMENT": "label_created",
  "RETURN": "returned",
  "HOLD": "exception",
  "CANCEL": "cancelled",
  "UNKNOWN": "unknown"
}

2. POS Indonesia (Government Postal)

Basic Info:

API Config:

{
  "auth_method": "api_key",
  "api_key": "YOUR_POS_API_KEY",
  "api_key_header": "X-API-Key",
  "method": "GET",
  "tracking_path": "/tracking",
  "param_name": "barcode",
  "headers": {
    "Accept": "application/json"
  },
  "response_status_path": ["data", "status"],
  "timeout": 45
}

Status Mapping:

{
  "10": "label_created",
  "20": "in_transit", 
  "30": "in_transit",
  "40": "out_for_delivery",
  "50": "delivered",
  "60": "exception",
  "70": "returned"
}

3. SiCepat (Indonesian Express)

Basic Info:

API Config:

{
  "auth_method": "api_key",
  "api_key": "YOUR_SICEPAT_API_KEY",
  "api_key_header": "api-key",
  "method": "GET",
  "tracking_path": "",
  "param_name": "waybill",
  "headers": {
    "Accept": "application/json"
  },
  "response_status_path": ["sicepat", "result", "last_status", "status"],
  "timeout": 30
}

4. UPS (International)

Basic Info:

API Config:

{
  "auth_method": "oauth",
  "client_id": "YOUR_UPS_CLIENT_ID",
  "client_secret": "YOUR_UPS_CLIENT_SECRET",
  "oauth_token_url": "https://onlinetools.ups.com/security/v1/oauth/token",
  "oauth_scope": "tracking",
  "method": "GET",
  "tracking_path": "/{tracking_number}",
  "headers": {
    "Accept": "application/json"
  },
  "response_status_path": ["trackResponse", "shipment", 0, "package", 0, "currentStatus", "type"],
  "timeout": 45
}

5. TNT (FedEx Network)

Basic Info:

API Config:

{
  "auth_method": "api_key",
  "api_key": "YOUR_TNT_API_KEY",
  "api_key_header": "TNT-API-KEY",
  "method": "GET",
  "tracking_path": "",
  "param_name": "con",
  "headers": {
    "Accept": "application/json"
  },
  "response_status_path": ["tracker", "consignmentLevelDetails", "statusData", "status"],
  "timeout": 30
}

API Configuration Guide

Authentication Methods

1. No Authentication (none)

{
  "auth_method": "none"
}

2. API Key Authentication (api_key)

{
  "auth_method": "api_key",
  "api_key": "your_api_key_here",
  "api_key_header": "X-API-Key"
}

3. Bearer Token (bearer)

{
  "auth_method": "bearer",
  "bearer_token": "your_bearer_token_here"
}

4. Basic Authentication (basic)

{
  "auth_method": "basic",
  "username": "your_username",
  "password": "your_password"
}

5. OAuth 2.0 (oauth)

{
  "auth_method": "oauth",
  "client_id": "your_client_id",
  "client_secret": "your_client_secret",
  "oauth_token_url": "https://api.provider.com/oauth/token",
  "oauth_scope": "tracking"
}

HTTP Methods and Body Encoding

GET Request (Query Parameters)

{
  "method": "GET",
  "param_name": "tracking_number",
  "tracking_path": "/track/{tracking_number}"
}

POST Request (JSON Body)

{
  "method": "POST",
  "body_encoding": "JSON",
  "body": {
    "trackingNumber": "{tracking_number}",
    "includeDetails": true
  }
}

POST Request (Form Data)

{
  "method": "POST",
  "body_encoding": "FORM",
  "body": {
    "awb": "{tracking_number}",
    "format": "json"
  }
}

Response Path Configuration

Simple Path (Single Level)

{
  "response_status_path": ["status"]
}

Nested Path (Multiple Levels)

{
  "response_status_path": ["data", "shipment", "status", "code"]
}

Array Access

{
  "response_status_path": ["shipments", 0, "currentStatus"]
}

Status Mapping Guide

Internal Status Codes

The system uses these standardized internal status codes:

Internal Code Description
pending Initial/unknown status
label_created Shipping label created
in_transit Package in transit
out_for_delivery Out for delivery
delivered Successfully delivered
exception Exception/problem occurred
returned Package returned to sender
cancelled Shipment cancelled
unknown Status unknown/unmapped

Provider-Specific Mapping Examples

DHL Status Mapping

{
  "delivered": "delivered",
  "transit": "in_transit", 
  "failure": "exception",
  "unknown": "unknown",
  "pre-transit": "label_created",
  "pickup": "in_transit",
  "exception": "exception",
  "on-hold": "exception",
  "out-for-delivery": "out_for_delivery"
}

FedEx Status Mapping

{
  "DL": "delivered",
  "IT": "in_transit",
  "OD": "out_for_delivery",
  "PU": "in_transit",
  "SH": "label_created",
  "DE": "exception",
  "CA": "cancelled",
  "RS": "returned"
}

JNE Status Mapping

{
  "DELIVERED": "delivered",
  "ON DELIVERY": "out_for_delivery",
  "ON TRANSIT": "in_transit",
  "PICKUP": "in_transit",
  "SHIPMENT": "label_created",
  "RETURN": "returned",
  "HOLD": "exception",
  "CANCEL": "cancelled"
}

Testing New Providers

1. Admin Interface Testing

  1. Navigate to Provider in Admin:

    https://track.oklabs.my.id/admin/providers/provider/[provider_id]/change/
    
  2. Use Test Connection Feature:

    • Enter a real tracking number in the test field
    • Click "Test Connection" button
    • Review the response and status mapping
  3. Example Test Cases:

    JNE: 8820326200001
    POS Indonesia: EA123456789ID
    SiCepat: 000123456789
    

2. Django Shell Testing

# SSH into VM and run
ssh root@core-stack "docker exec -it track python manage.py shell"

# Test provider tracking
from providers.models import Provider
from awbs.models import AWB
from django.contrib.auth.models import User

# Get provider
provider = Provider.objects.get(slug='jne')

# Create test AWB
user = User.objects.first()  # Get any user
awb = AWB.objects.create(
    user=user,
    provider=provider,
    awb_number='8820326200001',
    current_status_internal='pending'
)

# Test tracking (if tracking service is implemented)
from providers.services import ProviderService
service = ProviderService(provider)
result = service.track_awb('8820326200001')
print(f"Tracking result: {result}")

3. API Testing with Real AWBs

Create a test script to verify provider integration:

#!/usr/bin/env python3
"""
Test new provider integration
"""

import requests
import json

def test_jne_provider():
    """Test JNE provider directly"""
    api_url = "https://apiv2.jne.co.id/tracing/api/list/v1/cnote"

    data = {
        'cnote': '8820326200001'  # Test tracking number
    }

    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'ProviderTrack/1.0'
    }

    try:
        response = requests.post(api_url, data=data, headers=headers, timeout=30)
        print(f"Status: {response.status_code}")
        print(f"Response: {response.text}")

        if response.status_code == 200:
            json_data = response.json()
            status = json_data.get('cnote', {}).get('pod_status')
            print(f"Extracted status: {status}")

    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    test_jne_provider()

Troubleshooting

Common Issues and Solutions

1. Authentication Errors

Problem: 401 Unauthorized or 403 Forbidden

Solution:
- Verify API key/credentials are correct
- Check if API key header name is correct
- Ensure OAuth token is not expired
- Verify rate limits are not exceeded

2. Response Parsing Errors

Problem: Cannot extract status from response

Solution:
- Use admin "Test Connection" to see raw response
- Verify response_status_path matches actual JSON structure
- Check if response is array vs object
- Add debug logging to track response format

3. SSL/Certificate Errors

Problem: SSL verification failed

Solution:
- Ensure base_api_url uses HTTPS
- Verify SSL certificate is valid
- Check if provider uses custom certificates

4. Timeout Issues

Problem: Requests timing out

Solution:
- Increase timeout value in api_config
- Check provider's rate limiting
- Verify network connectivity from VM

5. Status Mapping Issues

Problem: Statuses not mapping correctly

Solution:
- Review provider's actual status codes
- Test with multiple tracking numbers
- Add fallback mapping for unknown statuses
- Use "unknown" as default for unmapped statuses

Debug Commands

Check Provider Configuration

# SSH to VM
ssh root@core-stack

# Check provider details
docker exec track python manage.py shell -c "
from providers.models import Provider
p = Provider.objects.get(slug='jne')
print('Name:', p.name)
print('URL:', p.base_api_url)
print('Config:', p.api_config)
print('Mapping:', p.status_mapping)
"

Test Provider API Directly

# Test JNE API
curl -X POST "https://apiv2.jne.co.id/tracing/api/list/v1/cnote" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "User-Agent: ProviderTrack/1.0" \
  -d "cnote=8820326200001"

Check Provider Logs

# Check Django logs for provider errors
ssh root@core-stack "docker logs track | grep -i 'provider\|tracking\|error'"

Quick Reference

Adding Provider Checklist

  • [ ] Determine provider's API documentation
  • [ ] Identify authentication method
  • [ ] Find tracking endpoint URL
  • [ ] Test API manually with curl/Postman
  • [ ] Map response structure to status path
  • [ ] Create status code mapping
  • [ ] Add provider via admin or management command
  • [ ] Test with real tracking numbers
  • [ ] Verify status updates work correctly
  • [ ] Enable scheduling if needed

Provider URLs for Testing

Provider Test Tracking Numbers Status Check URL
JNE 8820326200001 Manual API call
POS Indonesia EA123456789ID https://mypos.pos.co.id
SiCepat 000123456789 https://sicepat.com
DHL 5451596323 Built-in system
FedEx 883134258320 Built-in system

Important Notes

  1. No Docker Rebuild Required: All provider additions can be done through admin interface or management commands
  2. Live System Testing: Always test on the live system after adding providers
  3. API Rate Limits: Be mindful of provider API rate limits when scheduling
  4. Security: Never commit API keys to version control
  5. Monitoring: Monitor provider performance and adjust timeouts as needed

For additional support or specific provider integrations, contact the development team or check the provider's official API documentation.

results matching ""

    No results matching ""