定制 m4dev/laravel-usps 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

m4dev/laravel-usps

Composer 安装命令:

composer require m4dev/laravel-usps

包简介

Laravel package for USPS shipping integration with rates, labels, and tracking

README 文档

README

A comprehensive Laravel package for USPS shipping integration with support for address validation, rate calculation, label creation, and package tracking using the USPS API v3 with OAuth2 authentication.

Features

  • OAuth2 Authentication: Secure authentication using client credentials
  • Address Validation: Validate and standardize addresses using USPS API v3
  • Rate Calculation: Get shipping rates for different USPS services with caching support
  • Label Creation: Generate shipping labels in PDF format with tracking numbers
  • Package Tracking: Track packages and automatically update shipment status
  • Rate Caching: Cache rates to reduce API calls and improve performance
  • Rate Shopping: Compare rates across multiple USPS services
  • Database Integration: Store shipments and tracking information
  • Artisan Commands: Built-in commands for testing and maintenance

Requirements

  • PHP 8.1 or higher
  • Laravel 10.0 or 11.0
  • cURL extension
  • JSON extension
  • Valid USPS Developer Account

Installation

  1. Install via Composer:
composer require m4dev/laravel-usps
  1. Publish the configuration file:
php artisan vendor:publish --tag=usps-config
  1. Run the migrations:
php artisan migrate
  1. Configure your environment variables in .env:
# USPS API Credentials (from USPS Developer Portal)
USPS_CLIENT_ID=your_client_id_from_usps_developer_portal
USPS_CLIENT_SECRET=your_client_secret_from_usps_developer_portal
USPS_SANDBOX=true

# Optional configurations
USPS_DEFAULT_SERVICE=USPS_GROUND_ADVANTAGE
USPS_LABEL_FORMAT=PDF
USPS_CACHE_ENABLED=true
USPS_RATE_SHOPPING=false

# Default sender information
USPS_SENDER_NAME="Your Company"
USPS_SENDER_COMPANY="Your Company Inc"
USPS_SENDER_STREET="123 Main St"
USPS_SENDER_CITY="Anytown"
USPS_SENDER_STATE="CA"
USPS_SENDER_ZIP="12345"
USPS_SENDER_PHONE="555-123-4567"
USPS_SENDER_EMAIL="shipping@yourcompany.com"

Getting USPS API Credentials

  1. Go to the USPS Developer Portal
  2. Create an account or log in
  3. Register your application
  4. You'll receive a client_id and client_secret
  5. Use these credentials in your .env file

Note: The modern USPS API v3 uses OAuth2 authentication with client credentials, not API keys.

Quick Start

Basic Usage Example

use UspsShipping\Laravel\Services\UspsShippingService;

$shippingService = app(UspsShippingService::class);

$shipment = $shippingService->createShipment([
    'from_address' => [
        'street' => '123 Sender St',
        'city' => 'Los Angeles',
        'state' => 'CA',
        'zip' => '90210'
    ],
    'to_address' => [
        'street' => '456 Recipient Ave',
        'city' => 'New York',
        'state' => 'NY',
        'zip' => '10001'
    ],
    'weight' => 2.5,
    'dimensions' => [
        'length' => 12,
        'width' => 9,
        'height' => 3
    ],
    'service_type' => 'PRIORITY_MAIL',
    'customer_name' => 'John Doe',
    'customer_email' => 'john@example.com'
]);

echo "Tracking Number: " . $shipment->tracking_number;
echo "Label URL: " . $shipment->label_url;

Detailed Usage

Address Validation

use UspsShipping\Laravel\Services\AddressValidationService;

$addressService = app(AddressValidationService::class);

$result = $addressService->validate([
    'street' => '123 Main Street',
    'city' => 'Beverly Hills',
    'state' => 'CA',
    'zip' => '90210'
]);

if ($result['valid']) {
    $standardizedAddress = $result['standardized'];
    $corrections = $result['corrections'];

    foreach ($corrections as $field => $correction) {
        echo "Corrected {$field}: {$correction['original']}{$correction['corrected']}\n";
    }
}

Getting Shipping Rates

use UspsShipping\Laravel\Services\RateService;

$rateService = app(RateService::class);

// Get rates for a single service
$rates = $rateService->getRates([
    'origin_zip' => '90210',
    'destination_zip' => '10001',
    'weight' => 2.5,
    'length' => 12,
    'width' => 9,
    'height' => 3,
    'mail_class' => 'PRIORITY_MAIL'
]);

echo "Shipping cost: $" . $rates['totalBasePrice'];

// Enable rate shopping in config to compare multiple services
config(['usps.rate_shopping.enabled' => true]);
$allRates = $rateService->getRates([
    'origin_zip' => '90210',
    'destination_zip' => '10001',
    'weight' => 2.5
]);

foreach ($allRates['rates'] as $rate) {
    echo "{$rate['service_name']}: $" . $rate['totalBasePrice'] . "\n";
}

Creating Shipping Labels

use UspsShipping\Laravel\Services\LabelService;

$labelService = app(LabelService::class);

$shipment = $labelService->createAndSaveLabel([
    'to_address' => [
        'street' => '123 Customer St',
        'city' => 'New York',
        'state' => 'NY',
        'zip' => '10001'
    ],
    'weight' => 2.5,
    'dimensions' => [
        'length' => 12,
        'width' => 9,
        'height' => 3
    ],
    'service_type' => 'PRIORITY_MAIL',
    'customer_name' => 'John Doe',
    'customer_email' => 'john@example.com',
    'label_format' => 'PDF'
]);

// Access the label
echo "Tracking Number: " . $shipment->tracking_number;
echo "Label URL: " . $shipment->label_url;

// Download label as base64 for storage
if ($shipment->label_base64) {
    file_put_contents("label_{$shipment->tracking_number}.pdf",
        base64_decode($shipment->label_base64));
}

Package Tracking

use UspsShipping\Laravel\Services\TrackingService;

$trackingService = app(TrackingService::class);

$trackingInfo = $trackingService->track('9400111899562516386781');

echo "Status: " . $trackingInfo['status'] . "\n";
echo "Current Location: " . ($trackingInfo['current_location']['city'] ?? 'Unknown') . "\n";

foreach ($trackingInfo['events'] as $event) {
    echo $event['datetime'] . ": " . $event['description'] . " - " .
         ($event['location']['city'] ?? 'Unknown location') . "\n";
}

// Update a specific shipment's tracking
$updated = $trackingService->updateShipmentTracking('9400111899562516386781');
if ($updated) {
    echo "Shipment tracking updated successfully";
}

Using the Facade

use Usps;

// Validate address
$address = Usps::validateAddress([
    'street' => '123 Main St',
    'city' => 'Beverly Hills',
    'state' => 'CA',
    'zip' => '90210'
]);

// Get rates
$rates = Usps::getRates([
    'origin_zip' => '90210',
    'destination_zip' => '10001',
    'weight' => 2.5
]);

// Track package
$tracking = Usps::trackPackage('9400111899562516386781');

// Get ZIP code info
$zipInfo = Usps::getZipInfo('90210');

Artisan Commands

Test USPS Connection

php artisan usps:test-connection

Update Tracking Information

# Update all non-delivered shipments
php artisan usps:update-tracking --all

# Update specific tracking numbers
php artisan usps:update-tracking --tracking=9400111899562516386781 --tracking=9400111899562516386782

# Update shipments from last 7 days
php artisan usps:update-tracking --days=7

Clean Up Expired Cache

php artisan usps:cleanup-cache

Configuration Options

Service Types

Configure available USPS services in config/usps.php:

'services' => [
    'USPS_GROUND_ADVANTAGE' => [
        'name' => 'USPS Ground Advantage',
        'delivery_days' => '2-5',
        'max_weight' => 70,
    ],
    'PRIORITY_MAIL' => [
        'name' => 'Priority Mail',
        'delivery_days' => '1-3',
        'max_weight' => 70,
    ],
    // ... more services
],

Rate Shopping

Enable automatic rate comparison:

'rate_shopping' => [
    'enabled' => true,
    'services' => ['USPS_GROUND_ADVANTAGE', 'PRIORITY_MAIL', 'PRIORITY_MAIL_EXPRESS'],
    'sort_by' => 'price', // 'price' or 'delivery_time'
],

Caching

Configure rate caching:

'cache' => [
    'enabled' => true,
    'duration' => 3600, // 1 hour
    'prefix' => 'usps_',
],

Working with Models

UspsShipment Model

use UspsShipping\Laravel\Models\UspsShipment;

// Get all shipments
$shipments = UspsShipment::all();

// Get shipments by status
$inTransit = UspsShipment::where('status', 'in_transit')->get();

// Get delivered shipments
$delivered = UspsShipment::where('status', 'delivered')->get();

// Check shipment status
$shipment = UspsShipment::where('tracking_number', '9400111899562516386781')->first();
if ($shipment->isDelivered()) {
    echo "Package delivered on: " . $shipment->delivered_at;
}

// Get formatted weight and service name
echo "Weight: " . $shipment->formatted_weight;
echo "Service: " . $shipment->service_name;

Advanced Usage

Batch Operations

use UspsShipping\Laravel\Services\UspsShippingService;

$shippingService = app(UspsShippingService::class);

$shipments = [
    [
        'to_address' => ['street' => '123 First St', 'city' => 'New York', 'state' => 'NY', 'zip' => '10001'],
        'weight' => 1.5,
        'service_type' => 'PRIORITY_MAIL'
    ],
    [
        'to_address' => ['street' => '456 Second Ave', 'city' => 'Chicago', 'state' => 'IL', 'zip' => '60601'],
        'weight' => 2.0,
        'service_type' => 'USPS_GROUND_ADVANTAGE'
    ]
];

$results = $shippingService->createBatchShipments($shipments);

foreach ($results as $index => $result) {
    if ($result['success']) {
        echo "Shipment {$index}: " . $result['shipment']->tracking_number . "\n";
    } else {
        echo "Shipment {$index} failed: " . $result['error'] . "\n";
    }
}

Custom Exception Handling

use UspsShipping\Laravel\Exceptions\{
    UspsException,
    UspsApiException,
    UspsValidationException,
    UspsAuthenticationException,
    UspsRateLimitException
};

try {
    $rates = $rateService->getRates($params);
} catch (UspsAuthenticationException $e) {
    // Handle authentication errors (invalid client credentials)
    Log::error('USPS Authentication Error: ' . $e->getMessage());
} catch (UspsValidationException $e) {
    // Handle address validation errors
    return response()->json(['error' => 'Invalid address: ' . $e->getMessage()], 400);
} catch (UspsRateLimitException $e) {
    // Handle rate limiting
    return response()->json(['error' => 'Rate limit exceeded'], 429);
} catch (UspsApiException $e) {
    // Handle other API errors
    Log::error('USPS API Error: ' . $e->getMessage(), $e->getContext());
} catch (UspsException $e) {
    // Handle general USPS errors
    Log::error('USPS Error: ' . $e->getMessage());
}

Controller Example

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use UspsShipping\Laravel\Services\{RateService, LabelService, TrackingService, AddressValidationService};
use UspsShipping\Laravel\Models\UspsShipment;

class ShippingController extends Controller
{
    public function calculateRates(Request $request, RateService $rateService)
    {
        $request->validate([
            'origin_zip' => 'required|string|size:5',
            'destination_zip' => 'required|string|size:5',
            'weight' => 'required|numeric|min:0.1|max:70',
            'length' => 'nullable|numeric',
            'width' => 'nullable|numeric',
            'height' => 'nullable|numeric',
        ]);

        try {
            $rates = $rateService->getRates($request->all());

            return response()->json([
                'success' => true,
                'rates' => $rates
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage()
            ], 400);
        }
    }

    public function createShipment(Request $request, LabelService $labelService)
    {
        $request->validate([
            'to_address.street' => 'required|string',
            'to_address.city' => 'required|string',
            'to_address.state' => 'required|string|size:2',
            'to_address.zip' => 'required|string|size:5',
            'weight' => 'required|numeric|min:0.1|max:70',
            'service_type' => 'required|string',
        ]);

        try {
            $shipment = $labelService->createAndSaveLabel($request->all());

            return response()->json([
                'success' => true,
                'shipment' => $shipment,
                'tracking_url' => "https://tools.usps.com/go/TrackConfirmAction?tLabels={$shipment->tracking_number}"
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage()
            ], 400);
        }
    }

    public function trackShipment(string $trackingNumber, TrackingService $trackingService)
    {
        try {
            $trackingInfo = $trackingService->track($trackingNumber);

            return response()->json([
                'success' => true,
                'tracking' => $trackingInfo
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage()
            ], 400);
        }
    }

    public function validateAddress(Request $request, AddressValidationService $addressService)
    {
        $request->validate([
            'street' => 'required|string',
            'city' => 'required|string',
            'state' => 'required|string|size:2',
            'zip' => 'required|string|size:5',
        ]);

        $result = $addressService->validate($request->all());

        return response()->json([
            'success' => $result['valid'],
            'result' => $result
        ]);
    }

    public function getShipments(Request $request)
    {
        $shipments = UspsShipment::query()
            ->when($request->status, fn($q) => $q->where('status', $request->status))
            ->when($request->service_type, fn($q) => $q->where('service_type', $request->service_type))
            ->latest()
            ->paginate(20);

        return response()->json($shipments);
    }

    public function getShipment(string $trackingNumber)
    {
        $shipment = UspsShipment::where('tracking_number', $trackingNumber)->first();

        if (!$shipment) {
            return response()->json(['error' => 'Shipment not found'], 404);
        }

        return response()->json($shipment);
    }
}

Testing

Run the test suite:

vendor/bin/phpunit

Environment Setup for Testing

Create a .env.testing file:

USPS_CLIENT_ID=test_client_id
USPS_CLIENT_SECRET=test_client_secret
USPS_SANDBOX=true

Scheduled Tasks

Add to your app/Console/Kernel.php to automatically update tracking:

protected function schedule(Schedule $schedule)
{
    // Update tracking for recent shipments every hour
    $schedule->command('usps:update-tracking --days=7')
             ->hourly()
             ->withoutOverlapping();

    // Clean up expired cache daily
    $schedule->command('usps:cleanup-cache')
             ->daily();
}

Error Handling Best Practices

  1. Always validate addresses before creating labels
  2. Handle rate limits with proper delays between requests
  3. Cache rates to reduce API calls
  4. Log errors for debugging and monitoring
  5. Use try-catch blocks around all USPS API calls

API Rate Limits

The USPS API has rate limits. The package includes:

  • Automatic delays between batch operations
  • OAuth token caching to reduce auth requests
  • Rate caching to minimize API calls

Troubleshooting

Common Issues

  1. Authentication Errors: Verify your client_id and client_secret are correct
  2. Address Validation Failures: Ensure addresses are properly formatted
  3. Rate Errors: Check weight and dimension limits for selected service
  4. Label Creation Failures: Verify all required address fields are provided

Debug Mode

Enable debug logging in your .env:

LOG_LEVEL=debug

Support

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This package is open-sourced software licensed under the [MIT license] (LICENSE.md).

Changelog

v1.0.0

  • Initial release with USPS API v3 support
  • OAuth2 authentication
  • Address validation, rates, labels, and tracking
  • Rate caching and shopping features
  • Comprehensive test suite

m4dev/laravel-usps 适用场景与选型建议

m4dev/laravel-usps 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 8 次下载、GitHub Stars 达 1, 最近一次更新时间为 2025 年 08 月 28 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「laravel」 「shipping」 「tracking」 「rates」 「usps」 「labels」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 m4dev/laravel-usps 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 m4dev/laravel-usps 我们能提供哪些服务?
定制开发 / 二次开发

基于 m4dev/laravel-usps 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 8
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 28
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-08-28