234 lines
5.8 KiB
PHP
234 lines
5.8 KiB
PHP
<?php
|
|
|
|
//https://manjapro.net/paymentlink/post/winpay_report.php?action=transactions&from=2026-06-01&to=2026-06-5
|
|
//https://manjapro.net/paymentlink/post/winpay_report.php?action=balance&accountNo=1747356
|
|
//https://manjapro.net/paymentlink/post/winpay_report.php?winpay_report.php?action=statement&accountNo=XXX&token=XXX
|
|
|
|
require __DIR__ . '/../../config/connect.php';
|
|
|
|
$partnerId = "bb3736e5-eb14-4e7f-b62d-10db909db794";
|
|
$baseUrl = "https://snap.winpay.id";
|
|
$privateKeyPath = __DIR__ . "/private_key_prod.pem";
|
|
|
|
// =========================
|
|
// HELPER
|
|
// =========================
|
|
function getTimestamp()
|
|
{
|
|
return date("c");
|
|
}
|
|
|
|
// 🔥 FORMAT ISO8601 AMAN
|
|
function formatISO8601($date, $end = false)
|
|
{
|
|
$time = $end ? "23:59:59" : "00:00:00";
|
|
return date("Y-m-d\\T{$time}P", strtotime($date));
|
|
}
|
|
|
|
// 🔥 VALIDASI RANGE MAX 1 BULAN
|
|
function validateRange($from, $to)
|
|
{
|
|
$start = strtotime($from);
|
|
$end = strtotime($to);
|
|
|
|
if (($end - $start) > (31 * 24 * 60 * 60)) {
|
|
die(json_encode([
|
|
"error" => "Range maksimal 1 bulan"
|
|
], JSON_PRETTY_PRINT));
|
|
}
|
|
}
|
|
|
|
function generateSignature($method, $endpoint, $body, $timestamp, $privateKeyPath, &$debug = [])
|
|
{
|
|
$hashedBody = strtolower(bin2hex(hash('sha256', $body, true)));
|
|
|
|
$stringToSign = implode(":", [
|
|
$method,
|
|
$endpoint,
|
|
$hashedBody,
|
|
$timestamp
|
|
]);
|
|
|
|
$privateKey = openssl_pkey_get_private(file_get_contents($privateKeyPath));
|
|
|
|
if (!$privateKey) {
|
|
die(json_encode(["error" => "Private key tidak valid"]));
|
|
}
|
|
|
|
openssl_sign($stringToSign, $signature, $privateKey, OPENSSL_ALGO_SHA256);
|
|
|
|
$signatureBase64 = base64_encode($signature);
|
|
|
|
// DEBUG
|
|
$debug['string_to_sign'] = $stringToSign;
|
|
$debug['hashed_body'] = $hashedBody;
|
|
$debug['signature'] = $signatureBase64;
|
|
|
|
return $signatureBase64;
|
|
}
|
|
|
|
// 🔥 CURL DETAIL
|
|
function curlPost($url, $headers, $body)
|
|
{
|
|
$ch = curl_init();
|
|
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_URL => $url,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => $body,
|
|
CURLOPT_HTTPHEADER => $headers,
|
|
CURLOPT_HEADER => true
|
|
]);
|
|
|
|
$response = curl_exec($ch);
|
|
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
|
|
|
$responseHeader = substr($response, 0, $headerSize);
|
|
$responseBody = substr($response, $headerSize);
|
|
|
|
$error = curl_error($ch);
|
|
|
|
curl_close($ch);
|
|
|
|
return [
|
|
"http_code" => $httpCode,
|
|
"header" => $responseHeader,
|
|
"body" => $responseBody,
|
|
"error" => $error
|
|
];
|
|
}
|
|
|
|
function hitWinpay($method, $endpoint, $body, $baseUrl, $partnerId, $privateKeyPath)
|
|
{
|
|
$timestamp = getTimestamp();
|
|
$externalId = time() . rand(1000, 9999);
|
|
|
|
$jsonBody = json_encode($body, JSON_UNESCAPED_SLASHES);
|
|
|
|
$signature = generateSignature(
|
|
$method,
|
|
$endpoint,
|
|
$jsonBody,
|
|
$timestamp,
|
|
$privateKeyPath
|
|
);
|
|
|
|
$headers = [
|
|
"Content-Type: application/json",
|
|
"X-TIMESTAMP: $timestamp",
|
|
"X-SIGNATURE: $signature",
|
|
"X-PARTNER-ID: $partnerId",
|
|
"X-EXTERNAL-ID: $externalId",
|
|
"CHANNEL-ID: WEB"
|
|
];
|
|
|
|
$res = curlPost($baseUrl . $endpoint, $headers, $jsonBody);
|
|
|
|
// 🔥 kalau curl error
|
|
if (!empty($res['error'])) {
|
|
return json_encode([
|
|
"status" => false,
|
|
"error" => $res['error']
|
|
]);
|
|
}
|
|
|
|
// 🔥 return PURE response dari Winpay
|
|
return $res['body'];
|
|
}
|
|
|
|
// =========================
|
|
// ROUTER
|
|
// =========================
|
|
$action = $_GET['action'] ?? '';
|
|
|
|
// =========================
|
|
// BALANCE
|
|
// =========================
|
|
if ($action === 'balance') {
|
|
|
|
$accountNo = $_GET['accountNo'] ?? '';
|
|
|
|
$body = [
|
|
"partnerReferenceNo" => uniqid(),
|
|
"accountNo" => $accountNo,
|
|
"balanceTypes" => ["Transaction", "Settlement"]
|
|
];
|
|
|
|
echo hitWinpay("POST", "/v1.0/balance-inquiry", $body, $baseUrl, $partnerId, $privateKeyPath);
|
|
exit;
|
|
}
|
|
|
|
// =========================
|
|
// TRANSACTIONS
|
|
// =========================
|
|
if ($action === 'transactions') {
|
|
|
|
$fromRaw = $_GET['from'] ?? date('Y-m-01');
|
|
$toRaw = $_GET['to'] ?? date('Y-m-d');
|
|
|
|
$from = formatISO8601($fromRaw);
|
|
$to = formatISO8601($toRaw, true);
|
|
|
|
validateRange($from, $to);
|
|
|
|
$page = $_GET['page'] ?? 1;
|
|
$limit = $_GET['limit'] ?? 100;
|
|
|
|
$body = [
|
|
"partnerReferenceNo" => "REF" . time(),
|
|
"fromDateTime" => $from,
|
|
"toDateTime" => $to,
|
|
"pageSize" => (int)$limit,
|
|
"pageNumber" => (int)$page
|
|
];
|
|
|
|
echo hitWinpay("POST", "/v1.0/transaction-history-list", $body, $baseUrl, $partnerId, $privateKeyPath);
|
|
exit;
|
|
}
|
|
|
|
// =========================
|
|
// STATEMENT
|
|
// =========================
|
|
if ($action === 'statement') {
|
|
|
|
$accountNo = $_GET['accountNo'] ?? '';
|
|
$token = $_GET['token'] ?? '';
|
|
|
|
$fromRaw = $_GET['from'] ?? date('Y-m-01');
|
|
$toRaw = $_GET['to'] ?? date('Y-m-d');
|
|
|
|
$from = formatISO8601($fromRaw);
|
|
$to = formatISO8601($toRaw, true);
|
|
|
|
validateRange($from, $to);
|
|
|
|
$page = $_GET['page'] ?? 1;
|
|
$limit = $_GET['limit'] ?? 10;
|
|
|
|
$body = [
|
|
"partnerReferenceNo" => "REF" . time(),
|
|
"bankCardToken" => $token,
|
|
"accountNo" => $accountNo,
|
|
"fromDateTime" => $from,
|
|
"toDateTime" => $to,
|
|
"additionalInfo" => [
|
|
"pageSize" => (string)$limit,
|
|
"pageNumber" => (string)$page
|
|
]
|
|
];
|
|
|
|
echo hitWinpay("POST", "/v1.0/bank-statement", $body, $baseUrl, $partnerId, $privateKeyPath);
|
|
exit;
|
|
}
|
|
|
|
// =========================
|
|
// DEFAULT
|
|
// =========================
|
|
echo json_encode([
|
|
"status" => false,
|
|
"message" => "Invalid action",
|
|
"available" => ["balance","transactions","statement"]
|
|
], JSON_PRETTY_PRINT); |