# Contoh Implementasi PHP - Pembayaran Keluar (Payout)

Dokumentasi lengkap dengan contoh kode PHP untuk mengintegrasikan fitur pembayaran keluar (payout/disbursement).

## Class PaymentDisbursementAPI

```php
<?php
class PaymentDisbursementAPI {
    
    private $baseUrl = "https://pay-test.targeted.work/";
    private $memberId = "10036";
    private $secretKey = "150kz9esh1s2f793abb8l0e4mjot3r2c";
    
    /**
     * Generate MD5 Signature
     */
    public function generateSignature($data) {
        ksort($data);
        
        $stringSignTemp = "";
        foreach ($data as $key => $value) {
            if (!empty($value)) {
                $stringSignTemp .= $key . "=" . $value . "&";
            }
        }
        
        $stringSignTemp .= "key=" . $this->secretKey;
        return strtoupper(md5($stringSignTemp));
    }
    
    /**
     * Send Request via cURL
     */
    private function sendRequest($endpoint, $data) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->baseUrl . $endpoint);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        
        $response = curl_exec($ch);
        curl_close($ch);
        
        return $response;
    }
    
    /**
     * Validate Payment Data
     */
    public function validatePaymentData($params) {
        $errors = [];
        
        // Validate amount
        if (empty($params['amount']) || $params['amount'] < 10000 || $params['amount'] > 25000000) {
            $errors[] = "Amount harus antara Rp 10.000 - Rp 25.000.000";
        }
        
        // Validate account number
        if (empty($params['account']) || strlen($params['account']) < 9 || strlen($params['account']) > 18) {
            $errors[] = "Nomor rekening harus 9-18 digit";
        }
        
        // Validate name
        if (empty($params['name']) || strlen($params['name']) > 35) {
            $errors[] = "Nama penerima tidak valid (max 35 karakter)";
        }
        
        // Validate dstCode
        if (empty($params['dstCode'])) {
            $errors[] = "Kode bank/e-wallet harus dipilih";
        }
        
        return $errors;
    }
    
    /**
     * Create Disbursement (Payout)
     */
    public function createDisbursement($params) {
        // Validate input
        $errors = $this->validatePaymentData($params);
        if (!empty($errors)) {
            return ['status' => 'error', 'msg' => implode(", ", $errors)];
        }
        
        $data = [
            "memberId" => $this->memberId,
            "orderNo" => $params['orderNo'],
            "amount" => $params['amount'],
            "dstCode" => $params['dstCode'],
            "name" => $params['name'],
            "account" => $params['account']
        ];
        
        if (!empty($params['remark'])) {
            $data['remark'] = $params['remark'];
        }
        
        $data['sign'] = $this->generateSignature($data);
        
        $response = $this->sendRequest("payment_dfpay_add.html", $data);
        return json_decode($response, true);
    }
    
    /**
     * Query Disbursement Status
     */
    public function queryDisbursementStatus($orderNo) {
        $data = [
            "memberId" => $this->memberId,
            "orderNo" => $orderNo
        ];
        
        $data['sign'] = $this->generateSignature($data);
        
        $response = $this->sendRequest("payment_dfpay_query.html", $data);
        return json_decode($response, true);
    }
    
    /**
     * Check Merchant Balance
     */
    public function checkBalance() {
        $data = [
            "memberId" => $this->memberId
        ];
        
        $data['sign'] = $this->generateSignature($data);
        
        $response = $this->sendRequest("payment_dfpay_balance.html", $data);
        return json_decode($response, true);
    }
    
    /**
     * Verify Callback Signature
     */
    public function verifyCallbackSignature($callbackData) {
        $sign = $callbackData['sign'];
        unset($callbackData['sign']);
        
        $calculatedSign = $this->generateSignature($callbackData);
        return strtoupper($sign) === strtoupper($calculatedSign);
    }
    
    /**
     * Handle Callback
     */
    public function handleCallback($callbackData) {
        // Verify signature
        if (!$this->verifyCallbackSignature($callbackData)) {
            return ['status' => 'error', 'msg' => 'Invalid signature'];
        }
        
        $orderNo = $callbackData['orderNo'];
        $refCode = $callbackData['refCode'];
        
        // Update database
        if ($refCode == '1') {
            // Payout success
            updatePayoutStatus($orderNo, 'SUCCESS', $callbackData);
        } else {
            // Payout failed
            updatePayoutStatus($orderNo, 'FAILED', $callbackData);
        }
        
        return ['status' => 'success', 'msg' => 'Callback processed'];
    }
}
?>
```

## Contoh Penggunaan

### 1. Check Balance

```php
<?php
require 'PaymentDisbursementAPI.php';

$api = new PaymentDisbursementAPI();

$result = $api->checkBalance();

if ($result['status'] == 'success') {
    $balance = $result['data'];
    echo "Total Balance: Rp " . number_format($balance['balance']);
    echo "Frozen: Rp " . number_format($balance['frozen']);
    echo "Available: Rp " . number_format($balance['available']);
} else {
    echo "Error: " . $result['msg'];
}
?>
```

### 2. Create Payout to E-Wallet

```php
<?php
require 'PaymentDisbursementAPI.php';

$api = new PaymentDisbursementAPI();

// Check balance first
$balance = $api->checkBalance();
if ($balance['status'] == 'success' && $balance['data']['available'] < 50000) {
    echo "Saldo tidak cukup";
    exit;
}

// Create payout
$params = [
    'orderNo' => 'PAYOUT-' . time(),
    'amount' => 50000,
    'dstCode' => 'OVO',
    'name' => 'John Doe',
    'account' => '081234567890',
    'remark' => 'Refund order #123'
];

$result = $api->createDisbursement($params);

if ($result['status'] == 'success') {
    echo "Payout berhasil dibuat";
    echo "Order No: " . $result['data']['orderNo'];
    echo "Status: " . $result['data']['status'];
} else {
    echo "Error: " . $result['msg'];
    echo "Error Code: " . $result['errCode'];
}
?>
```

### 3. Create Payout to Bank

```php
<?php
require 'PaymentDisbursementAPI.php';

$api = new PaymentDisbursementAPI();

$params = [
    'orderNo' => 'PAYOUT-' . time(),
    'amount' => 100000,
    'dstCode' => 'PERMATA',
    'name' => 'Jane Smith',
    'account' => '1234567890123',
    'remark' => 'Payment for services'
];

$result = $api->createDisbursement($params);

if ($result['status'] == 'success') {
    echo "Payout berhasil dibuat";
    // Save to database
    savePayoutToDB($result['data']);
} else {
    echo "Error: " . $result['msg'];
}
?>
```

### 4. Query Payout Status

```php
<?php
require 'PaymentDisbursementAPI.php';

$api = new PaymentDisbursementAPI();

$orderNo = 'PAYOUT-123456';
$result = $api->queryDisbursementStatus($orderNo);

if ($result['status'] == 'success') {
    $payout = $result['data'];
    
    switch ($payout['status']) {
        case '0':
            echo "Payout sedang diproses (pending)";
            break;
        case '1':
            echo "Payout berhasil pada " . $payout['successTime'];
            echo "Dana sudah ke rekening " . $payout['account'];
            break;
        case '2':
            echo "Payout gagal";
            echo "Dana dikembalikan ke saldo merchant";
            break;
    }
} else {
    echo "Error: " . $result['msg'];
}
?>
```

### 5. Handle Callback

```php
<?php
// payout_callback.php
require 'PaymentDisbursementAPI.php';

$api = new PaymentDisbursementAPI();

// Receive callback data
$callbackData = $_POST;

// Verify and process
$result = $api->handleCallback($callbackData);

if ($result['status'] == 'success') {
    echo "OK";
} else {
    exit;
}
?>
```

## Helper Functions

```php
<?php
function savePayoutToDB($payoutData) {
    $mysqli = new mysqli("localhost", "user", "password", "database");
    
    $query = "INSERT INTO payouts (order_no, amount, dst_code, name, account, status, created_at) VALUES (?, ?, ?, ?, ?, ?, NOW())";
    $stmt = $mysqli->prepare($query);
    
    $status = '0'; // Pending
    $stmt->bind_param(
        "sissss",
        $payoutData['orderNo'],
        $payoutData['amount'],
        $payoutData['dstCode'],
        $payoutData['name'],
        $payoutData['account'],
        $status
    );
    
    return $stmt->execute();
}

function updatePayoutStatus($orderNo, $status, $data) {
    $mysqli = new mysqli("localhost", "user", "password", "database");
    
    $query = "UPDATE payouts SET status = ?, paid_time = ?, updated_at = NOW() WHERE order_no = ?";
    $stmt = $mysqli->prepare($query);
    
    $paidTime = $data['paidTime'] ?? date("Y-m-d H:i:s");
    $stmt->bind_param("sss", $status, $paidTime, $orderNo);
    
    return $stmt->execute();
}

function sendPayoutNotificationEmail($email, $payoutData, $status) {
    $subject = "Status Payout - " . $payoutData['orderNo'];
    
    if ($status == 'SUCCESS') {
        $message = "Payout berhasil!\n\n";
        $message .= "Order No: " . $payoutData['orderNo'] . "\n";
        $message .= "Amount: Rp " . number_format($payoutData['amount']) . "\n";
        $message .= "Tujuan: " . $payoutData['account'] . "\n";
        $message .= "Dana sudah sampai ke rekening tujuan.\n";
    } else {
        $message = "Payout gagal.\n\n";
        $message .= "Order No: " . $payoutData['orderNo'] . "\n";
        $message .= "Dana akan dikembalikan ke saldo merchant.\n";
    }
    
    mail($email, $subject, $message);
}
?>
```

---

**Catatan**: Selalu verifikasi saldo sebelum membuat payout untuk mencegah error saldo tidak cukup.
