- Implemented stock transfer creation and management with Livewire components. - Created StockTransfer and StockTransferItem models with necessary relationships. - Added migration files for stock_transfers and stock_transfer_items tables. - Developed traits for handling stock transfer items (add, delete, update). - Integrated stock transfer logging in StockActivityLogService. - Updated ViewServiceProvider to include stock transfer permissions and routes. - Created frontend views for stock transfer form and index with appropriate UI components. - Added role permissions for stock transfer actions in RolePermissionSeeder.
284 lines
8.9 KiB
PHP
284 lines
8.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Order;
|
|
use App\Models\Outlet;
|
|
use App\Models\Purchase;
|
|
use App\Models\Restock;
|
|
use App\Models\StockOpname;
|
|
use App\Models\StockTransfer;
|
|
use App\Models\Warehouse;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
class StockActivityLogService
|
|
{
|
|
public const LOG_PURCHASE = 'purchase';
|
|
|
|
public const LOG_DISTRIBUTION = 'distribution';
|
|
|
|
public const LOG_SALE = 'sale';
|
|
|
|
public const LOG_STOCK_OPNAME = 'stock_opname';
|
|
|
|
public const LOG_TRANSFER = 'transfer';
|
|
|
|
/**
|
|
* Log purchase activity (Incoming to Warehouse).
|
|
*/
|
|
public static function purchase(
|
|
Purchase $purchase,
|
|
Model $product,
|
|
int $quantity,
|
|
int $previousStock,
|
|
int $newStock,
|
|
?Model $causedBy = null
|
|
): void {
|
|
self::logWarehouse(
|
|
logName: self::LOG_PURCHASE,
|
|
event: 'increase',
|
|
description: "Purchase #{$purchase->hash_id}: Added {$quantity} stock to Warehouse.",
|
|
performedOn: $product,
|
|
warehouse: $purchase->warehouse,
|
|
quantityChange: $quantity,
|
|
previousStock: $previousStock,
|
|
newStock: $newStock,
|
|
extraProperties: [
|
|
'purchase_id' => $purchase->id,
|
|
'purchase_hash' => $purchase->hash_id,
|
|
],
|
|
causedBy: $causedBy
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Log distribution activity (Warehouse to Outlet).
|
|
* This logs two events: Out from Warehouse, In to Outlet.
|
|
*/
|
|
public static function distribution(
|
|
Restock $restock,
|
|
Model $product,
|
|
int $quantity,
|
|
int $warehousePreviousStock,
|
|
int $warehouseNewStock,
|
|
int $outletPreviousStock,
|
|
int $outletNewStock,
|
|
?Model $causedBy = null
|
|
): void {
|
|
// Log Warehouse Out
|
|
self::logWarehouse(
|
|
logName: self::LOG_DISTRIBUTION,
|
|
event: 'decrease',
|
|
description: "Restock #{$restock->hash_id}: Moved {$quantity} stock from Warehouse to Outlet.",
|
|
performedOn: $product,
|
|
warehouse: $restock->warehouse,
|
|
quantityChange: -1 * abs($quantity),
|
|
previousStock: $warehousePreviousStock,
|
|
newStock: $warehouseNewStock,
|
|
extraProperties: [
|
|
'restock_id' => $restock->id,
|
|
'restock_hash' => $restock->hash_id,
|
|
'target_outlet_id' => $restock->outlet_id,
|
|
],
|
|
causedBy: $causedBy
|
|
);
|
|
|
|
// Log Outlet In
|
|
self::logOutlet(
|
|
logName: self::LOG_DISTRIBUTION,
|
|
event: 'increase',
|
|
description: "Restock #{$restock->hash_id}: Received {$quantity} stock from Warehouse.",
|
|
performedOn: $product,
|
|
outlet: $restock->outlet,
|
|
quantityChange: abs($quantity),
|
|
previousStock: $outletPreviousStock,
|
|
newStock: $outletNewStock,
|
|
extraProperties: [
|
|
'restock_id' => $restock->id,
|
|
'restock_hash' => $restock->hash_id,
|
|
'source_warehouse_id' => $restock->warehouse_id,
|
|
],
|
|
causedBy: $causedBy
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Log sale activity (Outlet to Customer).
|
|
*/
|
|
public static function sale(
|
|
Order $order,
|
|
Model $product,
|
|
int $quantity,
|
|
int $previousStock,
|
|
int $newStock,
|
|
?Model $causedBy = null
|
|
): void {
|
|
self::logOutlet(
|
|
logName: self::LOG_SALE,
|
|
event: 'decrease',
|
|
description: "Order #{$order->hash_id}: Sold {$quantity} items.",
|
|
performedOn: $product,
|
|
outlet: $order->outlet,
|
|
quantityChange: -1 * abs($quantity),
|
|
previousStock: $previousStock,
|
|
newStock: $newStock,
|
|
extraProperties: [
|
|
'order_id' => $order->id,
|
|
'order_hash' => $order->hash_id,
|
|
],
|
|
causedBy: $causedBy ?? $order->user
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Log stock opname activity (Adjustment in Outlet).
|
|
*/
|
|
public static function stockOpname(
|
|
StockOpname $stockOpname,
|
|
Model $product,
|
|
int $quantityChange,
|
|
int $previousStock,
|
|
int $newStock,
|
|
?string $note = null,
|
|
?Model $causedBy = null
|
|
): void {
|
|
$event = $quantityChange > 0 ? 'increase' : 'decrease';
|
|
|
|
self::logOutlet(
|
|
logName: self::LOG_STOCK_OPNAME,
|
|
event: $event,
|
|
description: "Stock Opname #{$stockOpname->hash_id}: Adjusted stock by {$quantityChange}.",
|
|
performedOn: $product,
|
|
outlet: $stockOpname->outlet,
|
|
quantityChange: $quantityChange,
|
|
previousStock: $previousStock,
|
|
newStock: $newStock,
|
|
extraProperties: [
|
|
'stock_opname_id' => $stockOpname->id,
|
|
'stock_opname_hash' => $stockOpname->hash_id,
|
|
'note' => $note,
|
|
],
|
|
causedBy: $causedBy
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Log transfer activity (Outlet to Outlet).
|
|
* This logs two events: Out from Source Outlet, In to Destination Outlet.
|
|
*/
|
|
public static function transfer(
|
|
StockTransfer $stockTransfer,
|
|
Model $product,
|
|
int $quantity,
|
|
int $sourcePreviousStock,
|
|
int $sourceNewStock,
|
|
int $destinationPreviousStock,
|
|
int $destinationNewStock,
|
|
?Model $causedBy = null
|
|
): void {
|
|
// Log Source Outlet Out
|
|
self::logOutlet(
|
|
logName: self::LOG_TRANSFER,
|
|
event: 'decrease',
|
|
description: "Stock Transfer #{$stockTransfer->hash_id}: Moved {$quantity} stock from Source to Destination Outlet.",
|
|
performedOn: $product,
|
|
outlet: $stockTransfer->sourceOutlet,
|
|
quantityChange: -1 * abs($quantity),
|
|
previousStock: $sourcePreviousStock,
|
|
newStock: $sourceNewStock,
|
|
extraProperties: [
|
|
'stock_transfer_id' => $stockTransfer->id,
|
|
'stock_transfer_hash' => $stockTransfer->hash_id,
|
|
'destination_outlet_id' => $stockTransfer->destination_outlet_id,
|
|
],
|
|
causedBy: $causedBy
|
|
);
|
|
|
|
// Log Destination Outlet In
|
|
self::logOutlet(
|
|
logName: self::LOG_TRANSFER,
|
|
event: 'increase',
|
|
description: "Stock Transfer #{$stockTransfer->hash_id}: Received {$quantity} stock from Source Outlet.",
|
|
performedOn: $product,
|
|
outlet: $stockTransfer->destinationOutlet,
|
|
quantityChange: abs($quantity),
|
|
previousStock: $destinationPreviousStock,
|
|
newStock: $destinationNewStock,
|
|
extraProperties: [
|
|
'stock_transfer_id' => $stockTransfer->id,
|
|
'stock_transfer_hash' => $stockTransfer->hash_id,
|
|
'source_outlet_id' => $stockTransfer->source_outlet_id,
|
|
],
|
|
causedBy: $causedBy
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Log stock related activity for Outlet.
|
|
*/
|
|
public static function logOutlet(
|
|
string $logName,
|
|
string $event,
|
|
string $description,
|
|
Model $performedOn,
|
|
Model $outlet,
|
|
int $quantityChange,
|
|
int $previousStock,
|
|
int $newStock,
|
|
array $extraProperties = [],
|
|
?Model $causedBy = null
|
|
): void {
|
|
$causedBy = $causedBy ?: auth()->user();
|
|
|
|
$properties = array_merge([
|
|
'outlet_id' => $outlet->getKey(),
|
|
'quantity_change' => $quantityChange,
|
|
'previous_stock' => $previousStock,
|
|
'new_stock' => $newStock,
|
|
'location_type' => 'outlet',
|
|
'location_name' => $outlet->name ?? 'Unknown Outlet',
|
|
], $extraProperties);
|
|
|
|
activity($logName)
|
|
->performedOn($performedOn)
|
|
->causedBy($causedBy)
|
|
->withProperties($properties)
|
|
->event($event)
|
|
->log($description);
|
|
}
|
|
|
|
/**
|
|
* Log stock related activity for Warehouse.
|
|
*/
|
|
public static function logWarehouse(
|
|
string $logName,
|
|
string $event,
|
|
string $description,
|
|
Model $performedOn,
|
|
Warehouse $warehouse,
|
|
int $quantityChange,
|
|
int $previousStock,
|
|
int $newStock,
|
|
array $extraProperties = [],
|
|
?Model $causedBy = null
|
|
): void {
|
|
$causedBy = $causedBy ?: auth()->user();
|
|
|
|
$properties = array_merge([
|
|
'warehouse_id' => $warehouse->getKey(),
|
|
'quantity_change' => $quantityChange,
|
|
'previous_stock' => $previousStock,
|
|
'new_stock' => $newStock,
|
|
'location_type' => 'warehouse',
|
|
'location_name' => $warehouse->name ?? 'Unknown Warehouse',
|
|
], $extraProperties);
|
|
|
|
activity($logName)
|
|
->performedOn($performedOn)
|
|
->causedBy($causedBy)
|
|
->withProperties($properties)
|
|
->event($event)
|
|
->log($description);
|
|
}
|
|
}
|