feat: Introduce FeedDeliveryObserver for automatic feed stock management and enhance ProcessFeedSchedule with stock pre-checks and transactions.

This commit is contained in:
Yoga Pangestu 2026-02-26 13:42:23 +07:00
parent 551437c8e6
commit 22ef713f92
3 changed files with 82 additions and 9 deletions

View File

@ -5,6 +5,7 @@
use App\Models\FeedDelivery;
use App\Models\FeedSchedule;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class ProcessFeedSchedule extends Command
{
@ -21,7 +22,7 @@ public function handle(): int
{
$time = $this->argument('time') ?? now()->format('H:i');
$schedules = FeedSchedule::whereTime('scheduled_at', $time)->get();
$schedules = FeedSchedule::with('feeds.unit')->whereTime('scheduled_at', $time)->get();
if ($schedules->isEmpty()) {
$this->info("No schedules found for time: {$time}");
@ -31,15 +32,27 @@ public function handle(): int
foreach ($schedules as $schedule) {
foreach ($schedule->feeds as $feed) {
$quantity = $feed->pivot->quantity;
$decrement = min($quantity, $feed->stock);
$feed->decrement('stock', $decrement);
if ($feed->stock < $feed->pivot->quantity) {
$this->error("Stock pakan '{$feed->name}' tidak cukup untuk jadwal '{$schedule->scheduled_at->format('H:i')}'. Dibutuhkan: {$feed->pivot->quantity}, Tersedia: {$feed->stock}");
FeedDelivery::create([
'feed_id' => $feed->id,
'quantity' => $quantity,
'delivered_at' => now(),
]);
return 1;
}
}
try {
DB::transaction(function () use ($schedule) {
foreach ($schedule->feeds as $feed) {
FeedDelivery::create([
'feed_id' => $feed->id,
'quantity' => $feed->pivot->quantity,
'delivered_at' => now(),
]);
}
});
} catch (\Exception $e) {
$this->error('Gagal memproses jadwal pakan: '.$e->getMessage());
return 1;
}
}

View File

@ -2,11 +2,14 @@
namespace App\Models;
use App\Observers\FeedDeliveryObserver;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
#[ObservedBy([FeedDeliveryObserver::class])]
class FeedDelivery extends Model
{
use HasFactory, SoftDeletes;

View File

@ -0,0 +1,57 @@
<?php
namespace App\Observers;
use App\Models\FeedDelivery;
use Illuminate\Support\Facades\DB;
class FeedDeliveryObserver
{
/**
* Handle the FeedDelivery "created" event.
*/
public function created(FeedDelivery $feedDelivery): void
{
$feedDelivery->feed()->decrement('stock', $feedDelivery->quantity);
}
/**
* Handle the FeedDelivery "updating" event.
*/
public function updating(FeedDelivery $feedDelivery): void
{
if ($feedDelivery->isDirty('quantity')) {
$oldQuantity = $feedDelivery->getOriginal('quantity');
$newQuantity = $feedDelivery->quantity;
$diff = $newQuantity - $oldQuantity;
$feedDelivery->feed()->decrement('stock', $diff);
}
if ($feedDelivery->isDirty('feed_id')) {
$oldFeedId = $feedDelivery->getOriginal('feed_id');
$newFeedId = $feedDelivery->feed_id;
DB::table('feeds')->where('id', $oldFeedId)->increment('stock', $feedDelivery->getOriginal('quantity'));
DB::table('feeds')->where('id', $newFeedId)->decrement('stock', $feedDelivery->quantity);
}
}
/**
* Handle the FeedDelivery "deleted" event.
*/
public function deleted(FeedDelivery $feedDelivery): void
{
$feedDelivery->feed()->increment('stock', $feedDelivery->quantity);
}
/**
* Handle the FeedDelivery "restored" event.
*/
public function restored(FeedDelivery $feedDelivery): void
{
$feedDelivery->feed()->decrement('stock', $feedDelivery->quantity);
}
}