Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nepal Can Php Sdk Laravel Package

pralhadstha/nepal-can-php-sdk

PHP SDK for Nepal Can Move (NCM) shipping API. Create and manage shipments, track orders, calculate delivery rates, list branches, handle COD and returns/exchanges, manage tickets/staff, and process webhooks with typed resources. PHP 8.1+ with Guzzle.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require pralhadstha/nepal-can-php-sdk
    
  2. Initialize Client (use sandbox for testing):

    use OmniCargo\NepalCan\Client;
    
    $client = new Client(config('services.nepalcan.api_token'));
    
  3. First Use Case: Fetch branch details for a specific location:

    $branch = $client->branches->list()->first(fn($b) => $b->name === 'TINKUNE');
    

Key Entry Points

  • Shipments: shipments->create(), shipments->find()
  • Tracking: tracking->track(), tracking->getStatusHistory()
  • Rates: rates->calculate()
  • Webhooks: webhooks->parse() (for Laravel, use the dedicated package)

Implementation Patterns

Core Workflows

1. Order Creation & Management

// Create order with COD
$order = $client->shipments->create([
    'name' => 'Customer Name',
    'phone' => '98XXXXXXXX',
    'cod_charge' => '1500',
    'address' => 'Customer Address',
    'fbranch' => 'TINKUNE', // From branch
    'branch' => 'KATHMANDU', // To branch
    'package' => 'Product Description',
    'vref_id' => 'INV-123', // Your internal order ID
    'delivery_type' => RateService::TYPE_PICKUP_COLLECT, // Door2Door
]);

// Store order ID in your DB with $order->orderId

2. Real-Time Tracking Integration

// Poll for status updates (cron job)
$statuses = $client->tracking->getStatusHistory($orderId);
$lastStatus = end($statuses)->status;

// Update your DB
Order::where('ncm_order_id', $orderId)->update(['status' => $lastStatus]);

3. Webhook-Driven Updates (Laravel)

// routes/web.php
Route::post('/nepalcan-webhook', function (Request $request) {
    $webhook = $client->webhooks->parse($request->getContent());
    $dispatcher->dispatch($webhook);
});

4. Rate Calculation Before Checkout

// Calculate rate during cart checkout
$rate = $client->rates->calculate(
    'TINKUNE', // From branch
    'KATHMANDU', // To branch
    RateService::TYPE_PICKUP_COLLECT,
    weight: 1.5
);

$deliveryFee = $rate->charge;

Laravel-Specific Patterns

  1. Service Provider Binding:

    // app/Providers/NepalCanServiceProvider.php
    public function register()
    {
        $this->app->singleton(Client::class, function ($app) {
            return new Client(config('services.nepalcan.api_token'));
        });
    }
    
  2. Event-Driven Webhooks:

    // app/Providers/EventServiceProvider.php
    protected $listen = [
        WebhookEvent::DELIVERY_COMPLETED => [
            \App\Listeners\UpdateOrderStatus::class,
        ],
    ];
    
  3. Command for Bulk Status Checks:

    // app/Console/Commands/CheckNepalCanOrders.php
    public function handle()
    {
        $pendingOrders = Order::whereNull('last_ncm_status')->get();
        foreach ($pendingOrders as $order) {
            $status = $client->tracking->track($order->ncm_tracking_id);
            $order->update(['status' => $status->lastDeliveryStatus]);
        }
    }
    

Gotchas and Tips

Common Pitfalls

  1. API Token Management:

    • Sandbox and production tokens are separate. Never mix them.
    • Store tokens in Laravel's .env:
      NEPALCAN_SANDBOX_TOKEN=your_sandbox_token
      NEPALCAN_PRODUCTION_TOKEN=your_prod_token
      
  2. Idempotency in Webhooks:

    • Always implement idempotency keys to avoid duplicate processing:
      $key = $webhook->orderId . ':' . $webhook->event;
      if (ProcessedWebhook::where('key', $key)->exists()) return;
      
  3. Rate Calculation Edge Cases:

    • Weights must be in kilograms (NCM API expects numeric strings like "1.5").
    • Delivery types must match NCM's exact values (e.g., RateService::TYPE_PICKUP_COLLECT).
  4. Error Handling Quirks:

    • ValidationException contains a getErrors() method with field-specific validation messages.
    • NotFoundException is thrown for invalid order IDs (404).

Debugging Tips

  1. Enable Guzzle Debugging:

    $client = new Client($token, [], [
        'debug' => true,
        'handler' => HandlerStack::create([
            new \GuzzleHttp\Middleware::tap(function ($request) {
                \Log::debug('NCM Request:', $request->getBody());
            }),
        ]),
    ]);
    
  2. Webhook Validation:

    • Verify the User-Agent header matches NCM's expected value:
      if (!$client->webhooks->isValidUserAgent($request->header('User-Agent'))) {
          abort(403);
      }
      
  3. Rate Limiting:

    • NCM enforces 1,000 orders/day and 20,000 views/day. Cache responses aggressively:
      $rate = Cache::remember("ncm_rate_{$from}_{$to}", now()->addHours(1), function () use ($client, $from, $to) {
          return $client->rates->calculate($from, $to, $type);
      });
      

Extension Points

  1. Custom Webhook Handlers:

    • Extend WebhookHandlerInterface for domain-specific logic:
      class CodReceivedHandler implements WebhookHandlerInterface
      {
          public function handle(Webhook $webhook): void
          {
              if ($webhook->event === WebhookEvent::DELIVERY_COMPLETED) {
                  $this->processCodPayment($webhook->orderId);
              }
          }
      }
      
  2. Decorate the Client:

    • Add logging or retry logic:
      $client = new class($originalClient) extends Client {
          public function __call($method, $args) {
              \Log::info("Calling NCM {$method} with args: " . json_encode($args));
              return parent::__call($method, $args);
          }
      };
      
  3. Override Resources:

    • Extend immutable resources to add computed properties:
      class ExtendedOrder extends Order
      {
          public function getDeliveryETA(): ?Carbon
          {
              $status = $this->statusHistory->last();
              return $status ? Carbon::parse($status->addedTime)->addHours(24) : null;
          }
      }
      

Configuration Quirks

  • Base URL: Defaults to sandbox. Use Config::BASE_URL_PRODUCTION explicitly for live:
    $client = new Client($token, Config::BASE_URL_PRODUCTION);
    
  • Timeouts: Guzzle defaults to 5 seconds. Increase for slow connections:
    $client = new Client($token, [], ['timeout' => 10]);
    

Testing Strategies

  1. Mock the Client:
    $mockClient = Mockery::mock(Client::class);
    $mockClient->shouldReceive('shipments->create')
               ->once()
               ->andReturn(new Order(['orderId' => 12345]));
    
  2. Test Webhooks:
    $payload = file_get_contents('tests/fixtures/webhook_delivery_completed.json');
    $webhook = $client->webhooks->parse($payload);
    $this->assertEquals(WebhookEvent::DELIVERY_COMPLETED, $webhook->event);
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime