Shipping Service Package for Laravel with Strategy and Adapter patterns

Maintainers

Package info

github.com/linh20000/shipping-workflow

pkg:composer/shippable/hub

Statistics

Installs: 29

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.11 2026-06-23 01:41 UTC

This package is auto-updated.

Last update: 2026-06-23 03:53:30 UTC


README

Laravel Package cung cấp dịch vụ vận chuyển qua Strategy + Adapter Pattern, hỗ trợ GHN, GHTK và ViettelPost. Đặc biệt tối ưu cho hệ thống Multi-tenant nhờ cơ chế lưu trữ token và cấu hình linh hoạt trong Database.

Cài đặt

1. Thêm local path (development)

// composer.json của dự án
{
    "repositories": [
        {
            "type": "path",
            "url": "../package-php/shipping",
            "options": { "symlink": true }
        }
    ],
    "require": {
        "wf/shipping": "*"
    }
}
composer require wf/shipping --ignore-platform-reqs

2. Database & Migrations (Multi-Tenant Hỗ trợ)

Package sử dụng table shipping_providers để lưu trữ token của các đối tác (Thay vì đặt trong .env để hỗ trợ Multi-tenant).

Cách 1: Nếu dự án dùng chung 1 database (Single-tenant) Bạn cần publish migration ra ngoài và chạy lệnh migrate:

php artisan vendor:publish --tag=shipping-migrations
php artisan migrate

Lưu ý: Ngay sau khi migrate, hệ thống sẽ tự động chèn sẵn (seed) 3 bản ghi cho GHN, GHTK, ViettelPost vào database.

Cách 2: Nếu dự án dùng stancl/tenancy (Multi-tenant) Bạn có thể không cần publish, chỉ việc khai báo đường dẫn migration của package vào file config tenancy.php của bạn:

'migration_parameters' => [
    '--force' => true,
    '--path' => [
        database_path('migrations/tenant'),
        base_path('vendor/wf/shipping/src/database/migrations') // Trỏ thẳng vào thư mục migrations
    ],
    '--realpath' => true,
],

3. Publish config (tuỳ chọn)

php artisan vendor:publish --tag=shipping-config

Package sẽ tự động load config mặc định (endpoints, urls...) nếu bạn chưa publish. Chỉ publish khi muốn tuỳ chỉnh URL của đối tác.

4. Thiết lập .env (Chỉ dành cho URL)

Các biến liên quan đến Token giờ đây được quản lý trực tiếp qua database của từng Tenant. Trong .env, bạn chỉ cần khai báo (nếu có thay đổi) các Endpoint URL gốc:

GHN_BASE_URL=https://dev-online-gateway.ghn.vn/shiip/public-api
GHTK_ENDPOINT=https://services-staging.ghtklab.com
VIETTELPOST_ENDPOINT=https://partner.viettelpost.vn

Quản lý cấu hình đối tác (DB)

Mỗi tenant (hoặc hệ thống gốc) sẽ quản lý các cấu hình trong bảng shipping_providers. Các trường cấu hình bao gồm: provider_code, provider_name, api_token, is_enabled, additional_config (json lưu các thông số riêng như shop_id của GHN).

Cách sử dụng

Package sử dụng Factory Pattern nạp động từ cơ sở dữ liệu để bạn có thể tuỳ ý gọi dịch vụ ở bất cứ đâu (Controller, Job, Command) mà không bị phụ thuộc vào HTTP Request.

Cách 1 — Inject qua Constructor (Recommended)

use Wf\Shipping\ShippingFactory;
use Wf\Shipping\DTO\StandardShippingPayload;

class OrderController extends Controller
{
    public function __construct(
        private readonly ShippingFactory $shippingFactory
    ) {}

    public function createOrder(Request $request)
    {
        $payload = StandardShippingPayload::fromArray($request->validated());
        
        // Chọn hãng vận chuyển: ghn (express), ghtk (standard), viettelpost (fast)
        $method = $request->input('service_method', 'express');
        
        // Factory tự động móc DB lấy API Token của tenant hiện tại
        $strategy = $this->shippingFactory->make($method);
        
        $result = $strategy->createOrder($payload);

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

Cách 2 — Resolve thủ công qua app()

use Wf\Shipping\ShippingFactory;

$factory = app(ShippingFactory::class);
$ghnStrategy = $factory->make('express'); // Map tới ghn
$ghtkStrategy = $factory->make('standard'); // Map tới ghtk

Cách 3 — Dùng trực tiếp SDK thô

use Wf\Shipping\Models\ShippingProvider;
use Wf\Shipping\GHN;
use Wf\Shipping\GHTK;
use Wf\Shipping\ViettelPost;

$ghnProvider = ShippingProvider::where('provider_code', 'ghn')->first();
$ghn  = new GHN($ghnProvider->api_token);
$resp = $ghn->getProvince(); // array

$ghtkProvider = ShippingProvider::where('provider_code', 'ghtk')->first();
$ghtk = new GHTK($ghtkProvider->api_token);
$fee  = $ghtk->calculateFee([...]); // array

Cấu trúc package

src/
├── config/
│   └── shipping.php          ← Cấu hình endpoint, method (không lưu token)
├── database/
│   └── migrations/           ← Chứa bảng shipping_providers
├── Models/
│   └── ShippingProvider.php  ← Eloquent mapping với database
├── Contracts/
│   └── ShippingStrategyInterface.php
├── DTO/
│   └── StandardShippingPayload.php
├── Adapters/
│   ├── GHNAdapter.php        
│   ├── GHTKAdapter.php       
│   └── ViettelPostAdapter.php
├── Strategies/
│   ├── GHNStrategy.php       
│   ├── GHTKStrategy.php      
│   └── ViettelPostStrategy.php
├── GHN.php                   ← SDK thô
├── GHTK.php                  ← SDK thô
├── ViettelPost.php           ← SDK thô
├── ShippingFactory.php       ← Logic Lazy-Load provider từ DB
└── Providers/
    └── ShippingServiceProvider.php

Thêm hãng vận chuyển mới

  1. Chèn record cấu hình mới vào bảng shipping_providers (VD: provider_code = newcarrier).
  2. Tạo src/Adapters/NewCarrierAdapter.php — map DTO sang format của hãng.
  3. Tạo src/Strategies/NewCarrierStrategy.php — gọi SDK.
  4. Thêm map rule vào ShippingFactory::resolveStrategy() để khởi tạo class NewCarrierStrategy.
  5. Thêm config endpoint vào src/config/shipping.php.

Interface cần implement

interface ShippingStrategyInterface
{
    public function getServiceMethodName(): string;
    public function createOrder(StandardShippingPayload $payload): array;
    public function calculateFee(StandardShippingPayload $payload): array;
    public function cancelOrder(string $orderCode): array;
    public function printLabel(string $orderCode): mixed;
}