Skip to content

Place Service Developer Guide

Service layer for managing warehouse inventory operations with transaction safety and automatic logging.

Quick Start

php
use Obelaw\Warehouse\Facades\Warehouse;
use Obelaw\Warehouse\Models\Place\Inventory;
use Obelaw\Warehouse\Enums\PlaceItemType;

$inventory = Inventory::find(1);
$place = Warehouse::place($inventory);

// Add item
$item = $place->addItem($sourceModel, 'SKU-123', type: PlaceItemType::STORABLE);

// Check availability
$available = $place->getAvailableQuantity('SKU-123');

// Process item (IN → PENDING → OUT)
$place->prepareItem('SKU-123');
$place->deductItem('SKU-123');

Features

  • Transaction-safe operations
  • Auto-generated unique serial numbers
  • Status management (IN → PENDING → OUT)
  • Real-time quantity tracking
  • Comprehensive validation

Setup

php
use Obelaw\Warehouse\Facades\Warehouse;
use Obelaw\Warehouse\Models\Place\Inventory;
use Obelaw\Warehouse\Enums\{PlaceItemType, PlaceItemStatus};

Common Patterns

Basic Inventory Flow

php
$place = Warehouse::place($inventory);

// 1. Receive items
$item = $place->addItem($purchaseOrder, 'SKU-123');

// 2. Check stock
if ($place->hasAvailableQuantity('SKU-123', 1)) {
    // 3. Prepare for shipment
    $place->prepareItem('SKU-123');

    // 4. Ship item
    $place->deductItem('SKU-123');
}

Bulk Operations

php
// Check multiple SKUs
$requirements = ['SKU-A' => 5, 'SKU-B' => 10];

foreach ($requirements as $sku => $qty) {
    if (!$place->hasAvailableQuantity($sku, $qty)) {
        throw new Exception("Insufficient stock for {$sku}");
    }
}

// Process all items
foreach ($requirements as $sku => $qty) {
    for ($i = 0; $i < $qty; $i++) {
        $place->prepareItem($sku);
    }
}

Custom Serial Numbers

php
// Auto-generated serial
$item = $place->addItem($source, 'SKU-123');

// Custom serial
$item = $place->addItem($source, 'SKU-123', 'BATCH-2025-001');

Error Handling

php
try {
    $item = $place->addItem($source, $sku);
} catch (InvalidArgumentException $e) {
    // Validation errors (empty SKU, invalid place, etc.)
} catch (ModelNotFoundException $e) {
    // Product or item not found
} catch (Exception $e) {
    // Database errors, constraint violations
}

Development Tips

Transaction Safety

All operations are automatically wrapped in database transactions. For complex workflows, use explicit transactions:

php
DB::transaction(function () use ($place, $orderItems) {
    foreach ($orderItems as $item) {
        $place->prepareItem($item['sku']);
    }
    // Update order status, etc.
});

Performance Considerations

php
// ✅ Batch check availability
$skus = ['SKU-A', 'SKU-B', 'SKU-C'];
$available = collect($skus)->mapWithKeys(fn($sku) => [
    $sku => $place->getAvailableQuantity($sku)
]);

// ❌ Avoid multiple single checks in loops
foreach ($skus as $sku) {
    $qty = $place->getAvailableQuantity($sku); // N+1 queries
}

Status Filtering

php
use Obelaw\Warehouse\Enums\PlaceItemStatus;

// Get items by status
$inStock = $place->getItemsBySku('SKU-123', PlaceItemStatus::IN);
$pending = $place->getItemsBySku('SKU-123', PlaceItemStatus::PENDING);
$shipped = $place->getItemsBySku('SKU-123', PlaceItemStatus::OUT);

// Get all items
$allItems = $place->getItemsBySku('SKU-123');

Testing

php
// Test helpers
public function test_can_add_and_process_item()
{
    $inventory = Inventory::factory()->create();
    $place = Warehouse::place($inventory);
    $source = PurchaseOrder::factory()->create();

    // Add item
    $item = $place->addItem($source, 'TEST-SKU');
    $this->assertEquals(PlaceItemStatus::IN, $item->status);

    // Process item
    $place->prepareItem('TEST-SKU');
    $place->deductItem('TEST-SKU');

    $this->assertEquals(0, $place->getAvailableQuantity('TEST-SKU'));
}

API Reference

MethodPurposeReturns
addItem($source, $sku, $serial?, $type?)Add new itemPlaceItem
prepareItem($sku)IN → PENDINGPlaceItem
deductItem($sku)PENDING → OUTPlaceItem
getAvailableQuantity($sku, $status?)Get quantityint
hasAvailableQuantity($sku, $qty, $status?)Check availabilitybool
getItemsBySku($sku, $status?)Get itemsCollection
generateSerialNumber($digits?)Generate serialstring

Exceptions

  • InvalidArgumentException - Invalid inputs
  • ModelNotFoundException - Product/item not found
  • Exception - Database errors

Constants

php
PlaceService::DEFAULT_SERIAL_DIGITS = 16;
PlaceService::MIN_SERIAL_DIGITS = 8;
PlaceService::MAX_SERIAL_DIGITS = 32;

Released under the MIT License.