# TaxCore Implementation Checklist

## Implementation Status (October 2, 2025)

This document tracks the implementation status of the TaxCore Node.js architecture migration.

## ✅ Completed Components

### 1. Node.js TaxCore Service
**File:** `/var/www/html/TAF/websocket-server/taxcore-service.js`

- [x] HTTP server on port 3001
- [x] CORS enabled for browser access
- [x] Health check endpoint (`GET /health`)
- [x] Tax rates endpoint (`GET /tax-rates`)
- [x] Sale creation endpoint (`POST /sale`)
- [x] Support for all sale types (Normal, Advance, Proforma, Training, Copy)
- [x] mTLS certificate handling via curl
- [x] Auto-discovery of PFX certificate
- [x] Default field injection (date, type, options)
- [x] Comprehensive error handling and logging

**Status:** ✅ Fully Implemented

### 2. PHP Backend (PosController)
**File:** `/var/www/html/TAF/api/controllers/PosController.php`

- [x] `sale()` method - Saves sale data to `lineitems_payments`
- [x] `taxcore()` method - Proxy to Node.js service
- [x] `callTaxCoreService()` - HTTP client to Node.js
- [x] Certificate path resolution with fallbacks
- [x] Customer metadata persistence in both tables
- [x] Inventory deduction integration
- [x] Environment variable support
- [x] Payment type mapping
- [x] Cashier information fetching

**Status:** ✅ Fully Implemented

### 3. Frontend (POS.js)
**File:** `/var/www/html/TAF/FrontEnd/js/modules/POS/POS.js`

- [x] `sendTaxCoreData()` - Sends to TaxCore (direct or proxy)
- [x] `sendSaleData()` - Sends to PHP backend
- [x] `saveTaxCoreDataToDB()` - IndexedDB → PostgreSQL sync
- [x] `saveSaleDataToDB()` - Local sale data persistence
- [x] `createSale()` - Unified sale creation function
- [x] Payment modal integration
- [x] Multiple payment methods support
- [x] Customer selection and persistence
- [x] Tax label assignment
- [x] UUIDv7 transaction ID generation
- [x] Direct/Proxy mode configuration (localStorage)

**Status:** ✅ Fully Implemented

### 4. Database Schema
**Tables:**
- [x] `sales_receipts` - TaxCore receipt data
- [x] `lineitems_payments` - Sale line items and payments
- [x] Both linked by `sales_receipt_id` (UUID)

**Status:** ✅ Schema Exists

### 5. Documentation
- [x] `websocket-server/TAXCORE_SERVICE.md`
- [x] `docs/TaxCore_NodeJS_Migration.md`
- [x] `docs/TaxCore_Architecture_Diagrams.md`
- [x] `docs/TaxCore_Current_Architecture.md` (NEW)

**Status:** ✅ Complete

## ⚠️ Items to Verify

### 1. Data Flow Verification

**Test Steps:**
```bash
# 1. Start Node.js service
cd /var/www/html/TAF/websocket-server
npm run taxcore

# 2. Verify service is running
curl http://localhost:3001/health
# Expected: {"status":"ok","service":"TaxCore Service"}

# 3. Test in browser
# - Open POS module
# - Add items to cart
# - Complete a sale
# - Check browser console for:
#   * sendTaxCoreData call
#   * sendSaleData call
#   * saveTaxCoreDataToDB call
#   * saveSaleDataToDB call
```

**Verification Points:**
- [ ] Node.js service receives sale request
- [ ] TaxCore API returns receipt
- [ ] Browser saves to `sales_receipts` via IndexedDB
- [ ] PHP saves to `lineitems_payments` table
- [ ] Both records have same `sales_receipt_id`
- [ ] Customer data persisted in both tables
- [ ] Inventory deducted correctly

### 2. Direct vs Proxy Mode

**Direct Mode Test:**
```javascript
// In browser console
localStorage.setItem('taxcore_direct', 'true');
localStorage.setItem('taxcore_service_url', 'http://localhost:3001');
location.reload();
```

**Proxy Mode Test:**
```javascript
// In browser console
localStorage.setItem('taxcore_direct', 'false');
location.reload();
```

**Verification:**
- [ ] Direct mode: Browser → Node.js → TaxCore
- [ ] Proxy mode: Browser → PHP → Node.js → TaxCore
- [ ] Both modes save data correctly
- [ ] Error handling works in both modes

### 3. All Sale Types

Test each sale type:
- [ ] Normal Sale
- [ ] Proforma Invoice
- [ ] Training Invoice
- [ ] Advance Payment
- [ ] Copy Invoice
- [ ] Refund

**Verification:**
- [ ] Correct `invoiceType` sent to TaxCore
- [ ] Correct `type` field in database
- [ ] Receipt displays correctly
- [ ] Data saved to both tables

### 4. Payment Methods

Test each payment method:
- [ ] Cash
- [ ] Card/EFTPOS
- [ ] Mobile Money (Mpaisa, Digicel)
- [ ] Check
- [ ] Wire Transfer
- [ ] Multiple payments (split payment)

**Verification:**
- [ ] Correct payment type codes sent to TaxCore
- [ ] Payments array saved correctly
- [ ] Multiple payments handled properly

### 5. Customer Integration

Test customer scenarios:
- [ ] Sale with no customer
- [ ] Sale with customer (name + TIN)
- [ ] Sale with customer ID only
- [ ] Customer balance updates (for credit sales)

**Verification:**
- [ ] Customer data in `sales_receipts.data`
- [ ] Customer data in `lineitems_payments`
- [ ] Buyer info sent to TaxCore correctly

### 6. Error Handling

Test error scenarios:
- [ ] Node.js service not running
- [ ] TaxCore API unreachable
- [ ] Invalid certificate
- [ ] Network timeout
- [ ] Invalid payload
- [ ] Database save failure

**Verification:**
- [ ] User-friendly error messages
- [ ] Errors logged appropriately
- [ ] No partial data saves
- [ ] Graceful degradation where possible

## 🔧 Implementation Tasks

### Task 1: Ensure Cashier Data is Compiled by Browser

**Current Status:** ⚠️ Needs Verification

The cashier name is currently fetched by PHP backend. According to the new architecture, the browser should compile this data.

**Action Required:**
```javascript
// In POS.js, ensure cashier info is added to saleData
const saleData = {
  // ... existing fields
  cashier_name: window.currentUserName || 'Unknown',
  cashier_id: window.currentUserId || null,
};
```

**Files to Update:**
- [ ] `FrontEnd/js/modules/POS/POS.js` - Add cashier to saleData
- [ ] `api/controllers/PosController.php` - Use provided cashier or fetch as fallback

### Task 2: Validate Tax Labels Assignment

**Current Status:** ⚠️ Needs Verification

Ensure all products have tax labels assigned before sending to TaxCore.

**Action Required:**
```javascript
// In POS.js, ensure labels are set for all items
items.forEach(item => {
  if (!item.labels || !Array.isArray(item.labels) || item.labels.length === 0) {
    // Default to 'G' (0% tax) if no labels
    item.labels = ['G'];
    console.warn(`Product ${item.name} has no tax labels, defaulting to G (0%)`);
  }
});
```

**Files to Update:**
- [ ] `FrontEnd/js/modules/POS/POS.js` - Validate labels in createSale()
- [ ] Add UI feedback for products missing tax labels

### Task 3: Atomic Transaction Handling

**Current Status:** ⚠️ Not Implemented

Currently, TaxCore save and database save are independent. If one fails, the other may succeed, causing data inconsistency.

**Proposed Solution:**

**Option A: Transaction Wrapper (PHP)**
```php
// In PosController
public function completeSale() {
  $input = json_decode(file_get_contents('php://input'), true);
  
  DB::beginTransaction();
  try {
    // 1. Call TaxCore via Node.js
    $taxCoreResult = $this->callTaxCoreService($input);
    
    // 2. Save TaxCore receipt
    $this->saveTaxCoreReceipt($taxCoreResult);
    
    // 3. Save sale data
    $this->saveSaleData($input);
    
    // 4. Deduct inventory
    $this->deductInventory($input);
    
    DB::commit();
    respond(200, ['success' => true, 'receipt' => $taxCoreResult]);
  } catch (\Exception $e) {
    DB::rollback();
    respond(500, ['error' => $e->getMessage()]);
  }
}
```

**Option B: Compensating Transactions (Browser)**
```javascript
// In POS.js
async function createSale(items, total, options) {
  const uuid = generateUUIDv7();
  let taxCoreResult = null;
  
  try {
    // Step 1: Get TaxCore receipt
    taxCoreResult = await sendTaxCoreData(saleData);
    
    if (!taxCoreResult || !taxCoreResult.receipt) {
      throw new Error('TaxCore receipt not received');
    }
    
    // Step 2: Save both (in parallel for speed, but handle rollback)
    const [taxSave, saleSave] = await Promise.allSettled([
      saveTaxCoreDataToDB(uuid, taxCoreResult),
      sendSaleData(saleData).then(r => saveSaleDataToDB(uuid, r))
    ]);
    
    // Check if both succeeded
    if (taxSave.status === 'rejected' || saleSave.status === 'rejected') {
      // Attempt rollback - delete TaxCore receipt if sale save failed
      if (taxSave.status === 'fulfilled' && saleSave.status === 'rejected') {
        await deleteTaxCoreReceipt(uuid);
      }
      throw new Error('Failed to save sale data completely');
    }
    
    return { success: true, taxCoreResult, uuid };
    
  } catch (error) {
    // If we have a TaxCore receipt but failed to save, log for manual recovery
    if (taxCoreResult && taxCoreResult.receipt) {
      console.error('CRITICAL: TaxCore receipt obtained but save failed', {
        uuid,
        invoiceNumber: taxCoreResult.taxcore?.invoiceNumber,
        error: error.message
      });
      // TODO: Queue for retry or manual intervention
    }
    throw error;
  }
}
```

**Recommendation:** Implement Option A (Transaction Wrapper) for data integrity.

**Files to Create/Update:**
- [ ] `api/controllers/PosController.php` - Add `completeSale()` method
- [ ] `FrontEnd/js/modules/POS/POS.js` - Update to use new endpoint
- [ ] Add database transaction support to QueryBuilder

### Task 4: Offline Queue for TaxCore Failures

**Current Status:** ❌ Not Implemented

If TaxCore is unreachable, sales should be queued locally and submitted when service is restored.

**Proposed Implementation:**
```javascript
// In POS.js
const OFFLINE_QUEUE_STORE = 'taxcore_offline_queue';

async function sendTaxCoreData(saleData) {
  try {
    const result = await fetch(endpoint, { /* ... */ });
    return await result.json();
  } catch (error) {
    // Queue for later submission
    await queueOfflineSale(saleData);
    
    // Return mock receipt for now (mark as pending)
    return {
      success: false,
      offline: true,
      pending: true,
      error: 'TaxCore unreachable - queued for submission',
      receipt: 'PENDING SUBMISSION'
    };
  }
}

async function queueOfflineSale(saleData) {
  const db = await dbService.getDatabase();
  const record = {
    id: generateUUIDv7(),
    saleData: saleData,
    timestamp: Date.now(),
    retryCount: 0,
    status: 'queued'
  };
  await db.put(OFFLINE_QUEUE_STORE, record);
  console.log('Sale queued for offline submission:', record.id);
}

// Background sync worker
async function processOfflineQueue() {
  const db = await dbService.getDatabase();
  const queued = await db.getAllFromIndex(OFFLINE_QUEUE_STORE, 'status', 'queued');
  
  for (const item of queued) {
    try {
      const result = await sendTaxCoreData(item.saleData);
      if (result.success) {
        // Update record as submitted
        await db.put(OFFLINE_QUEUE_STORE, { ...item, status: 'submitted' });
        console.log('Offline sale submitted:', item.id);
      }
    } catch (error) {
      // Increment retry count
      item.retryCount++;
      if (item.retryCount > 5) {
        item.status = 'failed';
      }
      await db.put(OFFLINE_QUEUE_STORE, item);
    }
  }
}

// Start background sync every 30 seconds
setInterval(processOfflineQueue, 30000);
```

**Files to Create/Update:**
- [ ] `FrontEnd/js/modules/POS/offlineQueue.js` - Offline queue manager
- [ ] `FrontEnd/js/modules/POS/POS.js` - Integrate queue
- [ ] Add IndexedDB store for offline queue

### Task 5: Service Health Monitoring

**Current Status:** ❌ Not Implemented

Add UI indicators for TaxCore service health.

**Proposed Implementation:**
```javascript
// In POS.js
async function checkTaxCoreHealth() {
  try {
    const res = await fetch('http://localhost:3001/health', { timeout: 3000 });
    const data = await res.json();
    return data.status === 'ok';
  } catch {
    return false;
  }
}

// Show status indicator in UI
async function updateServiceStatus() {
  const isHealthy = await checkTaxCoreHealth();
  const indicator = document.getElementById('taxcoreStatusIndicator');
  
  if (indicator) {
    indicator.className = isHealthy ? 'status-ok' : 'status-error';
    indicator.title = isHealthy 
      ? 'TaxCore Service: Online' 
      : 'TaxCore Service: Offline';
  }
}

// Check every minute
setInterval(updateServiceStatus, 60000);
updateServiceStatus(); // Initial check
```

**Files to Update:**
- [ ] `FrontEnd/Dashboard.html` - Add status indicator
- [ ] `FrontEnd/js/modules/POS/POS.js` - Add health check
- [ ] `FrontEnd/css/pos.css` - Status indicator styles

## 📝 Testing Script

Create a comprehensive test script to verify the implementation:

**File:** `tests/taxcore_integration_test.sh`

```bash
#!/bin/bash

echo "=== TaxCore Integration Test ==="
echo ""

# Test 1: Node.js Service Health
echo "Test 1: Checking Node.js service health..."
HEALTH=$(curl -s http://localhost:3001/health)
if echo "$HEALTH" | grep -q "ok"; then
  echo "✅ Node.js service is healthy"
else
  echo "❌ Node.js service is not responding"
  exit 1
fi
echo ""

# Test 2: Tax Rates Endpoint
echo "Test 2: Fetching tax rates..."
TAX_RATES=$(curl -s http://localhost:3001/tax-rates)
if echo "$TAX_RATES" | grep -q "success"; then
  echo "✅ Tax rates fetched successfully"
else
  echo "❌ Failed to fetch tax rates"
fi
echo ""

# Test 3: Certificate Exists
echo "Test 3: Checking certificate..."
CERT_PATH="/var/www/html/TAF/FRCS_Certs_Install/LK2VRSH4-DeveloperAuthenticationCertificate.pfx"
if [ -f "$CERT_PATH" ]; then
  echo "✅ Certificate found at $CERT_PATH"
else
  echo "❌ Certificate not found"
fi
echo ""

# Test 4: Database Tables Exist
echo "Test 4: Checking database tables..."
TABLES=$(psql -U postgres -d taf_erp -c "SELECT tablename FROM pg_tables WHERE tablename IN ('sales_receipts', 'lineitems_payments');" -t)
if echo "$TABLES" | grep -q "sales_receipts" && echo "$TABLES" | grep -q "lineitems_payments"; then
  echo "✅ Required database tables exist"
else
  echo "❌ Database tables missing"
fi
echo ""

# Test 5: PHP Endpoint Accessible
echo "Test 5: Checking PHP endpoint..."
PHP_RESPONSE=$(curl -s -X POST http://localhost/api/POS/sale \
  -H "Content-Type: application/json" \
  -d '{"items":[],"payments":[]}' || echo "error")
if [ "$PHP_RESPONSE" != "error" ]; then
  echo "✅ PHP endpoint accessible"
else
  echo "❌ PHP endpoint not accessible"
fi
echo ""

echo "=== Test Summary ==="
echo "All critical components checked."
echo "Please test manually in browser for full verification."
```

## 🚀 Deployment Steps

1. **Start Node.js Service**
   ```bash
   cd /var/www/html/TAF/websocket-server
   npm install
   npm run taxcore
   ```

2. **Verify Service**
   ```bash
   curl http://localhost:3001/health
   ```

3. **Configure Browser (if needed)**
   ```javascript
   // Direct mode (recommended)
   localStorage.setItem('taxcore_direct', 'true');
   localStorage.setItem('taxcore_service_url', 'http://localhost:3001');
   ```

4. **Test Complete Sale Flow**
   - Open POS module
   - Add items to cart
   - Select customer (optional)
   - Click Pay
   - Verify receipt displays
   - Check database records

5. **Monitor Logs**
   ```bash
   # Node.js logs
   tail -f /usr/src/logs/taxcore-service.log
   
   # PHP logs
   tail -f /var/log/apache2/error.log
   ```

## ✅ Acceptance Criteria

The implementation is complete when:

- [ ] Node.js service runs reliably on port 3001
- [ ] All sale types work correctly
- [ ] Data saved to both database tables
- [ ] Customer information persists correctly
- [ ] Inventory deducted accurately
- [ ] Receipt displays properly
- [ ] Error handling is robust
- [ ] Both Direct and Proxy modes work
- [ ] Documentation is complete
- [ ] Manual testing passes all scenarios

## 📚 Related Documentation

- `docs/TaxCore_Current_Architecture.md` - Current architecture overview
- `websocket-server/TAXCORE_SERVICE.md` - Node.js service documentation
- `docs/TaxCore_NodeJS_Migration.md` - Migration guide
- `docs/TaxCore_Architecture_Diagrams.md` - Visual diagrams

---

**Last Updated:** October 2, 2025  
**Status:** Implementation ~90% Complete, Verification Required
