# UltimatePOS Codebase Knowledge Base

## Project Overview
- **Framework**: Laravel 9.x
- **Permission Package**: Spatie Laravel Permission (v5.5)
- **Module System**: nwidart/laravel-modules (v9.0)
- **Architecture**: Modular monolith with extensive module support

## Core Architecture

### 1. Permission System

#### Permission Package
- Uses **Spatie Laravel Permission** (`spatie/laravel-permission`)
- Configuration: `config/permission.php`
- Main tables: `roles`, `permissions`, `model_has_roles`, `model_has_permissions`, `role_has_permissions`

#### Location-Based Permissions
- **Key Permission**: `access_all_locations` - Grants access to all locations
- **Location-Specific**: `location.{location_id}` - Grants access to specific location
- **User Model Method**: `permitted_locations($business_id = null)`
  - Returns: `'all'` (string) or `[location_ids]` (array)
  - Checks: `access_all_locations` permission OR `location.{id}` permissions

#### Permission Enforcement Pattern
```php
$permitted_locations = auth()->user()->permitted_locations();
if ($permitted_locations != 'all') {
    $query->whereIn('location_id', $permitted_locations);
}
```

#### Common Permission Checks
- `auth()->user()->can('permission.name')`
- `auth()->user()->hasPermissionTo('permission.name')`
- Location checks: `User::can_access_this_location($location_id, $business_id)`

### 2. Multi-Location Inventory System

#### Core Tables
1. **`business_locations`**: Stores location information
   - Fields: `id`, `business_id`, `name`, `location_id`, `is_active`, etc.
   - Model: `App\BusinessLocation`

2. **`variation_location_details`**: Tracks stock per location per variation
   - Fields: `id`, `product_id`, `product_variation_id`, `variation_id`, `location_id`, `qty_available`
   - Model: `App\VariationLocationDetails`
   - **This is the core inventory tracking table**

3. **`product_locations`**: Pivot table for product-location associations
   - Fields: `product_id`, `location_id`
   - Determines which products are available at which locations

#### Inventory Flow
- **Stock Tracking**: Each variation has stock per location in `variation_location_details`
- **Product Availability**: Products linked to locations via `product_locations` pivot
- **Stock Updates**: Handled through `TransactionUtil` and `ProductUtil` classes
- **Stock Movements**: Purchase, Sale, Transfer, Adjustment all update `variation_location_details`

#### Key Models
- `App\Product`: Main product model with `product_locations()` relationship
- `App\Variation`: Product variations (SKU level)
- `App\VariationLocationDetails`: Location-specific stock quantities
- `App\BusinessLocation`: Business locations

#### Location Filtering in Queries
```php
// Get permitted locations
$permitted_locations = auth()->user()->permitted_locations();

// Filter queries
if ($permitted_locations != 'all') {
    $query->whereIn('location_id', $permitted_locations);
    // OR for variation_location_details
    $query->whereIn('vld.location_id', $permitted_locations);
}
```

### 3. Reporting System

#### Main Report Controller
- **File**: `app/Http/Controllers/ReportController.php`
- **Key Methods**:
  - `getProfitLoss()`: Profit/Loss report with location filtering
  - `getPurchaseSell()`: Purchase vs Sales report
  - `getCustomerSuppliers()`: Customer/Supplier reports
  - `getStockReport()`: Stock reports
  - `getProductReport()`: Product performance reports
  - `getRegisterReport()`: Cash register reports

#### Report Filtering Pattern
All reports follow this pattern:
```php
$permitted_locations = auth()->user()->permitted_locations();
$location_id = $request->get('location_id');

// Apply location filtering
if ($permitted_locations != 'all') {
    $query->whereIn('transactions.location_id', $permitted_locations);
}

// Apply specific location if selected
if (!empty($location_id)) {
    $query->where('transactions.location_id', $location_id);
}
```

#### Advanced Reports Module
- **Module**: `Modules/AdvancedReports/`
- Additional report controllers for specialized reports
- Includes: Stock Reports, Sales Reports, Profit/Loss, GST Reports, etc.

#### Report Utilities
- `App\Utils\TransactionUtil`: Core transaction reporting utilities
  - `getProfitLossDetails()`: Detailed P&L calculation
  - `getPurchaseTotals()`: Purchase totals with location filtering
  - `getSellTotals()`: Sales totals with location filtering
  - `getOpeningClosingStock()`: Stock calculations
  - `getGrossProfit()`: Gross profit calculations
  - `registerReport()`: Cash register reports

### 4. Transaction System

#### Transaction Model
- **Model**: `App\Transaction`
- **Types**: `purchase`, `sell`, `expense`, `stock_adjustment`, `sell_transfer`, `purchase_transfer`, `opening_stock`, `sell_return`, `purchase_return`, `payroll`, `expense_refund`, `sales_order`, `purchase_order`
- **Statuses**: `received`, `pending`, `ordered`, `draft`, `final`, `in_transit`, `completed`

#### Transaction Utilities
- **File**: `app/Utils/TransactionUtil.php`
- **Key Methods**:
  - `createSellTransaction()`: Creates sell transactions
  - `createTransaction()`: Generic transaction creation
  - `updateStock()`: Updates stock after transactions
  - Location-aware transaction creation

#### Stock Updates
- Stock updates happen automatically during:
  - Purchases (increase stock)
  - Sales (decrease stock)
  - Stock Transfers (move between locations)
  - Stock Adjustments (manual corrections)
  - Returns (reverse stock movements)

### 5. User Management

#### User Model (`App\User`)
- Uses `HasRoles` trait from Spatie Permission
- **Key Methods**:
  - `permitted_locations($business_id = null)`: Returns permitted locations
  - `can_access_this_location($location_id, $business_id = null)`: Static check method
  - `scopeOnlyPermittedLocations($query)`: Query scope for filtering

#### User-Location Relationship
- Users can have:
  - `access_all_locations` permission: Full access
  - `location.{id}` permissions: Access to specific locations
  - Permissions checked via `permitted_locations()` method

### 6. Business Location System

#### BusinessLocation Model
- **Key Method**: `forDropdown($business_id, $show_all = false, $receipt_printer_type_attribute = false, $append_id = true, $check_permission = true)`
- Automatically filters by user's permitted locations when `$check_permission = true`
- Returns location dropdown with location filtering

#### Location Features
- Each location can have:
  - Default price group
  - Default payment accounts
  - Invoice scheme
  - Receipt printer settings
  - Featured products

### 7. Product Management

#### Product Model (`App\Product`)
- **Relationships**:
  - `product_locations()`: Many-to-many with BusinessLocation
  - `variations()`: Has many variations
  - `product_variations()`: Has many product variations

#### Product Utilities
- **File**: `app/Utils/ProductUtil.php`
- Handles product creation, variation management, stock calculations
- Location-aware product queries

#### Stock Queries
```php
// Get stock for specific location
VariationLocationDetails::where('variation_id', $variation_id)
    ->where('location_id', $location_id)
    ->first();

// Get stock across permitted locations
$permitted_locations = auth()->user()->permitted_locations();
if ($permitted_locations != 'all') {
    $query->whereIn('vld.location_id', $permitted_locations);
}
```

### 8. Middleware Stack

#### Key Middleware
1. **SetSessionData**: Sets user, business, currency, financial year in session
2. **CheckUserLogin**: Validates user login status
3. **AdminSidebarMenu**: Builds admin sidebar menu
4. **Language**: Sets application language
5. **Timezone**: Sets timezone

#### Route Protection
Routes are protected with:
```php
Route::middleware(['setData', 'web', 'auth', 'SetSessionData', 'language', 'timezone', 'AdminSidebarMenu', 'CheckUserLogin'])
```

### 9. Common Patterns

#### Location Filtering Pattern
```php
// 1. Get permitted locations
$permitted_locations = auth()->user()->permitted_locations();

// 2. Apply filter if not 'all'
if ($permitted_locations != 'all') {
    $query->whereIn('location_id', $permitted_locations);
}

// 3. Apply specific location if provided
if (!empty($location_id)) {
    $query->where('location_id', $location_id);
}
```

#### Permission Check Pattern
```php
// Check permission before action
if (!auth()->user()->can('permission.name')) {
    abort(403, 'Unauthorized action.');
}
```

#### Location Dropdown Pattern
```php
// Get locations dropdown (automatically filtered by permissions)
$business_locations = BusinessLocation::forDropdown($business_id, true);
```

### 10. Database Structure

#### Key Tables
- `business_locations`: Business locations
- `variation_location_details`: Stock per location per variation
- `product_locations`: Product-location associations
- `transactions`: All transactions (purchases, sales, etc.)
- `transaction_sell_lines`: Sale line items
- `purchase_lines`: Purchase line items
- `roles`: User roles
- `permissions`: System permissions
- `model_has_roles`: User-role assignments
- `model_has_permissions`: User-permission assignments

### 11. Module System

#### Modules Structure
- Located in `Modules/` directory
- Each module is self-contained with:
  - Controllers
  - Models
  - Views
  - Routes
  - Migrations

#### Key Modules
- **AdvancedReports**: Advanced reporting features
- **Accounting**: Accounting integration
- **Crm**: Customer Relationship Management
- **Essentials**: Essential features
- **InventoryManagement**: Inventory management
- **Manufacturing**: Manufacturing features
- **Repair**: Repair management
- **Superadmin**: Super admin features

### 12. Stock Transfer Flow

#### Stock Transfer Process
1. Create transfer transaction (`sell_transfer` or `purchase_transfer`)
2. Source location stock decreases
3. Destination location stock increases
4. Tracked in `variation_location_details` for both locations
5. Location permissions enforced on both source and destination

### 13. Reporting Best Practices

#### Report Implementation Checklist
1. ✅ Get `permitted_locations` from authenticated user
2. ✅ Apply location filtering to queries
3. ✅ Check user permissions before generating report
4. ✅ Filter by specific location if provided in request
5. ✅ Use `TransactionUtil` methods for calculations
6. ✅ Respect location permissions in all queries

### 14. Common Utility Classes

#### TransactionUtil (`app/Utils/TransactionUtil.php`)
- Transaction creation and management
- Stock calculations
- Profit/Loss calculations
- Location-aware transaction operations

#### ProductUtil (`app/Utils/ProductUtil.php`)
- Product and variation management
- Stock calculations
- Location-aware product queries

#### BusinessUtil (`app/Utils/BusinessUtil.php`)
- Business settings management
- Financial year calculations

#### ModuleUtil (`app/Utils/ModuleUtil.php`)
- Module management
- Permission checks
- Subscription checks

## Important Notes

1. **Always check permissions** before performing actions
2. **Always filter by permitted locations** in queries
3. **Location permissions are hierarchical**: `access_all_locations` > `location.{id}`
4. **Stock is tracked per location** in `variation_location_details`
5. **Products must be linked to locations** via `product_locations` to be available
6. **All reports should respect location permissions**
7. **Transaction creation automatically updates stock** per location
8. **User sessions store business_id** for multi-tenant support

## Security Considerations

1. **Never trust client-side location IDs** - always validate against `permitted_locations()`
2. **Check permissions at controller level** before actions
3. **Filter queries by permitted locations** to prevent data leakage
4. **Use Laravel's authorization policies** where applicable
5. **Validate business_id** matches session business_id

### 15. Stock Update Flow

#### Stock Update Methods
- **`ProductUtil::updateProductStock()`**: Main method for updating stock based on transaction status changes
  - Handles status transitions: `received` ↔ `not received`
  - Calls `updateProductQuantity()` or `decreaseProductQuantity()` based on status
  - Location-specific: Updates `variation_location_details` for the transaction's location

- **`ProductUtil::updateProductQuantity()`**: Updates quantity for a specific location
  - Finds or creates `VariationLocationDetails` record
  - Calculates difference and updates `qty_available`
  - Handles currency conversions if needed

- **`ProductUtil::decreaseProductQuantity()`**: Decreases stock for a location
  - Decrements `qty_available` in `variation_location_details`
  - Used when transaction status changes from `received` to other status

#### Stock Transfer Flow
- **Transaction Types**: `sell_transfer` (source) and `purchase_transfer` (destination)
- **Process**:
  1. Create `sell_transfer` transaction at source location (decreases stock)
  2. Create `purchase_transfer` transaction at destination location (increases stock)
  3. Linked via `transfer_parent_id` in destination transaction
  4. Stock updates happen through standard purchase/sell stock update mechanisms
  5. Both locations must be accessible to user (permission checked)

#### Stock Adjustment Flow
- **Transaction Type**: `stock_adjustment`
- Updates `variation_location_details.qty_available` directly
- Can increase or decrease stock
- Location-specific adjustments

#### Purchase Flow
- **Transaction Type**: `purchase`
- **Status**: `received` → stock increases
- Updates `variation_location_details` for purchase location
- Links to `purchase_lines` table

#### Sales Flow
- **Transaction Type**: `sell`
- **Status**: `final` → stock decreases
- Updates `variation_location_details` for sale location
- Links to `transaction_sell_lines` table
- Can map to specific purchase lines via `transaction_sell_lines_purchase_lines`

### 16. Module System Details

#### AdvancedReports Module
- **Location**: `Modules/AdvancedReports/`
- **Key Features**: 
  - Advanced reporting with location filtering
  - Customer recognition and rewards
  - Staff performance tracking
  - GST reports
  - Business analytics
- **Controllers**: 48+ report controllers
- **Exports**: Excel/CSV exports for all reports
- **Permissions**: Module-specific permissions added via seeder

#### Module Structure Pattern
```
Modules/{ModuleName}/
├── Entities/          # Models
├── Http/
│   ├── Controllers/  # Controllers
│   └── Middleware/   # Middleware
├── Database/
│   ├── Migrations/   # Database migrations
│   └── Seeders/      # Database seeders
├── Resources/
│   ├── views/        # Blade templates
│   └── lang/         # Language files
├── Routes/
│   ├── web.php       # Web routes
│   └── api.php       # API routes
└── Utils/            # Utility classes
```

### 17. Transaction Status Flow

#### Transaction Statuses
- **`draft`**: Unfinalized transaction
- **`final`**: Completed transaction (stock is updated)
- **`received`**: Purchase/transfer received (stock updated)
- **`pending`**: Awaiting completion
- **`ordered`**: Order placed but not received
- **`in_transit`**: Stock transfer in transit
- **`completed`**: Transfer completed

#### Stock Update Rules
- **Purchase**: Stock increases when status = `received`
- **Sale**: Stock decreases when status = `final`
- **Transfer**: Source decreases when status = `received`, destination increases when status = `received`
- **Return**: Reverses original transaction stock movement

### 18. Reporting Filtering Best Practices

#### Standard Report Filter Pattern
```php
// 1. Check permission
if (!auth()->user()->can('report.permission')) {
    abort(403, 'Unauthorized action.');
}

// 2. Get business ID
$business_id = $request->session()->get('user.business_id');

// 3. Get permitted locations
$permitted_locations = auth()->user()->permitted_locations();

// 4. Build query with location filtering
$query = Transaction::where('business_id', $business_id);

if ($permitted_locations != 'all') {
    $query->whereIn('location_id', $permitted_locations);
}

// 5. Apply additional filters
$location_id = $request->get('location_id');
if (!empty($location_id)) {
    // Validate location is in permitted locations
    if ($permitted_locations != 'all' && !in_array($location_id, $permitted_locations)) {
        abort(403, 'Unauthorized location.');
    }
    $query->where('location_id', $location_id);
}

// 6. Apply date range
$start_date = $request->get('start_date');
$end_date = $request->get('end_date');
if (!empty($start_date) && !empty($end_date)) {
    $query->whereBetween('transaction_date', [$start_date, $end_date]);
}
```

### 19. Product-Location Relationship

#### Product Availability
- Products must be linked to locations via `product_locations` pivot table
- Only products linked to a location appear in that location's inventory
- Link created when:
  - Product is added to a location
  - Product is purchased at a location
  - Product is transferred to a location

#### Stock Query Pattern
```php
// Get products with stock for a location
$products = Product::join('variations as v', 'products.id', '=', 'v.product_id')
    ->join('variation_location_details as vld', 'v.id', '=', 'vld.variation_id')
    ->join('product_locations as pl', 'pl.product_id', '=', 'products.id')
    ->where('pl.location_id', $location_id)
    ->where('vld.location_id', $location_id)
    ->where('vld.qty_available', '>', 0)
    ->select('products.*', 'vld.qty_available')
    ->get();
```

### 20. Key Utility Classes

#### TransactionUtil (`app/Utils/TransactionUtil.php`)
- **Key Methods**:
  - `createSellTransaction()`: Creates sell transactions
  - `createTransaction()`: Generic transaction creation
  - `getProfitLossDetails()`: Profit/Loss calculations with location filtering
  - `getPurchaseTotals()`: Purchase totals with location filtering
  - `getSellTotals()`: Sales totals with location filtering
  - `getOpeningClosingStock()`: Stock calculations per location
  - `getGrossProfit()`: Gross profit calculations
  - `registerReport()`: Cash register reports

#### ProductUtil (`app/Utils/ProductUtil.php`)
- **Key Methods**:
  - `updateProductStock()`: Updates stock based on transaction status
  - `updateProductQuantity()`: Updates quantity for a location
  - `decreaseProductQuantity()`: Decreases stock for a location
  - `getCurrentStock()`: Gets current stock for variation at location
  - `createSingleProductVariation()`: Creates single-type product variations
  - `createVariableProductVariations()`: Creates variable-type product variations
  - `adjustStockOverSelling()`: Adjusts stock for overselling scenarios

#### BusinessUtil (`app/Utils/BusinessUtil.php`)
- Business settings management
- Financial year calculations
- Currency formatting

#### ModuleUtil (`app/Utils/ModuleUtil.php`)
- Module management
- Permission checks
- Subscription checks

---

*Last Updated: Comprehensive codebase analysis completed*
*Framework: Laravel 9.x with Spatie Permission 5.5*
*Module System: nwidart/laravel-modules v9.0*

