# AccountingCore & SystemCore Integration

This document explains the integration between AccountingCore and SystemCore modules for automatic syncing of sales and purchase orders to accounting transactions.

## Overview

The integration automatically creates accounting transactions (income/expense) when sales or purchase orders are marked as paid, providing seamless financial tracking without manual data entry.

## Features

- **Automatic Transaction Creation**: Sales orders create income transactions, purchase orders create expense transactions
- **Bidirectional Relationships**: Orders link to their accounting transactions and vice versa
- **Payment Status Tracking**: Automatically syncs when payment status changes to 'paid' or 'partial'
- **Configurable**: Enable/disable auto-sync per order type via settings
- **Manual Sync Option**: Bulk sync existing orders or manually sync individual orders
- **Transaction Removal**: Automatically removes transactions if payment status changes back to 'pending'

## Architecture

### Database Structure

The `basic_transactions` table now includes polymorphic fields to link to source documents:
- `sourceable_type` - The class name of the source (e.g., CoreSalesOrder)
- `sourceable_id` - The ID of the source order
- `sync_status` - Tracks sync type: 'manual', 'auto_synced', or 'pending'

### Event-Driven Sync

The integration uses Laravel's event system:

1. **Events** (SystemCore module):
   - `SalesOrderPaymentStatusChanged` - Dispatched when sales order payment status changes
   - `PurchaseOrderPaymentStatusChanged` - Dispatched when purchase order payment status changes

2. **Listeners** (AccountingCore module):
   - `SyncSalesOrderToAccounting` - Creates/updates income transactions
   - `SyncPurchaseOrderToAccounting` - Creates/updates expense transactions

3. **Service** (AccountingCore module):
   - `AccountingSyncService` - Handles all sync business logic

## Installation

### 1. Run Migration

```bash
php artisan module:migrate AccountingCore
```

This adds the polymorphic fields (`sourceable_type`, `sourceable_id`, `sync_status`) to the `basic_transactions` table.

### 2. Clear Cache

```bash
php artisan optimize:clear
```

## Configuration

### Enable Auto-Sync

Navigate to: **Accounting Core > Settings > Integration Settings**

Toggle the following options:
- **Auto-Sync Sales Orders**: Automatically create income transactions when sales orders are marked as paid
- **Auto-Sync Purchase Orders**: Automatically create expense transactions when purchase orders are marked as paid

Default: Both are **disabled** for safety. Enable when ready to start automatic syncing.

## Usage

### Automatic Syncing

Once auto-sync is enabled:

1. **Sales Order** → Mark payment status as 'paid' or 'partial'
   - Income transaction automatically created in 'Sales' category
   - Transaction amount = order total_amount
   - Transaction date = order date
   - Reference number = order number

2. **Purchase Order** → Mark payment status as 'paid' or 'partial'
   - Expense transaction automatically created in 'Purchases' category
   - Transaction amount = order total_amount
   - Transaction date = order date
   - Reference number = order number

### Manual Syncing

You can manually sync orders using the `AccountingSyncService`:

```php
use Modules\AccountingCore\app\Services\AccountingSyncService;

$syncService = app(AccountingSyncService::class);

// Sync a specific sales order
$transaction = $syncService->syncSalesOrder($salesOrder, $force = true);

// Sync a specific purchase order
$transaction = $syncService->syncPurchaseOrder($purchaseOrder, $force = true);

// Bulk sync all paid sales orders
$result = $syncService->bulkSyncOrders('sales');
// Returns: ['synced' => [...], 'errors' => [...], 'total' => 10]

// Bulk sync all paid purchase orders
$result = $syncService->bulkSyncOrders('purchases');
```

### Checking Sync Status

```php
// Check if an order is synced
$isSynced = $syncService->isOrderSynced($salesOrder);

// Get the accounting transaction for an order
$transaction = $syncService->getTransactionForOrder($salesOrder);

// Or use the relationship
$transaction = $salesOrder->accountingTransaction;
```

### Removing Sync

```php
// Remove accounting transaction for an order
$syncService->unsyncOrder($salesOrder);
```

## Relationships

### From Order to Transaction

```php
$salesOrder = CoreSalesOrder::find(1);
$transaction = $salesOrder->accountingTransaction; // Returns BasicTransaction or null

$purchaseOrder = CorePurchaseOrder::find(1);
$transaction = $purchaseOrder->accountingTransaction; // Returns BasicTransaction or null
```

### From Transaction to Order

```php
$transaction = BasicTransaction::find(1);
$order = $transaction->sourceable; // Returns CoreSalesOrder or CorePurchaseOrder or null
```

## Transaction Categories

The integration automatically creates/uses these categories:

- **Sales** (Income) - For sales order transactions
- **Purchases** (Expense) - For purchase order transactions

You can customize categories in the AccountingCore module.

## Best Practices

### 1. Enable Auto-Sync Gradually
- Test with a few orders first
- Enable for one order type at a time
- Monitor the results before full deployment

### 2. Bulk Sync Existing Orders
Before enabling auto-sync, bulk sync existing paid orders:

```php
// In a controller or artisan command
$syncService = app(AccountingSyncService::class);

// Sync all existing paid sales orders
$salesResult = $syncService->bulkSyncOrders('sales');
Log::info('Synced sales orders', $salesResult);

// Sync all existing paid purchase orders
$purchaseResult = $syncService->bulkSyncOrders('purchases');
Log::info('Synced purchase orders', $purchaseResult);
```

### 3. Handle Partial Payments
Currently, the integration records the full order amount regardless of payment status. For partial payments, you may want to:
- Track multiple transactions per order (enhance the relationship from `morphOne` to `morphMany`)
- Or record only the paid amount (customize `calculateTransactionAmount` method)

### 4. Monitor Sync Failures
All sync failures are logged to Laravel's log system:

```php
// Check logs for sync errors
tail -f storage/logs/laravel.log | grep "Failed to sync"
```

## Troubleshooting

### Transactions Not Created Automatically

**Check:**
1. Auto-sync settings are enabled in AccountingCore settings
2. Order payment status is 'paid' or 'partial'
3. EventServiceProvider is registered in AccountingCore
4. Laravel event cache is cleared: `php artisan event:clear`

### Duplicate Transactions

The service checks for existing transactions before creating new ones. If duplicates occur:
1. Check the `sourceable_type` and `sourceable_id` indexes
2. Verify the model's fully qualified class name

### Transaction Not Removed When Payment Reverted

The listener automatically removes transactions when payment status changes from 'paid'/'partial' to 'pending'. If this doesn't work:
1. Check that the event is dispatching: `Log::info('Payment status changed', [$oldStatus, $newStatus])`
2. Verify the listener is registered in EventServiceProvider

## Extending the Integration

### Custom Transaction Categories

Modify `AccountingSyncService` methods:
- `getSalesCategory()` - Customize sales category selection
- `getPurchasesCategory()` - Customize purchase category selection

### Custom Transaction Amount Calculation

Override `calculateTransactionAmount()` in AccountingSyncService:

```php
protected function calculateTransactionAmount(Model $order): float
{
    // Custom logic here
    // For example, only record partial payment amount:
    if ($order->payment_status === 'partial') {
        return $order->paid_amount ?? $order->total_amount;
    }

    return $order->total_amount;
}
```

### Additional Order Types

To sync other order types:

1. Create an event (e.g., `ServiceOrderPaymentStatusChanged`)
2. Create a listener (e.g., `SyncServiceOrderToAccounting`)
3. Add sync method to `AccountingSyncService`
4. Register the event/listener in `EventServiceProvider`

## API Reference

### AccountingSyncService Methods

| Method | Parameters | Returns | Description |
|--------|-----------|---------|-------------|
| `syncSalesOrder()` | `CoreSalesOrder $order`, `bool $force = false` | `?BasicTransaction` | Sync sales order to accounting |
| `syncPurchaseOrder()` | `CorePurchaseOrder $order`, `bool $force = false` | `?BasicTransaction` | Sync purchase order to accounting |
| `unsyncOrder()` | `Model $order` | `bool` | Remove accounting transaction |
| `getTransactionForOrder()` | `Model $order` | `?BasicTransaction` | Get transaction for order |
| `isOrderSynced()` | `Model $order` | `bool` | Check if order is synced |
| `bulkSyncOrders()` | `string $type` (sales/purchases) | `array` | Bulk sync all eligible orders |

## Security Considerations

- Only authenticated users can trigger sync operations
- All transactions record `created_by_id` for audit trails
- Laravel Auditing tracks all transaction changes
- Soft deletes preserve transaction history

## Performance

- Events are handled synchronously by default
- For high-volume operations, consider queuing the listeners:
  - Add `ShouldQueue` interface to listener classes
  - Configure queue workers

## Support

For issues or questions:
1. Check Laravel logs: `storage/logs/laravel.log`
2. Review event/listener registration in `EventServiceProvider`
3. Verify module is enabled: `modules_statuses.json`
