# Pre-Authorization - Examples

Comprehensive examples for implementing pre-authorization workflows.

---

## Table of Contents

1. [Basic Pre-Auth Creation](#basic-pre-auth-creation)
2. [Backend API Implementation](#backend-api-implementation)
3. [Frontend Form Submission](#frontend-form-submission)
4. [Complete Pre-Auth Examples](#complete-pre-auth-examples)
5. [Cancel Pre-Auth Examples](#cancel-pre-auth-examples)
6. [Use Case Examples](#use-case-examples)
7. [Error Handling](#error-handling)

---

## Basic Pre-Auth Creation

### Example 1: Generate Pre-Auth Form Parameters

```typescript
import { 
  generatePurchaseHash, 
  generateReqTime, 
  generateTransactionId,
  encodeItems 
} from 'aba-payway-sdk/utils';

function generatePreAuthParams(amount: number, customer: any) {
  const req_time = generateReqTime();
  const tran_id = generateTransactionId();
  
  const formParams = {
    req_time,
    merchant_id: process.env.PAYWAY_MERCHANT_ID!,
    tran_id,
    amount,
    currency: 'USD',
    type: 'pre-auth', // 👈 Key difference
    firstname: customer.firstName,
    lastname: customer.lastName,
    email: customer.email,
    phone: customer.phone,
    items: encodeItems([{
      name: 'Reservation Deposit',
      quantity: 1,
      price: amount
    }]),
    return_url: Buffer.from('https://yourapp.com/return').toString('base64'),
    hash: ''
  };
  
  formParams.hash = generatePurchaseHash(
    formParams, 
    process.env.PAYWAY_API_KEY!
  );
  
  return {
    formAction: 'https://checkout-sandbox.payway.com.kh/api/payment-gateway/v1/payments/purchase',
    formParams,
    tranId: tran_id
  };
}

// Usage
const preAuth = generatePreAuthParams(200.00, {
  firstName: 'John',
  lastName: 'Doe',
  email: 'john@example.com',
  phone: '012345678'
});

console.log('Transaction ID:', preAuth.tranId);
console.log('Form Action:', preAuth.formAction);
```

### Example 2: Multiple Payment Method Support

```typescript
function generatePreAuthWithPaymentOption(
  amount: number,
  paymentMethod: 'cards' | 'abapay_khqr' | 'abapay_khqr_deeplink'
) {
  const formParams = {
    req_time: generateReqTime(),
    merchant_id: process.env.PAYWAY_MERCHANT_ID!,
    tran_id: generateTransactionId(),
    amount,
    currency: 'USD',
    type: 'pre-auth',
    payment_option: paymentMethod, // Specify payment method
    // ... other fields
    hash: ''
  };
  
  formParams.hash = generatePurchaseHash(
    formParams,
    process.env.PAYWAY_API_KEY!
  );
  
  return formParams;
}
```

---

## Backend API Implementation

### Example 3: Express.js API Endpoint

```typescript
import express from 'express';
import { PayWayClient } from 'aba-payway-sdk';
import { 
  generatePurchaseHash,
  generateReqTime,
  generateTransactionId,
  encodeItems
} from 'aba-payway-sdk/utils';

const app = express();
app.use(express.json());

const client = new PayWayClient({
  merchantId: process.env.PAYWAY_MERCHANT_ID,
  apiKey: process.env.PAYWAY_API_KEY,
  rsaPublicKey: process.env.PAYWAY_RSA_PUBLIC_KEY,
  sandbox: true
});

// Create pre-auth
app.post('/api/preauth/create', async (req, res) => {
  try {
    const { amount, customer, items, bookingId } = req.body;
    
    const req_time = generateReqTime();
    const tran_id = `BOOKING-${bookingId}`;
    
    const formParams = {
      req_time,
      merchant_id: process.env.PAYWAY_MERCHANT_ID,
      tran_id,
      amount,
      currency: 'USD',
      type: 'pre-auth',
      firstname: customer.firstName,
      lastname: customer.lastName,
      email: customer.email,
      phone: customer.phone,
      items: encodeItems(items),
      return_url: Buffer.from(`${process.env.APP_URL}/booking/return`).toString('base64'),
      continue_success_url: `${process.env.APP_URL}/booking/confirmed/${bookingId}`,
      hash: ''
    };
    
    formParams.hash = generatePurchaseHash(formParams, process.env.PAYWAY_API_KEY);
    
    // Save to database
    await savePreAuthToDatabase({
      bookingId,
      tranId: tran_id,
      amount,
      status: 'PENDING',
      createdAt: new Date()
    });
    
    res.json({
      success: true,
      formAction: 'https://checkout-sandbox.payway.com.kh/api/payment-gateway/v1/payments/purchase',
      formParams,
      tranId: tran_id
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Complete pre-auth
app.post('/api/preauth/complete', async (req, res) => {
  try {
    const { tranId, amount, payout } = req.body;
    
    const result = await client.completePreAuth({
      tranId,
      completeAmount: amount,
      rsaPublicKey: process.env.PAYWAY_RSA_PUBLIC_KEY,
      payout: payout || undefined
    });
    
    if (result.status.code === '00') {
      // Update database
      await updatePreAuthStatus(tranId, 'COMPLETED', amount);
      
      res.json({
        success: true,
        status: result.transaction_status,
        amount: result.grand_total
      });
    } else {
      res.status(400).json({
        success: false,
        error: result.status.message
      });
    }
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Cancel pre-auth
app.post('/api/preauth/cancel', async (req, res) => {
  try {
    const { tranId } = req.body;
    
    const result = await client.cancelPreAuth({
      tranId,
      rsaPublicKey: process.env.PAYWAY_RSA_PUBLIC_KEY
    });
    
    if (result.status.code === '00') {
      await updatePreAuthStatus(tranId, 'CANCELLED');
      
      res.json({
        success: true,
        status: result.transaction_status
      });
    } else {
      res.status(400).json({
        success: false,
        error: result.status.message
      });
    }
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000);
```

---

## Frontend Form Submission

### Example 4: React Component

```tsx
import React, { useState } from 'react';

interface PreAuthFormProps {
  amount: number;
  customer: {
    firstName: string;
    lastName: string;
    email: string;
    phone: string;
  };
}

export function PreAuthCheckout({ amount, customer }: PreAuthFormProps) {
  const [loading, setLoading] = useState(false);
  
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    
    try {
      // Get form parameters from backend
      const response = await fetch('/api/preauth/create', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          amount,
          customer,
          items: [{
            name: 'Hotel Reservation',
            quantity: 1,
            price: amount
          }]
        })
      });
      
      const { formAction, formParams } = await response.json();
      
      // Create and submit form
      const form = document.createElement('form');
      form.method = 'POST';
      form.action = formAction;
      
      Object.entries(formParams).forEach(([key, value]) => {
        const input = document.createElement('input');
        input.type = 'hidden';
        input.name = key;
        input.value = String(value);
        form.appendChild(input);
      });
      
      document.body.appendChild(form);
      form.submit();
    } catch (error) {
      console.error('Pre-auth failed:', error);
      setLoading(false);
    }
  };
  
  return (
    <div>
      <h2>Reservation Payment</h2>
      <p>Amount to authorize: ${amount.toFixed(2)}</p>
      <p className="text-sm text-gray-600">
        💡 This will hold the funds, not charge immediately
      </p>
      <button
        onClick={handleSubmit}
        disabled={loading}
        className="btn btn-primary"
      >
        {loading ? 'Processing...' : 'Authorize Payment'}
      </button>
    </div>
  );
}
```

### Example 5: Vue.js Component

```vue
<template>
  <div class="pre-auth-checkout">
    <h2>Complete Your Reservation</h2>
    <div class="amount-display">
      <label>Authorization Amount:</label>
      <span>${{ amount.toFixed(2) }}</span>
    </div>
    <p class="info-text">
      💡 We'll hold this amount on your card. The final charge may differ.
    </p>
    <button 
      @click="submitPreAuth" 
      :disabled="loading"
      class="btn-submit"
    >
      {{ loading ? 'Processing...' : 'Authorize & Continue' }}
    </button>
  </div>
</template>

<script>
export default {
  props: {
    amount: Number,
    customer: Object
  },
  data() {
    return {
      loading: false
    };
  },
  methods: {
    async submitPreAuth() {
      this.loading = true;
      
      try {
        const response = await fetch('/api/preauth/create', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            amount: this.amount,
            customer: this.customer
          })
        });
        
        const { formAction, formParams } = await response.json();
        
        // Create form and submit
        const form = document.createElement('form');
        form.method = 'POST';
        form.action = formAction;
        
        for (const [key, value] of Object.entries(formParams)) {
          const input = document.createElement('input');
          input.type = 'hidden';
          input.name = key;
          input.value = value;
          form.appendChild(input);
        }
        
        document.body.appendChild(form);
        form.submit();
      } catch (error) {
        console.error('Error:', error);
        this.loading = false;
      }
    }
  }
};
</script>
```

---

## Complete Pre-Auth Examples

### Example 6: Hotel Checkout

```typescript
async function completeHotelCheckout(
  preAuthTranId: string,
  roomCharges: number,
  extras: { minibar: number; parking: number; spa: number }
) {
  const totalExtras = extras.minibar + extras.parking + extras.spa;
  const finalAmount = roomCharges + totalExtras;
  
  console.log('Completing hotel checkout:');
  console.log(`  Room: $${roomCharges}`);
  console.log(`  Minibar: $${extras.minibar}`);
  console.log(`  Parking: $${extras.parking}`);
  console.log(`  Spa: $${extras.spa}`);
  console.log(`  Total: $${finalAmount}`);
  
  const result = await client.completePreAuth({
    tranId: preAuthTranId,
    completeAmount: finalAmount,
    rsaPublicKey: process.env.PAYWAY_RSA_PUBLIC_KEY!
  });
  
  return result;
}

// Usage
await completeHotelCheckout('HOTEL-12345', 200.00, {
  minibar: 25.00,
  parking: 10.00,
  spa: 50.00
});
```

### Example 7: Car Rental Return

```typescript
interface CarRentalCharges {
  baseCost: number;
  mileageCharges: number;
  lateFee: number;
  damageCost: number;
  fuelCharge: number;
}

async function completeCarRental(
  preAuthTranId: string,
  charges: CarRentalCharges
) {
  const total = Object.values(charges).reduce((sum, val) => sum + val, 0);
  
  console.log('Car rental charges:');
  Object.entries(charges).forEach(([key, value]) => {
    if (value > 0) {
      console.log(`  ${key}: $${value.toFixed(2)}`);
    }
  });
  console.log(`  Total: $${total.toFixed(2)}`);
  
  return await client.completePreAuth({
    tranId: preAuthTranId,
    completeAmount: total,
    rsaPublicKey: process.env.PAYWAY_RSA_PUBLIC_KEY!
  });
}

// Usage
await completeCarRental('RENTAL-67890', {
  baseCost: 300.00,
  mileageCharges: 50.00,
  lateFee: 0,
  damageCost: 100.00,
  fuelCharge: 20.00
});
```

---

## Cancel Pre-Auth Examples

### Example 8: Booking Cancellation

```typescript
async function cancelBooking(bookingId: string, reason: string) {
  // Get pre-auth transaction ID from database
  const booking = await getBookingFromDatabase(bookingId);
  
  console.log(`Cancelling booking: ${bookingId}`);
  console.log(`Reason: ${reason}`);
  console.log(`Pre-auth amount: $${booking.amount}`);
  
  const result = await client.cancelPreAuth({
    tranId: booking.preAuthTranId,
    rsaPublicKey: process.env.PAYWAY_RSA_PUBLIC_KEY!
  });
  
  if (result.status.code === '00') {
    // Update database
    await updateBookingStatus(bookingId, 'CANCELLED', reason);
    
    // Send customer notification
    await sendCancellationEmail(booking.customerEmail, {
      bookingId,
      refundAmount: booking.amount,
      reason
    });
    
    console.log('✓ Booking cancelled, funds released');
  }
  
  return result;
}

// Usage
await cancelBooking('BK-12345', 'Customer requested cancellation');
```

---

## Use Case Examples

### Example 9: Variable Shipping Cost

```typescript
// Step 1: Create pre-auth with estimated total
async function createOrderPreAuth(order: Order) {
  const estimatedShipping = 20.00;
  const estimatedTotal = order.subtotal + estimatedShipping;
  
  const preAuthParams = generatePreAuthParams(estimatedTotal, order.customer);
  
  await saveOrderToDatabase({
    orderId: order.id,
    preAuthTranId: preAuthParams.tranId,
    estimatedTotal,
    status: 'PENDING_PAYMENT'
  });
  
  return preAuthParams;
}

// Step 2: Complete with actual shipping cost
async function completeOrderWithActualShipping(orderId: string) {
  const order = await getOrderFromDatabase(orderId);
  const actualShipping = await calculateActualShipping(order);
  const finalTotal = order.subtotal + actualShipping;
  
  console.log(`Order ${orderId}:`);
  console.log(`  Estimated shipping: $${order.estimatedShipping}`);
  console.log(`  Actual shipping: $${actualShipping}`);
  console.log(`  Final total: $${finalTotal}`);
  
  return await client.completePreAuth({
    tranId: order.preAuthTranId,
    completeAmount: finalTotal,
    rsaPublicKey: process.env.PAYWAY_RSA_PUBLIC_KEY!
  });
}
```

### Example 10: Gas Station Pre-Auth

```typescript
//Pre-auth for maximum fill amount
async function createGasPreAuth(pumpId: number, customerId: string) {
  const maxAmount = 100.00; // $100 max pre-auth
  
  const preAuthParams = generatePreAuthParams(maxAmount, {
    firstName: 'Customer',
    lastName: customerId,
    email: `${customerId}@gas.station`,
    phone: '000000000'
  });
  
  // Start pump
  await activatePump(pumpId, preAuthParams.tranId);
  
  return preAuthParams;
}

// Complete with actual amount pumped
async function completeGasPurchase(tranId: string, gallons: number, pricePerGallon: number) {
  const actualAmount = gallons * pricePerGallon;
  
  console.log(`Gas purchase:`);
  console.log(`  Gallons: ${gallons.toFixed(2)}`);
  console.log(`  Price/gallon: $${pricePerGallon.toFixed(2)}`);
  console.log(`  Total: $${actualAmount.toFixed(2)}`);
  
  return await client.completePreAuth({
    tranId,
    completeAmount: actualAmount,
    rsaPublicKey: process.env.PAYWAY_RSA_PUBLIC_KEY!
  });
}
```

---

## Error Handling

### Example 11: Comprehensive Error Handler

```typescript
async function safeCompletePreAuth(tranId: string, amount: number) {
  try {
    // Check status first
    const status = await client.getTransactionDetail({ tranId });
    
    if (status.tran_id_status !== 'PRE-AUTH') {
      throw new Error(
        `Cannot complete: Transaction is ${status.tran_id_status}`
      );
    }
    
    // Complete pre-auth
    const result = await client.completePreAuth({
      tranId,
      completeAmount: amount,
      rsaPublicKey: process.env.PAYWAY_RSA_PUBLIC_KEY!
    });
    
    if (result.status.code === '00') {
      return { success: true, result };
    } else {
      throw new Error(`Completion failed: ${result.status.message}`);
    }
  } catch (error: any) {
    console.error('Pre-auth completion error:', error.message);
    
    // Handle specific errors
    if (error.message.includes('expired')) {
      await notifyExpiredPreAuth(tranId);
    } else if (error.message.includes('CANCELLED')) {
      await handleCancelledPreAuth(tranId);
    } else if (error.message.includes('COMPLETED')) {
      console.log('Pre-auth already completed');
    }
    
    return { success: false, error: error.message };
  }
}
```

---

## Best Practices

1. **Always store transaction IDs**: Save pre-auth `tran_id` immediately
2. **Check status before actions**: Verify status before completing/cancelling
3. **Handle 30-day expiration**: Set reminders, don't wait until last day
4. **Communicate clearly**: Tell customers it's a hold, not a charge
5. **Log all operations**: Track create, complete, cancel for auditing
6. **Handle failures gracefully**: Retry logic for transient errors

---

For more information, see:
- [Main Skill Documentation](./SKILL.md)
- [Complete Pre-Auth](../aba-payway-pre-auth-complete/SKILL.md)
- [Cancel Pre-Auth](../aba-payway-pre-auth-cancel/SKILL.md)
