Projects/3BIT/winter-semester/IIS/xnecasr00/app/Models/Purchase.php
2026-04-14 19:28:46 +02:00

96 lines
2.5 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\DB;
use App\Models\PurchaseItem;
use App\Models\Wine;
class Purchase extends Model
{
/** @use HasFactory<\Database\Factories\PurchaseFactory> */
use HasFactory;
protected $fillable = [
'user_id',
'wine_id',
'amount',
'price',
'status',
'purchased_at',
'note',
];
/**
* Casts for attributes
*
* @var array
*/
protected $casts = [
'amount' => 'integer',
'price' => 'decimal:2',
'purchased_at' => 'datetime',
'status' => 'string',
'note' => 'string',
];
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function wine()
{
return $this->belongsTo(Wine::class, 'wine_id');
}
/**
* Purchase has many items (weak entity)
*/
public function items(): HasMany
{
return $this->hasMany(PurchaseItem::class, 'purchase_id');
}
/**
* Create a purchase with items and decrement wine stock atomically.
*
* $items = [ ['wine_id'=>1,'quantity'=>2,'unit_price'=>12.5], ... ]
*/
public static function createWithItems(array $data, array $items): self
{
return DB::transaction(function () use ($data, $items) {
$purchase = self::create($data);
foreach ($items as $it) {
$wine = Wine::findOrFail($it['wine_id']);
$qty = (int) ($it['quantity'] ?? 1);
if ($wine->bottles_in_stock !== null && $wine->bottles_in_stock < $qty) {
throw new \Exception("Insufficient stock for wine id {$wine->id}");
}
$unit = $it['unit_price'] ?? $wine->price_per_bottle ?? 0;
$lineTotal = round($qty * $unit, 2);
$purchase->items()->create([
'wine_id' => $wine->getKey(),
'quantity' => $qty,
'unit_price' => $unit,
'line_total' => $lineTotal,
]);
// decrement stock if tracked
if ($wine->bottles_in_stock !== null) {
$wine->decrement('bottles_in_stock', $qty);
}
}
return $purchase;
});
}
}