# Phase 4: New Payment Methods (POS & Cash)

## Objective
Add POS and Cash payment methods alongside existing Stripe, Wallet, and Crypto. POS requires a receipt photo; Cash requires amounts received/returned and a photo of the cash.

---

## Existing Payment Providers

From `PaymentProvider` enum:
- `WALLET` - Debit from customer wallet
- `STRIPE` - Card payment via Stripe
- `DESK` - Manual desk payment (already exists, similar to POS)
- `NOWPAYMENTS` - Crypto payments

---

## Tasks

### 4.1 Extend PaymentProvider Enum

**File:** `app/Enums/PaymentProvider.php`

Add:
```php
case POS = 'pos';
case CASH = 'cash';
```

> **Note:** `DESK` already exists. Evaluate whether POS should replace DESK or coexist. If DESK is already used in production, keep both. POS differs from DESK in that it requires a receipt photo as proof.

### 4.2 Migration: Add Cash/POS Fields to Orders

**File:** `database/migrations/YYYY_MM_DD_HHMMSS_add_payment_details_to_orders_table.php`

Add columns:
```php
$table->json('payment_details')->nullable();
// Stores structured data:
// For CASH: { "amount_received", "amount_returned", "currency" }
// For POS: { "terminal_id" (optional) }
```

The receipt/cash photos will be stored via Spatie MediaLibrary on the Order model.

### 4.3 Add Media Collection to Order Model

**File:** `app/Models/Order.php`

Register media collections:
```php
public function registerMediaCollections(): void
{
    $this->addMediaCollection('payment_receipt')
        ->singleFile();

    $this->addMediaCollection('cash_photo')
        ->singleFile();
}
```

Add the `HasMedia` interface and `InteractsWithMedia` trait to Order if not already present.

### 4.4 POS Payment Controller

**File:** `app/Http/Controllers/Api/Employee/ShopManager/PosPayOrderController.php`

- `POST /v1/places/{place}/shop/carts/{order}/pay/pos`
- Multipart request with:
  - `receipt_photo` (image file, required)
  - `terminal_id` (string, optional)
- Validates order is WAITING_PAYMENT
- Stores receipt photo on Order media collection
- Marks order as PAID with `payment_provider = POS`
- Dispatches `OrderPaid` event (triggers existing listeners: bookings, wallet credits, etc.)

**Request:** `app/Http/Requests/ShopManager/PosPaymentRequest.php`
```php
public function rules(): array
{
    return [
        'receipt_photo' => ['required', 'image', 'max:10240'], // 10MB
        'terminal_id' => ['nullable', 'string', 'max:50'],
    ];
}
```

**Action:** `app/Actions/ShopManager/ProcessPosPaymentAction.php`

### 4.5 Cash Payment Controller

**File:** `app/Http/Controllers/Api/Employee/ShopManager/CashPayOrderController.php`

- `POST /v1/places/{place}/shop/carts/{order}/pay/cash`
- Multipart request with:
  - `amount_received` (numeric, required) - How much customer gave
  - `amount_returned` (numeric, required) - Change given back
  - `currency` (string, required) - Currency code
  - `cash_photo` (image file, required) - Photo of cash received
- Validates:
  - `amount_received >= order total`
  - `amount_returned = amount_received - order total`
- Stores cash photo and payment details
- Marks order as PAID with `payment_provider = CASH`
- Dispatches `OrderPaid` event

**Request:** `app/Http/Requests/ShopManager/CashPaymentRequest.php`
```php
public function rules(): array
{
    return [
        'amount_received' => ['required', 'numeric', 'min:0'],
        'amount_returned' => ['required', 'numeric', 'min:0'],
        'currency' => ['required', 'string', 'size:3'],
        'cash_photo' => ['required', 'image', 'max:10240'],
    ];
}
```

**Action:** `app/Actions/ShopManager/ProcessCashPaymentAction.php`

### 4.6 Existing Payment Wrappers

Create shop-manager-specific wrappers for the existing payment flows that work in the vendor context (employee paying on behalf of customer):

**File:** `app/Http/Controllers/Api/Employee/ShopManager/StripePayCartController.php`
- Wraps existing Stripe flow but operates in employee context
- Creates payment intent for the customer's order

**File:** `app/Http/Controllers/Api/Employee/ShopManager/WalletPayCartController.php`
- Wraps existing wallet payment
- Deducts from customer's wallet

**File:** `app/Http/Controllers/Api/Employee/ShopManager/CryptoPayCartController.php`
- Wraps existing NowPayments flow

### 4.7 Payment Details Resource

**File:** `app/Http/Resources/ShopManager/PaymentDetailsResource.php`

Returns payment-specific details after checkout:
```json
{
  "order_id": "public_id",
  "status": "paid",
  "payment_provider": "cash",
  "payment_details": {
    "amount_received": 50.00,
    "amount_returned": 9.00,
    "currency": "USD"
  },
  "receipt_url": "https://...",
  "paid_at": "2026-03-12T14:30:00Z"
}
```

### 4.8 Tests

**File:** `tests/Feature/Controllers/ShopManager/PaymentTest.php`

Test cases:
- [ ] POS payment with receipt photo marks order as PAID
- [ ] POS payment without photo returns 422
- [ ] Cash payment with correct amounts marks order as PAID
- [ ] Cash payment where amount_received < total returns 422
- [ ] Cash payment stores photo and amounts
- [ ] Cash payment calculates change correctly
- [ ] Stripe payment works in vendor context
- [ ] Wallet payment deducts from customer's wallet
- [ ] Cannot pay an already PAID order
- [ ] OrderPaid event is dispatched for all payment types
- [ ] Payment provider is correctly recorded on order

---

## Files Created/Modified

| Action | File |
|---|---|
| Modify | `app/Enums/PaymentProvider.php` |
| Create | `database/migrations/..._add_payment_details_to_orders_table.php` |
| Modify | `app/Models/Order.php` (HasMedia, media collections, payment_details cast) |
| Create | `app/Http/Controllers/Api/Employee/ShopManager/PosPayOrderController.php` |
| Create | `app/Http/Controllers/Api/Employee/ShopManager/CashPayOrderController.php` |
| Create | `app/Http/Controllers/Api/Employee/ShopManager/StripePayCartController.php` |
| Create | `app/Http/Controllers/Api/Employee/ShopManager/WalletPayCartController.php` |
| Create | `app/Http/Controllers/Api/Employee/ShopManager/CryptoPayCartController.php` |
| Create | `app/Actions/ShopManager/ProcessPosPaymentAction.php` |
| Create | `app/Actions/ShopManager/ProcessCashPaymentAction.php` |
| Create | `app/Http/Requests/ShopManager/PosPaymentRequest.php` |
| Create | `app/Http/Requests/ShopManager/CashPaymentRequest.php` |
| Create | `app/Http/Resources/ShopManager/PaymentDetailsResource.php` |
| Modify | `routes/api.php` |
| Create | `tests/Feature/Controllers/ShopManager/PaymentTest.php` |

---

## Acceptance Criteria

- [ ] POS payment requires and stores receipt photo
- [ ] Cash payment stores amounts + photo
- [ ] Change calculation is validated server-side
- [ ] All 5 payment types work through the shop manager flow
- [ ] OrderPaid event fires for POS and Cash (triggering existing downstream listeners)
- [ ] Payment details are retrievable on the order
- [ ] Swagger annotations on all controllers
- [ ] All tests pass
- [ ] `./gitCheck.sh` passes
