This is the core order distribution algorithm from my 2017 WooCommerce multi-vendor marketplace:
<?php
/**
* Food Hub - Order Distribution System (2017)
*
* This recreates the core logic from my custom WooCommerce multi-vendor marketplace
* that aggregated agricultural products from multiple producers into unified orders.
*
* The key challenge: A customer orders "10 quarts of strawberries" but we need to
* distribute this across multiple vendors based on inventory, pricing,
* and delivery logistics.
*/
class MarketplaceOrderDistributor {
private $vendors;
private $delivery_zones;
public function __construct() {
// Sample vendor data (in production, this came from WooCommerce vendor tables)
$this->vendors = [
[
'id' => 101,
'name' => 'Sunrise Farms',
'products' => [
'strawberries' => [
'available_qty' => 15,
'price_per_unit' => 4.50,
'quality_grade' => 'A',
'harvest_date' => '2017-06-15'
]
],
'delivery_zone' => 'north',
'commission_rate' => 0.12 // Platform takes 12%
],
[
'id' => 102,
'name' => 'Valley Fresh Co-op',
'products' => [
'strawberries' => [
'available_qty' => 8,
'price_per_unit' => 4.25,
'quality_grade' => 'A',
'harvest_date' => '2017-06-14'
]
],
'delivery_zone' => 'central',
'commission_rate' => 0.10
],
[
'id' => 103,
'name' => 'Heritage Gardens',
'products' => [
'strawberries' => [
'available_qty' => 12,
'price_per_unit' => 5.00,
'quality_grade' => 'Premium',
'harvest_date' => '2017-06-16'
]
],
'delivery_zone' => 'south',
'commission_rate' => 0.15
]
];
// Delivery zones and their logistics costs
$this->delivery_zones = [
'north' => ['base_cost' => 5.00, 'per_mile' => 0.50],
'central' => ['base_cost' => 3.00, 'per_mile' => 0.40],
'south' => ['base_cost' => 7.00, 'per_mile' => 0.60]
];
}
/**
* Main distribution algorithm
* Takes a customer order and distributes it across vendors
* considering inventory, pricing, quality, and logistics
*/
public function distributeOrder($product, $requested_qty, $customer_location, $max_vendors = 3) {
echo "<h3>Processing Order: {$requested_qty} quarts of {$product}</h3>\n";
echo "<p><strong>Customer Location:</strong> {$customer_location}</p>\n";
// Step 1: Find available vendors for this product
$available_vendors = $this->getAvailableVendors($product);
if (empty($available_vendors)) {
return ['error' => 'No vendors available for this product'];
}
// Step 2: Calculate total cost for each vendor (including logistics)
$vendor_costs = $this->calculateVendorCosts($available_vendors, $customer_location);
// Step 3: Sort vendors by cost-effectiveness (price + logistics + quality)
$sorted_vendors = $this->rankVendors($vendor_costs);
// Step 4: Distribute the order using our smart allocation algorithm
$distribution = $this->allocateOrder($sorted_vendors, $requested_qty, $max_vendors);
// Step 5: Generate vendor order slips
$order_slips = $this->generateOrderSlips($distribution, $product);
return [
'distribution' => $distribution,
'order_slips' => $order_slips,
'total_cost' => array_sum(array_column($distribution, 'total_cost')),
'total_commission' => array_sum(array_column($distribution, 'commission'))
];
}
/**
* Find vendors who have the requested product in stock
*/
private function getAvailableVendors($product) {
$available = [];
foreach ($this->vendors as $vendor) {
if (isset($vendor['products'][$product]) &&
$vendor['products'][$product]['available_qty'] > 0) {
$available[] = $vendor;
}
}
return $available;
}
/**
* Calculate total cost per unit for each vendor (product + logistics)
*/
private function calculateVendorCosts($vendors, $customer_location) {
$costs = [];
foreach ($vendors as $vendor) {
$delivery_cost = $this->calculateDeliveryFee($vendor['delivery_zone'], $customer_location);
$base_price = $vendor['products']['strawberries']['price_per_unit'];
// Total cost per unit = base price + (delivery cost / quantity)
// This spreads delivery cost across all units from this vendor
$costs[] = [
'vendor' => $vendor,
'base_price' => $base_price,
'delivery_cost' => $delivery_cost,
'cost_per_unit' => $base_price + ($delivery_cost / max(1, $vendor['products']['strawberries']['available_qty'])),
'quality_score' => $this->getQualityScore($vendor['products']['strawberries']['quality_grade'])
];
}
return $costs;
}
/**
* Vendor ranking considering price, quality, and logistics
*/
private function rankVendors($vendor_costs) {
// Sort by a weighted score: 60% cost, 40% quality
usort($vendor_costs, function($a, $b) {
$score_a = ($a['cost_per_unit'] * 0.6) - ($a['quality_score'] * 0.4);
$score_b = ($b['cost_per_unit'] * 0.6) - ($b['quality_score'] * 0.4);
return $score_a <=> $score_b;
});
return $vendor_costs;
}
/**
* Smart allocation algorithm
*/
private function allocateOrder($sorted_vendors, $requested_qty, $max_vendors) {
$distribution = [];
$remaining_qty = $requested_qty;
$vendors_used = 0;
foreach ($sorted_vendors as $vendor_data) {
if ($remaining_qty <= 0 || $vendors_used >= $max_vendors) {
break;
}
$vendor = $vendor_data['vendor'];
$available = $vendor['products']['strawberries']['available_qty'];
// Take what we need or what's available, whichever is less
$allocated_qty = min($remaining_qty, $available);
if ($allocated_qty > 0) {
$unit_price = $vendor['products']['strawberries']['price_per_unit'];
$subtotal = $allocated_qty * $unit_price;
$commission = $subtotal * $vendor['commission_rate'];
$vendor_payment = $subtotal - $commission;
$distribution[] = [
'vendor_id' => $vendor['id'],
'vendor_name' => $vendor['name'],
'quantity' => $allocated_qty,
'unit_price' => $unit_price,
'subtotal' => $subtotal,
'commission' => $commission,
'vendor_payment' => $vendor_payment,
'total_cost' => $subtotal + $vendor_data['delivery_cost'],
'delivery_cost' => $vendor_data['delivery_cost'],
'quality_grade' => $vendor['products']['strawberries']['quality_grade']
];
$remaining_qty -= $allocated_qty;
$vendors_used++;
}
}
// Check if we could fulfill the entire order
if ($remaining_qty > 0) {
// In the real system, this would trigger backorder or waitlist logic
echo "<div class='alert alert-warning'>Could only fulfill " . ($requested_qty - $remaining_qty) . " of {$requested_qty} requested units</div>\n";
}
return $distribution;
}
/**
* Generate the actual order slips that vendors would receive
* This was critical for the multi-vendor workflow
*/
private function generateOrderSlips($distribution, $product) {
$order_slips = [];
$order_id = 'ORD-' . date('Ymd') . '-' . rand(1000, 9999);
foreach ($distribution as $allocation) {
$order_slips[] = [
'slip_id' => $order_id . '-V' . $allocation['vendor_id'],
'vendor_name' => $allocation['vendor_name'],
'product' => $product,
'quantity_to_fulfill' => $allocation['quantity'],
'payment_amount' => $allocation['vendor_payment'],
'delivery_instructions' => $this->generateDeliveryInstructions($allocation),
'fulfillment_deadline' => date('Y-m-d', strtotime('+2 days')),
'quality_requirements' => 'Grade: ' . $allocation['quality_grade']
];
}
return $order_slips;
}
/**
* Helper functions for the distribution logic
*/
private function calculateDeliveryFee($vendor_zone, $customer_location) {
// Simplified delivery calculation
$zone_data = $this->delivery_zones[$vendor_zone] ?? $this->delivery_zones['central'];
$estimated_miles = rand(5, 25); // In reality, this used Google Maps API
return $zone_data['base_cost'] + ($zone_data['per_mile'] * $estimated_miles);
}
private function getQualityScore($grade) {
$scores = ['Premium' => 5, 'A' => 4, 'B' => 3, 'C' => 2];
return $scores[$grade] ?? 2;
}
private function generateDeliveryInstructions($allocation) {
return "Deliver to central pickup point by 10 AM on fulfillment date. " .
"Package in marketplace-branded containers. " .
"Include quality certification sheet.";
}
}