# Simaya Midtrans Payment Server

Backend Express.js server untuk integrasi pembayaran Midtrans dengan sistem ERP.

## 📋 Daftar Isi

- [Fitur Utama](#fitur-utama)
- [Konfigurasi Environment](#konfigurasi-environment)
- [API Endpoints](#api-endpoints)
- [Payment Flow](#payment-flow)
- [Testing](#testing)
- [Logging](#logging)

## 🚀 Fitur Utama

### 1. **Dual Mode Payment**
- **CORE API**: Bank Transfer, Credit Card, GoPay/QRIS, Convenience Store
- **SNAP**: Hosted payment interface dengan UI Midtrans

### 2. **Payment Link Generation**
- Generate secure payment link dengan signature validation
- Configurable TTL (Time To Live)
- Token-based authentication

### 3. **ERP Integration**
- Notifikasi otomatis ke sistem ERP setelah pembayaran sukses
- Multi-endpoint support (comma-separated URLs)
- Signature verification untuk keamanan

### 4. **Webhook Handler**
- Unified webhook untuk CORE dan SNAP
- Signature verification
- Idempotent notification handling

### 5. **Advanced Logging**
- Level-based logging (debug, info, warn, error)
- In-memory log buffer
- Payload masking untuk sensitive data
- Jakarta timezone (WIB/UTC+7)

## ⚙️ Konfigurasi Environment

### Midtrans Configuration
```env
# Required
MIDTRANS_SERVER_KEY=your-server-key
MIDTRANS_CLIENT_KEY=your-client-key
MIDTRANS_IS_PRODUCTION=false

# Payment Method Toggles
ENABLE_BANK_TRANSFER=true
ENABLE_CREDIT_CARD=true
ENABLE_GOPAY=true
ENABLE_CSTORE=true
```

### Payment Link Configuration
```env
# External API Access
EXTERNAL_API_KEY=your-api-key

# Payment Link Settings
PAYMENT_LINK_SECRET=your-secret-for-signing
PAYMENT_LINK_TTL_MINUTES=1440
PAYMENT_LINK_BASE=http://localhost:5174/pay
```

### ERP Integration
```env
# Single URL (legacy)
ERP_NOTIFICATION_URL=https://your-erp.com/api/payment-notification
ERP_CLIENT_SECRET=your-erp-client-secret

# Multi-URL (recommended)
ERP_NOTIFICATION_URLS=https://erp1.com/api/notif,https://erp2.com/api/notif

# Toggle
ERP_ENABLE_NOTIF=true
```

### Logging Configuration
```env
# Logging Level: debug, info, warn, error
LOG_LEVEL=info

# Expose /api/logs endpoint (dev only)
LOG_EXPOSE_API=true

# In-memory buffer size
LOG_BUFFER_SIZE=1000
```

### Server Configuration
```env
PORT=8000
NODE_ENV=development
```

## 📡 API Endpoints

### Health & Config

#### `GET /api/health`
Health check endpoint.

**Response:**
```json
{
  "ok": true,
  "env": {
    "isProduction": false,
    "hasServerKey": true,
    "hasClientKey": true
  }
}
```

#### `GET /api/config`
Get current payment configuration.

**Response:**
```json
{
  "paymentToggles": {
    "bank_transfer": true,
    "credit_card": true,
    "gopay": true,
    "cstore": true
  },
  "midtransEnv": "sandbox",
  "clientKey": "SB-Mid-client-xxx"
}
```

#### `POST /api/config` (Dev Only)
Update payment toggles at runtime.

**Request:**
```json
{
  "paymentToggles": {
    "bank_transfer": false
  }
}
```

### Payment Operations

#### `POST /api/payments/charge`
Create payment transaction via Midtrans Core API.

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

**Request Body:**
```json
{
  "payment_type": "bank_transfer",
  "transaction_details": {
    "order_id": "order-123",
    "gross_amount": 150000
  },
  "bank_transfer": {
    "bank": "bca"
  }
}
```

**Response:**
```json
{
  "status_code": "201",
  "status_message": "Success",
  "transaction_id": "xxx",
  "order_id": "order-123",
  "va_numbers": [
    {
      "bank": "bca",
      "va_number": "12345678901"
    }
  ]
}
```

#### `POST /api/payments/snap/token`
Generate Snap token for hosted payment.

**Request:**
```json
{
  "transaction_details": {
    "order_id": "order-123",
    "gross_amount": 150000
  },
  "customer_details": {
    "first_name": "John",
    "email": "john@example.com"
  }
}
```

**Response:**
```json
{
  "token": "snap-token-xxx"
}
```

#### `GET /api/payments/:orderId/status`
Check payment status.

**Response:**
```json
{
  "status_code": "200",
  "transaction_status": "settlement",
  "order_id": "order-123",
  "gross_amount": "150000.00"
}
```

### Payment Link

#### `POST /createtransaksi`
Generate payment link (external ERP endpoint).

**Headers:**
```
X-API-KEY: your-external-api-key
Content-Type: application/json
```

**Request:**
```json
{
  "mercant_id": "merchant-001",
  "nominal": 150000,
  "nama": "John Doe",
  "email": "john@example.com",
  "no_telepon": "081234567890",
  "item": [
    {
      "item_id": "product-123",
      "nama": "Product Name",
      "harga": 150000,
      "qty": 1
    }
  ],
  "allowed_methods": ["bank_transfer", "gopay"]
}
```

**Response:**
```json
{
  "status": "200",
  "messages": "SUCCESS",
  "data": {
    "url": "http://localhost:5174/pay/eyJ2Ijox..."
  }
}
```

#### `GET /api/payment-links/:token`
Resolve payment link token.

**Response:**
```json
{
  "order_id": "merchant-001:product-123",
  "nominal": 150000,
  "customer": {
    "name": "John Doe",
    "email": "john@example.com",
    "phone": "081234567890"
  },
  "expire_at": 1733280000000,
  "allowed_methods": ["bank_transfer", "gopay"]
}
```

### Webhook

#### `POST /api/payments/notification`
Midtrans webhook handler (unified for CORE & SNAP).

**Request (from Midtrans):**
```json
{
  "order_id": "order-123",
  "transaction_status": "settlement",
  "gross_amount": "150000.00",
  "signature_key": "xxx"
}
```

**Response:**
```json
{
  "ok": true
}
```

### Logging (Dev Only)

#### `GET /api/logs?limit=100&level=info&q=payment`
Get recent logs.

**Query Parameters:**
- `limit`: Max entries (1-1000, default: 100)
- `level`: Filter by level (debug|info|warn|error)
- `q`: Search keyword

**Response:**
```json
{
  "count": 50,
  "items": [
    {
      "ts": "2024-12-04T12:00:00.000+07:00",
      "level": "info",
      "msg": "charge.request",
      "meta": {
        "id": "abc123",
        "payment_type": "bank_transfer"
      }
    }
  ]
}
```

### Testing (Dev Only)

#### `POST /api/echo`
Echo endpoint untuk testing ERP notification.

#### `POST /api/test/notify-erp`
Manual trigger ERP notification.

**Request:**
```json
{
  "orderId": "order-123",
  "nominal": "150000",
  "mercant_id": "merchant-001"
}
```

## 🔄 Payment Flow

### 1. Payment Link Creation Flow
```
ERP System → POST /createtransaksi → Server generates token → Payment URL
```

### 2. Payment Execution Flow
```
Customer → Payment URL → Frontend resolves token → 
Choose method → POST /api/payments/charge or SNAP → Midtrans
```

### 3. Payment Completion Flow
```
Midtrans → Webhook → Verify signature → Update ledger → 
Notify ERP → Mark order complete
```

### 4. ERP Notification Format
```json
{
  "mercant_id": "merchant-001",
  "status_code": "200",
  "nominal": "150000",
  "signature": "sha512-hash"
}
```

**Signature Calculation:**
```
SHA512(mercant_id + status_code + nominal + ERP_CLIENT_SECRET)
```

## 🧪 Testing

Lihat folder `tests/` untuk file-file testing:

```bash
# Test create payment link
node tests/test-create-payment-link.cjs

# Test frontend payload
node tests/test-frontend-payload.cjs

# Test snap token
node tests/test-snap-token.cjs
```

Lihat `tests/README.md` untuk detail lengkap.

## 📝 Logging

### Log Levels
- **debug**: Detailed information, typically of interest only when diagnosing problems
- **info**: General informational messages
- **warn**: Warning messages for potentially harmful situations
- **error**: Error events that might still allow the application to continue running

### Log Format
```
[2024-12-04T12:00:00.000+07:00] [info] charge.request {"id": "abc123", "payment_type": "bank_transfer"}
```

### Important Log Events

#### Payment Lifecycle
- `charge.request`: Payment charge initiated
- `charge.success`: Charge successful
- `charge.error`: Charge failed
- `status.request`: Status check requested
- `webhook.received`: Webhook notification received

#### ERP Integration
- `erp.notify.start`: ERP notification started
- `erp.notify.success`: ERP notified successfully
- `erp.notify.error`: ERP notification failed
- `erp.notify.skip`: Notification skipped (already sent or disabled)

#### Security
- `webhook.signature.invalid`: Invalid webhook signature
- `createtransaksi.unauthorized`: Unauthorized API key

## 🔒 Security Features

1. **Signature Verification**
   - Webhook signature validation
   - Payment link token signing
   - ERP notification signing

2. **Idempotency**
   - Prevent duplicate order creation
   - Prevent duplicate ERP notifications
   - Block re-charge for pending orders

3. **API Key Authentication**
   - External API key for `/createtransaksi`
   - Dev mode fallback for easier local testing

4. **Payload Masking**
   - Sensitive fields masked in logs
   - Card numbers, CVV, tokens automatically hidden

## 🚀 Running the Server

```bash
# Install dependencies
npm install

# Start server
node server/index.cjs

# Server runs on http://localhost:8000
```

## 📚 Related Documentation

- [Tests README](../tests/README.md) - Testing documentation
- [Temp Files README](../temp/README.md) - Temporary files info
- [Frontend README](../README.md) - Main project README

## 🐛 Common Issues

### Issue: "Transaction already pending"
**Cause**: Order ID already has pending transaction in Midtrans
**Solution**: Use existing payment instructions or create new order with different ID

### Issue: "ERP notification failed"
**Cause**: ERP endpoint unreachable or signature mismatch
**Solution**: Check `ERP_NOTIFICATION_URLS` and `ERP_CLIENT_SECRET` configuration

### Issue: "Invalid signature on webhook"
**Cause**: Incorrect server key or webhook from unauthorized source
**Solution**: Verify `MIDTRANS_SERVER_KEY` matches your Midtrans account

## 📞 Support

Untuk bantuan lebih lanjut, hubungi tim development atau lihat dokumentasi Midtrans:
- [Midtrans API Documentation](https://docs.midtrans.com/)
- [Midtrans Node.js Library](https://github.com/Midtrans/midtrans-nodejs-client)
