# Minimarket Stock Checkout Bug Fix

**Date**: May 24, 2026
**Status**: Implemented & Tested
**Related Features**: Minimarket Cash/Cashless Checkout, Product Stock Mutation

---

## 1. Problem / Bug Description

In the legacy implementation, customer checkout requests (`payMinimarketCash` and `payMinimarketCashless` in `[StoreController.php](file:///home/noxturne/projects/ziad/backend/ziad-laravel-template/app/Http/Controllers/StoreController.php)`) allowed products to be purchased even if the requested quantity exceeded the available stock. 

Furthermore, the stock update was executed using a raw SQL decrement (`stock-count`) without any validation or concurrency locking. Under concurrent checkout conditions, or if the client payload was manipulated, the product stock was reduced to negative numbers (stock < 0), causing inventory discrepancies.

---

## 2. Implemented Fix

To resolve this issue, the checkout flow was updated with transaction safety and pessimistic row locking:

### Pessimistic Row Locking & Validation
In `SaveTransactionProduct()` of `[TransactionService.php](file:///home/noxturne/projects/ziad/backend/ziad-laravel-template/app/Services/TransactionService.php)`:
- Retrieve each product in the cart with `Product::lockForUpdate()->find($id)` inside the database transaction.
- If `isCountStock === 1`, validate if the database stock is sufficient (`stock >= count`).
- If the stock is insufficient, throw a `\RuntimeException` detailing the product name, available stock, and requested count. This halts the operation immediately.
- Decrement stock directly on the locked Eloquent model instance: `$productDb->stock -= $count` and persist via `$productDb->save()`.

### Database Transactions
In `payMinimarketCash()` and `payMinimarketCashless()` of `[StoreController.php](file:///home/noxturne/projects/ziad/backend/ziad-laravel-template/app/Http/Controllers/StoreController.php)`:
- Wrapped the entire checkout process in database transactions (`DB::beginTransaction()`, `DB::commit()`, and `DB::rollBack()`).
- This guarantees atomicity: if any product has insufficient stock or any other step fails, all mutations (including student/store balance updates, journal insertions, and transaction logs) are completely rolled back to maintain database consistency.

---

## 3. Verification & Testing

A new comprehensive feature test suite has been created at `[MinimarketStockCheckoutTest.php](file:///home/noxturne/projects/ziad/backend/ziad-laravel-template/tests/Feature/MinimarketStockCheckoutTest.php)` to cover the following scenarios:
1. **Cash Checkout (Success):** Verifies that checking out with sufficient stock successfully records the transaction and decrements the product's stock.
2. **Cash Checkout (Failure/Rollback):** Verifies that attempting to checkout with insufficient stock throws the expected error, leaves the product stock unchanged, and does not record any transactions.
3. **Cashless Checkout (Success):** Verifies that cashless checkout correctly decrements both product stock and student balance, and removes the checkout queue from `card_queues`.
4. **Cashless Checkout (Failure/Rollback):** Verifies that cashless checkout with insufficient stock fails, leaving the product stock, student balance, and card queue unchanged (rolled back).

### How to Run the Tests
Run the PHPUnit tests inside the Laravel PHP container:
```bash
docker exec -it ziad-laravel-template-php ./vendor/bin/phpunit tests/Feature/MinimarketStockCheckoutTest.php
```
