Skip to main content
Suppliers represent external vendors or manufacturers who provide products for your store. This is primarily used in dropshipping scenarios where products are shipped directly from the supplier to the customer, without you handling inventory.
The supplier feature is gated behind a feature flag. It must be enabled in your config/shopper/features.php configuration file.

Model

Shopper\Core\Models\Supplier
use Shopper\Core\Models\Supplier;

// The model implements
- Shopper\Core\Models\Contracts\Supplier

// Uses traits
- HasFactory
- HasModelContract
- HasSlug

Extending the Model

namespace App\Models;

use Shopper\Core\Models\Supplier as BaseSupplier;

class Supplier extends BaseSupplier
{
    // Add your customizations here
}
Update config/shopper/models.php:
return [
    'supplier' => \App\Models\Supplier::class,
];

Feature Flag

Enable the supplier feature in config/shopper/features.php:
use Shopper\Core\Enum\FeatureState;

return [
    // ...
    'supplier' => FeatureState::Enabled,
];
When enabled, the Suppliers page appears under Products in the admin sidebar, and the supplier select field becomes visible on External product forms.

Database Schema

ColumnTypeNullableDefaultDescription
idbigintnoautoPrimary key
namestringno-Supplier name
slugstringyesautoURL-friendly identifier (unique)
emailstringyesnullContact email
phonestringyesnullContact phone
contact_namestringyesnullPrimary contact person
websitestringyesnullSupplier website URL
descriptionlongTextyesnullDetailed description
noteslongTextyesnullInternal notes
is_enabledbooleannofalseSupplier visibility
metadatajsonbyesnullAdditional custom data
created_attimestampyesnullCreation timestamp
updated_attimestampyesnullLast update timestamp

Relationships

Products

A supplier can have many products linked to it:
// Get all products from a supplier
$supplier->products; // Collection<Product>

// Get enabled products
$supplier->products()
    ->where('is_visible', true)
    ->get();

// Count products per supplier
$supplier->products()->count();

Product → Supplier

Each product can optionally belong to one supplier:
// Get a product's supplier
$product->supplier; // Supplier (nullable)

// Check if a product has a supplier
if ($product->supplier_id) {
    // This is a dropshipped product
}

// Get all products from a specific supplier
Product::query()
    ->where('supplier_id', $supplier->id)
    ->get();

Query Scopes

use Shopper\Core\Models\Supplier;

// Get only enabled suppliers
Supplier::query()->enabled()->get();

Creating Suppliers

use Shopper\Core\Models\Supplier;

$supplier = Supplier::query()->create([
    'name' => 'TechParts Co., Ltd',
    'email' => 'orders@techparts.com',
    'phone' => '+86 755 1234 5678',
    'contact_name' => 'Zhang Wei',
    'website' => 'https://techparts.com',
    'description' => 'Electronics components and accessories manufacturer based in Shenzhen.',
    'notes' => 'Minimum order: 50 units. Lead time: 5-7 days.',
    'is_enabled' => true,
    'metadata' => [
        'payment_terms' => 'net_30',
        'currency' => 'USD',
        'minimum_order' => 50,
    ],
]);

Updating Status

// Enable a supplier
$supplier->updateStatus(enabled: true);

// Disable a supplier
$supplier->updateStatus(enabled: false);

Retrieving Suppliers

// Get all enabled suppliers
$suppliers = Supplier::query()
    ->enabled()
    ->withCount('products')
    ->get();

// Find by slug
$supplier = Supplier::query()
    ->where('slug', 'techparts-co')
    ->firstOrFail();

// Search suppliers
$results = Supplier::query()
    ->where('name', 'like', "%{$search}%")
    ->orWhere('email', 'like', "%{$search}%")
    ->enabled()
    ->get();

Linking Products to Suppliers

Products of type External can be linked to a supplier. The supplier_id column on the products table stores this relationship:
use Shopper\Core\Enum\ProductType;
use Shopper\Core\Models\Product;

// Create an external product linked to a supplier
$product = Product::query()->create([
    'name' => 'Wireless Bluetooth Earbuds',
    'slug' => 'wireless-bluetooth-earbuds',
    'type' => ProductType::External,
    'supplier_id' => $supplier->id,
    'is_visible' => true,
    // ... other product fields
]);

// Change a product's supplier
$product->update(['supplier_id' => $newSupplier->id]);

// Remove supplier link
$product->update(['supplier_id' => null]);

Dropshipping Workflow

The supplier feature is designed to work with the Fulfillment system. Here’s the complete flow:

1. Setup

// Create your supplier
$supplier = Supplier::query()->create([
    'name' => 'Shenzhen TechParts',
    'email' => 'orders@techparts.com',
    'is_enabled' => true,
]);

// Link products to supplier
$product->update(['supplier_id' => $supplier->id]);

2. Customer Places Order

When a customer orders a product linked to a supplier, the order is created normally. The item’s fulfillment_status starts as Pending.

3. Forward to Supplier

After receiving the customer’s payment, you place the order with your supplier using the customer’s shipping address:
use Shopper\Core\Enum\FulfillmentStatus;

// Mark items as forwarded
$order->items()
    ->whereHas('product', fn ($q) => $q->where('supplier_id', $supplier->id))
    ->update(['fulfillment_status' => FulfillmentStatus::ForwardedToSupplier]);

4. Supplier Ships

When the supplier provides tracking information:
$shipment = $order->shippings()->create([
    'carrier_id' => $carrierId,
    'tracking_number' => $supplierTracking,
    'tracking_url' => $supplierTrackingUrl,
    'shipped_at' => now(),
]);

$order->items()
    ->where('fulfillment_status', FulfillmentStatus::ForwardedToSupplier)
    ->update([
        'order_shipping_id' => $shipment->id,
        'fulfillment_status' => FulfillmentStatus::Shipped,
    ]);

5. Delivery Confirmation

$shipment->update(['received_at' => now()]);

$shipment->items()->update([
    'fulfillment_status' => FulfillmentStatus::Delivered,
]);

Querying by Supplier

// Get all pending orders for a supplier
$pendingItems = OrderItem::query()
    ->whereIn('fulfillment_status', [
        FulfillmentStatus::Pending,
        FulfillmentStatus::ForwardedToSupplier,
    ])
    ->whereHas('product', fn ($q) => $q->where('supplier_id', $supplier->id))
    ->with(['order.customer', 'order.shippingAddress'])
    ->get();

// Get supplier revenue (items sold)
$revenue = OrderItem::query()
    ->whereHas('product', fn ($q) => $q->where('supplier_id', $supplier->id))
    ->where('fulfillment_status', FulfillmentStatus::Delivered)
    ->sum(DB::raw('unit_price_amount * quantity'));

Permissions

The supplier feature uses the following permissions:
PermissionDescription
browse_suppliersView the suppliers list
read_suppliersView supplier details
add_suppliersCreate new suppliers
edit_suppliersUpdate existing suppliers
delete_suppliersDelete suppliers
// Check permission
$user->hasPermissionTo('browse_suppliers');

// Assign permission to a role
$role->givePermissionTo('browse_suppliers');

Components

The supplier feature registers its components through the product configuration. Publish the product components to customize:
php artisan shopper:component:publish product
This includes:
// In config/shopper/components/product.php
return [
    'pages' => [
        'supplier-index' => Livewire\Pages\Supplier\Index::class,
        // ...
    ],
    'components' => [
        'slide-overs.supplier-form' => Livewire\SlideOvers\SupplierForm::class,
        // ...
    ],
];

Metadata

The metadata column (JSON) can store any additional supplier-specific data:
$supplier = Supplier::query()->create([
    'name' => 'FastShip Logistics',
    'metadata' => [
        'payment_terms' => 'net_30',
        'currency' => 'USD',
        'minimum_order' => 100,
        'lead_time_days' => 7,
        'return_policy' => '30 days',
        'api_endpoint' => 'https://api.fastship.com/v2',
    ],
]);

// Access metadata
$terms = $supplier->metadata['payment_terms'];