# Inventory Processing API

## Overview

The Inventory Processing API provides endpoints to manually trigger the processing of pending inventory transactions. This is useful for on-demand processing, testing, or when you need immediate inventory updates without waiting for the cron job.

## Endpoint

### Process Inventory Transactions

Processes all unprocessed records in the `inventory_txn` table and updates the `inventory` table accordingly.

**URL:** `/api/inventory/processTransactions`

**Method:** `POST`

**Authentication:** Required (uses session/token)

**Content-Type:** `application/json`

---

## Request

### Headers
```
Content-Type: application/json
Cookie: PHPSESSID=your_session_id
```

### Body
No request body required. This endpoint processes all pending transactions.

```json
{}
```

---

## Response

### Success Response (200 OK)

When transactions are processed successfully:

```json
{
  "success": true,
  "message": "Inventory transactions processed successfully",
  "unprocessed_count": 15,
  "processed_count": 15
}
```

### Success Response - No Transactions (200 OK)

When there are no pending transactions:

```json
{
  "success": true,
  "message": "No transactions to process",
  "unprocessed_count": 0,
  "processed_count": 0
}
```

### Error Response (500 Internal Server Error)

```json
{
  "success": false,
  "error": "Failed to process inventory transactions",
  "message": "No batch number found for product_id: 123e4567-e89b-12d3-a456-426614174000"
}
```

---

## Examples

### cURL Example

```bash
curl -X POST https://your-domain.com/api/inventory/processTransactions \
  -H "Content-Type: application/json" \
  -H "Cookie: PHPSESSID=your_session_id" \
  -d '{}'
```

### JavaScript (Fetch API)

```javascript
fetch('/api/inventory/processTransactions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  credentials: 'include' // Include cookies
})
  .then(response => response.json())
  .then(data => {
    console.log('Processed:', data.processed_count);
    console.log('Message:', data.message);
  })
  .catch(error => {
    console.error('Error:', error);
  });
```

### jQuery Example

```javascript
$.ajax({
  url: '/api/inventory/processTransactions',
  method: 'POST',
  contentType: 'application/json',
  success: function(response) {
    console.log('Success:', response.message);
    console.log('Processed ' + response.processed_count + ' transactions');
  },
  error: function(xhr, status, error) {
    console.error('Error:', xhr.responseJSON.message);
  }
});
```

### PHP Example

```php
<?php
$ch = curl_init('https://your-domain.com/api/inventory/processTransactions');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Cookie: PHPSESSID=' . session_id()
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([]));

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode === 200) {
    $data = json_decode($response, true);
    echo "Processed {$data['processed_count']} transactions\n";
} else {
    echo "Error: $response\n";
}
```

---

## Use Cases

### 1. **Immediate Processing After POS Sale**

Trigger processing right after a sale to immediately update inventory levels:

```javascript
// After POS sale completes
await fetch('/api/pos/sale', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(saleData)
});

// Immediately process inventory
await fetch('/api/inventory/processTransactions', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' }
});
```

### 2. **Manual Admin Button**

Add a button in your admin panel to manually trigger processing:

```html
<button id="processInventory" class="btn btn-primary">
  Process Pending Inventory
</button>

<script>
$('#processInventory').on('click', function() {
  const btn = $(this);
  btn.prop('disabled', true).text('Processing...');
  
  $.post('/api/inventory/processTransactions')
    .done(function(response) {
      alert('Processed ' + response.processed_count + ' transactions');
    })
    .fail(function(xhr) {
      alert('Error: ' + xhr.responseJSON.message);
    })
    .always(function() {
      btn.prop('disabled', false).text('Process Pending Inventory');
    });
});
</script>
```

### 3. **Scheduled Webhook**

Call from an external scheduler or webhook:

```bash
# Add to external scheduler (e.g., GitHub Actions, Jenkins)
curl -X POST https://your-domain.com/api/inventory/processTransactions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
```

### 4. **Testing During Development**

Quickly process transactions during testing:

```bash
# Test script
php -r "
  \$ch = curl_init('http://localhost/api/inventory/processTransactions');
  curl_setopt(\$ch, CURLOPT_POST, true);
  curl_setopt(\$ch, CURLOPT_RETURNTRANSFER, true);
  \$response = curl_exec(\$ch);
  echo \$response;
"
```

---

## What Happens When Called

1. **Fetch Unprocessed Transactions**
   - Queries `inventory_txn` table for records where `processed_at IS NULL`
   - Locks rows to prevent concurrent processing

2. **Aggregate Changes**
   - Groups transactions by `product_id` and `branch_id`
   - Sums up quantity changes

3. **Update Inventory**
   - Looks up `product_batch_number_id` for each product
   - Updates `inventory.current_qty` (or inserts if doesn't exist)
   - Uses database transactions for atomicity

4. **Mark as Processed**
   - Sets `processed_at = NOW()` for all processed transactions
   - Commits transaction

---

## Performance Considerations

- **Processing Time:** Typically 100-500ms for 10-50 transactions
- **Database Load:** Minimal - uses batch operations and transactions
- **Concurrency:** Safe to call multiple times (uses row locking)
- **Rate Limiting:** Consider adding rate limiting if exposed publicly

---

## Monitoring

### Check Pending Transactions

```sql
SELECT COUNT(*) as pending_count
FROM inventory_txn
WHERE processed_at IS NULL
AND isDeleted = false;
```

### Check Recently Processed

```sql
SELECT COUNT(*) as recently_processed
FROM inventory_txn
WHERE processed_at > NOW() - INTERVAL '1 hour'
AND isDeleted = false;
```

### Check Processing Failures

Look for transactions that remain unprocessed for a long time:

```sql
SELECT product_id, branch_id, change, reason, updatedAt
FROM inventory_txn
WHERE processed_at IS NULL
AND isDeleted = false
AND updatedAt < NOW() - INTERVAL '1 hour'
ORDER BY updatedAt ASC;
```

---

## Best Practices

1. **Use Cron for Regular Processing**
   - API is for on-demand/manual use
   - Cron job ensures consistent processing

2. **Call After Critical Operations**
   - After bulk imports
   - After end-of-day reconciliation
   - After major inventory adjustments

3. **Add to Admin Dashboard**
   - Show pending transaction count
   - Provide manual processing button
   - Display last processing time

4. **Log All Calls**
   - Track who triggered processing
   - Monitor processing frequency
   - Alert on repeated failures

5. **Handle Errors Gracefully**
   - Display user-friendly error messages
   - Retry failed processing
   - Notify administrators of persistent issues

---

## Troubleshooting

### Issue: "No transactions to process" but inventory is wrong

**Solution:** Transactions may have already been processed. Check `processed_at` timestamps.

```sql
SELECT * FROM inventory_txn
WHERE updatedAt > NOW() - INTERVAL '1 hour'
ORDER BY updatedAt DESC;
```

### Issue: Transactions processed but inventory not updated

**Solution:** Check for products without batch numbers:

```sql
SELECT DISTINCT it.product_id, p.name
FROM inventory_txn it
LEFT JOIN product_batch_number pbn ON it.product_id = pbn.product_id
LEFT JOIN products p ON it.product_id = p.product_id
WHERE pbn.product_batch_number_id IS NULL
AND it.processed_at IS NULL;
```

### Issue: 500 Error when calling endpoint

**Solution:** Check error logs:

```bash
tail -f /var/www/html/TAF/logs/error.log
```

Common causes:
- Missing `product_batch_number` records
- Database connection issues
- Insufficient permissions

---

## Related Endpoints

- `POST /api/pos/sale` - Create POS sale (generates inventory transactions)
- `POST /api/inventory/receiveInventory` - Receive inventory from vendor
- `POST /api/inventory/transferInventory` - Transfer between branches
- `GET /api/inventory/getInventory` - Get current inventory levels

---

## See Also

- [InventoryProcessingCron.md](./InventoryProcessingCron.md) - Cron job setup
- [FormBuilder.md](./FormBuilder.md) - Form configuration
- [WorkflowEngine.md](./WorkflowEngine.md) - Workflow automation
