From d080f6db11ab726c34521d3b2dcfe6ee9372979c Mon Sep 17 00:00:00 2001 From: cnohall Date: Fri, 9 May 2025 20:11:18 +0900 Subject: [PATCH] Enhance Blockonomics payment integration by adding required fields and improving transaction handling --- .../Blockonomics/Blockonomics.php | 38 +++++++++++++++++-- .../BlockonomicsPaymentDriver.php | 24 ++++++------ resources/js/clients/payments/blockonomics.js | 14 ++++--- .../gateways/blockonomics/pay.blade.php | 7 ++-- .../blockonomics/pay_livewire.blade.php | 13 ++++--- 5 files changed, 65 insertions(+), 31 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 3c852b71b1..e7d37b3310 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -124,6 +124,7 @@ class Blockonomics implements LivewireMethodInterface return render('gateways.blockonomics.pay', $data); } + public function paymentResponse(PaymentResponseRequest $request) { $request->validate([ @@ -132,20 +133,49 @@ class Blockonomics implements LivewireMethodInterface 'currency' => ['required'], 'txid' => ['required'], 'payment_method_id' => ['required'], + 'btc_address' => ['required'], + 'btc_amount' => ['required'], + 'btc_price' => ['required'], + // Setting status to required will break the payment process + // because sometimes the status is returned as 0 which is falsy + // and the validation will fail. + // 'status' => ['required'], ]); try { $data = []; - $fiat_amount = round(($request->btc_price * $request->btc_amount), 2); + $fiat_amount = round(($request->btc_price * $request->btc_amount), 2) / 100000000; $data['amount'] = $fiat_amount; - $data['currency'] = $request->currency; $data['payment_method_id'] = $request->payment_method_id; $data['payment_type'] = PaymentType::CRYPTO; $data['gateway_type_id'] = GatewayType::CRYPTO; - $data['transaction_reference'] = $request->txid; + // Randomize the transaction reference if the txid is a test payment + // to avoid duplicate transaction references in the database. + // Otherwise the payment hashed_id will not be unique. + if ($request->txid == 'WarningThisIsAGeneratedTestPaymentAndNotARealBitcoinTransaction') { + $data['transaction_reference'] = $request->txid . bin2hex(random_bytes(16)); + } else { + $data['transaction_reference'] = $request->txid; + } + $statusId; + + switch ($request->status) { + case 0: + $statusId = Payment::STATUS_PENDING; + break; + case 1: + $statusId = Payment::STATUS_PENDING; + break; + case 2: + $statusId = Payment::STATUS_COMPLETED; + break; + default: + $statusId = Payment::STATUS_PENDING; + } - $statusId = Payment::STATUS_PENDING; $payment = $this->blockonomics->createPayment($data, $statusId); + $payment->custom_value1 = $request->btc_address; + $payment->save(); SystemLogger::dispatch( ['response' => $payment, 'data' => $data], diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index f815eb711d..2eec94114c 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -107,17 +107,15 @@ class BlockonomicsPaymentDriver extends BaseDriver $addr = $request->addr; $payment = Payment::query() - ->where('company_id', $company->id) - ->where('transaction_reference', $txid) - ->firstOrFail(); + ->where('company_id', $company->id) + ->where('transaction_reference', $txid) + ->firstOrFail(); - if (!$payment) { + // Already completed payment, no need to update status + if ($payment->status_id == Payment::STATUS_COMPLETED) { return response()->json([], 200); - // TODO: Implement logic to create new payment in case user sends payment to the address after closing the payment page } - $statusId = Payment::STATUS_PENDING; - switch ($status) { case 0: $statusId = Payment::STATUS_PENDING; @@ -128,16 +126,16 @@ class BlockonomicsPaymentDriver extends BaseDriver case 2: $statusId = Payment::STATUS_COMPLETED; break; + default: + $statusId = Payment::STATUS_PENDING; } - if ($payment->status_id == $statusId) { - return response()->json([], 200); - } else { + if ($payment->status_id !== $statusId) { $payment->status_id = $statusId; $payment->save(); - - return response()->json([], 200); } + return response()->json([], 200); + } @@ -203,7 +201,7 @@ class BlockonomicsPaymentDriver extends BaseDriver } return 'ok'; } - return "Copy your Invoice Ninja Webhook URL and set it as your callback URL in Blockonomics"; + return "No callback URL from your Blockonomics stores matches your Invoice Ninja webhook"; } public function auth(): string diff --git a/resources/js/clients/payments/blockonomics.js b/resources/js/clients/payments/blockonomics.js index 3d7b86ccfa..038b746b1e 100644 --- a/resources/js/clients/payments/blockonomics.js +++ b/resources/js/clients/payments/blockonomics.js @@ -161,14 +161,18 @@ class Blockonomics { ws.onmessage = function (event) { const data = JSON.parse(event.data); - console.log('Payment status:', data.status); - const isPaymentUnconfirmed = data.status === 0; - const isPaymentPartiallyConfirmed = data.status === 1; - const isPaymentConfirmed = data.status === 2; + const { status, txid, value } = data || {}; + console.log('Payment status:', status); + const isPaymentUnconfirmed = status === 0; + const isPaymentPartiallyConfirmed = status === 1; + const isPaymentConfirmed = status === 2; // Confirmation status: 0 = unconfirmed, 1 = partially confirmed, 2 = confirmed // If any of the statuses are true, submit the form and redirect if (isPaymentUnconfirmed || isPaymentPartiallyConfirmed || isPaymentConfirmed) { - document.querySelector('input[name="txid"]').value = data.txid || ''; + document.querySelector('input[name="txid"]').value = txid || ''; + document.querySelector('input[name="status"]').value = status || ''; + document.querySelector('input[name="btc_amount"]').value = value || ''; + document.querySelector('input[name="btc_address"]').value = btcAddress || ''; document.getElementById('server-response').submit(); } } diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index 2d5a1b8172..7613e0c8a4 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -60,6 +60,7 @@ + @@ -102,19 +103,19 @@ margin-bottom: 20px; display: flex; justify-content: space-between; - } + } .invoice-number { width: 50%; float: left; text-align: left; - } + } .invoice-amount { width: 50%; float: right; text-align: right; text-transform: uppercase; margin-bottom: 20px; - } + } .blockonomics-payment-wrapper { display: flex; justify-content: center; diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay_livewire.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay_livewire.blade.php index 0e03cec1e5..3126c75a26 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay_livewire.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay_livewire.blade.php @@ -1,5 +1,4 @@
- @@ -58,12 +57,14 @@ + + - +