# Implementation Guide: Backdated Sales, Granular Permissions & POS Enhancements

This guide documents the changes required to implement the "Backdated Sales", "Granular Menu Permissions", and "POS Cart Quantity Input" features. Follow these steps to replicate the changes in another project instance.

## 1. Database Changes

### 1.1 Add Permissions Column to Users Table
Create a new migration to add the json `permissions` column to the `users` table.

```bash
php artisan make:migration add_permissions_to_users_table
```

Update the migration file:
```php
public function up(): void
{
    Schema::table('users', function (Blueprint $table) {
        $table->json('permissions')->nullable()->after('role');
    });
}

public function down(): void
{
    Schema::table('users', function (Blueprint $table) {
        $table->dropColumn('permissions');
    });
}
```
Run the migration: `php artisan migrate`

## 2. Backend Core Updates

### 2.1 Update `User` Model (`app/Models/User.php`)
- Add `permissions` to `$fillable`.
- Add `'permissions' => 'array'` to `$casts`.
- Add `hasPermission` method:

```php
public function hasPermission($permission): bool
{
    if ($this->role === 'admin') {
        return true;
    }
    return !empty($this->permissions) && !empty($this->permissions[$permission]);
}
```

### 2.2 Allow Timestamp Edits in Models
Add `'created_at'` and `'updated_at'` to the `$fillable` array in the following models to allow backdating:
- `app/Models/Transaction.php`
- `app/Models/TransactionItem.php`
- `app/Models/StockMovement.php`

### 2.3 Create Permission Middleware
Create `app/Http/Middleware/CheckPermission.php`:

```php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class CheckPermission
{
    public function handle(Request $request, Closure $next, string $permission): Response
    {
        if (!auth()->check()) return redirect()->route('login');
        if (!auth()->user()->hasPermission($permission)) {
            abort(403, 'Access denied. You do not have permission to view this page.');
        }
        return $next($request);
    }
}
```

### 2.4 Register Middleware (`bootstrap/app.php`)
Add the alias in the `withMiddleware` section:

```php
$middleware->alias([
    'admin' => \App\Http\Middleware\AdminMiddleware::class,
    'permission' => \App\Http\Middleware\CheckPermission::class, // Add this line
]);
```

## 3. Routes Configuration (`routes/web.php`)

Refactor the routes to use the new middleware instead of the rigid `admin` group.

```php
// BEFORE:
// Route::middleware('admin')->group(function () { ... });

// AFTER:
// Protected Routes (Admin or Permission based)
Route::resource('products', ProductController::class)->middleware('permission:view_products');
Route::resource('categories', CategoryController::class)->middleware('permission:view_categories');
Route::resource('suppliers', \App\Http\Controllers\SupplierController::class)->middleware('permission:view_suppliers');
Route::resource('customers', \App\Http\Controllers\CustomerController::class)->middleware('permission:view_customers');
Route::resource('transactions', \App\Http\Controllers\TransactionController::class)->middleware('permission:view_transactions');
Route::get('/reports', [ReportController::class, 'index'])->name('reports.index')->middleware('permission:view_reports');
// ... apply middleware to other report routes ...
Route::get('/reports/receivables', ...)->middleware('permission:view_receivables');

// Keep Admin Specific Routes
Route::middleware('admin')->group(function () {
    Route::resource('users', UserController::class);
    Route::get('/settings', ...);
});
```

## 4. Controller Logic

### 4.1 Update `UserController.php`
Update `store` and `update` methods to save permissions:

```php
// In store() and update()
'permissions' => $request->role === 'kasir' ? $request->input('permissions', []) : null,
```

### 4.2 Update `PosController.php` (Backdate Logic)
In the `store` method, handle the custom transaction date:

```php
$transactionDate = now();
if ($request->has('transaction_date') && auth()->user()->hasPermission('can_backdate_sales')) {
    $inputDate = \Carbon\Carbon::parse($request->transaction_date);
    $transactionDate = $inputDate->setTimeFrom(now());
}

// Ensure 'created_at' => $transactionDate is passed to Transaction::create(), TransactionItem::create(), and StockMovement::create()
```

## 5. User Interface (Views)

### 5.1 User Management (`resources/views/users/create.blade.php` & `edit.blade.php`)
Add the permission checkboxes form using AlpineJS logic to show only for 'Kasir' role. Include checkboxes for:
- `can_backdate_sales`
- `view_products`, `view_suppliers`, `view_customers`, etc.

### 5.2 Sidebar Navigation (`resources/views/layouts/sidebar.blade.php`)
Replace the single `if(admin)` check with granular checks for **Desktop and Mobile** menus:

```blade
@if(auth()->user()->role === 'admin' || auth()->user()->hasPermission('view_products'))
    <!-- Product Menu Link -->
@endif
<!-- Repeat for all other menus -->
```

### 5.3 POS Interface (`resources/views/pos/index.blade.php`)

**A. Backdate Input:**
Add date picker in the Payment Modal:
```blade
@if(auth()->user()->hasPermission('can_backdate_sales'))
    <!-- Date input field -->
@endif
```
Update JS `processTransaction` to send `transaction_date`.

**B. Cart Quantity Input:**
1. Update `updateCartDisplay` JS function to render `<input type="number">` instead of just text.
2. Add `updateItemQuantity(id, value)` JS function to handle changes.
3. Add CSS style to hide spin buttons (arrows) on number inputs:
```css
input[type=number]::-webkit-inner-spin-button, 
input[type=number]::-webkit-outer-spin-button { 
    -webkit-appearance: none; margin: 0; 
}
```
