Enhance Blockonomics payment integration by adding required fields and improving transaction handling

This commit is contained in:
cnohall 2025-05-09 20:11:18 +09:00
parent dce8d798b3
commit d080f6db11
5 changed files with 65 additions and 31 deletions

View File

@ -124,6 +124,7 @@ class Blockonomics implements LivewireMethodInterface
return render('gateways.blockonomics.pay', $data); return render('gateways.blockonomics.pay', $data);
} }
public function paymentResponse(PaymentResponseRequest $request) public function paymentResponse(PaymentResponseRequest $request)
{ {
$request->validate([ $request->validate([
@ -132,20 +133,49 @@ class Blockonomics implements LivewireMethodInterface
'currency' => ['required'], 'currency' => ['required'],
'txid' => ['required'], 'txid' => ['required'],
'payment_method_id' => ['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 { try {
$data = []; $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['amount'] = $fiat_amount;
$data['currency'] = $request->currency;
$data['payment_method_id'] = $request->payment_method_id; $data['payment_method_id'] = $request->payment_method_id;
$data['payment_type'] = PaymentType::CRYPTO; $data['payment_type'] = PaymentType::CRYPTO;
$data['gateway_type_id'] = GatewayType::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 = $this->blockonomics->createPayment($data, $statusId);
$payment->custom_value1 = $request->btc_address;
$payment->save();
SystemLogger::dispatch( SystemLogger::dispatch(
['response' => $payment, 'data' => $data], ['response' => $payment, 'data' => $data],

View File

@ -107,17 +107,15 @@ class BlockonomicsPaymentDriver extends BaseDriver
$addr = $request->addr; $addr = $request->addr;
$payment = Payment::query() $payment = Payment::query()
->where('company_id', $company->id) ->where('company_id', $company->id)
->where('transaction_reference', $txid) ->where('transaction_reference', $txid)
->firstOrFail(); ->firstOrFail();
if (!$payment) { // Already completed payment, no need to update status
if ($payment->status_id == Payment::STATUS_COMPLETED) {
return response()->json([], 200); 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) { switch ($status) {
case 0: case 0:
$statusId = Payment::STATUS_PENDING; $statusId = Payment::STATUS_PENDING;
@ -128,16 +126,16 @@ class BlockonomicsPaymentDriver extends BaseDriver
case 2: case 2:
$statusId = Payment::STATUS_COMPLETED; $statusId = Payment::STATUS_COMPLETED;
break; break;
default:
$statusId = Payment::STATUS_PENDING;
} }
if ($payment->status_id == $statusId) { if ($payment->status_id !== $statusId) {
return response()->json([], 200);
} else {
$payment->status_id = $statusId; $payment->status_id = $statusId;
$payment->save(); $payment->save();
return response()->json([], 200);
} }
return response()->json([], 200);
} }
@ -203,7 +201,7 @@ class BlockonomicsPaymentDriver extends BaseDriver
} }
return 'ok'; 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 public function auth(): string

View File

@ -161,14 +161,18 @@ class Blockonomics {
ws.onmessage = function (event) { ws.onmessage = function (event) {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
console.log('Payment status:', data.status); const { status, txid, value } = data || {};
const isPaymentUnconfirmed = data.status === 0; console.log('Payment status:', status);
const isPaymentPartiallyConfirmed = data.status === 1; const isPaymentUnconfirmed = status === 0;
const isPaymentConfirmed = data.status === 2; const isPaymentPartiallyConfirmed = status === 1;
const isPaymentConfirmed = status === 2;
// Confirmation status: 0 = unconfirmed, 1 = partially confirmed, 2 = confirmed // Confirmation status: 0 = unconfirmed, 1 = partially confirmed, 2 = confirmed
// If any of the statuses are true, submit the form and redirect // If any of the statuses are true, submit the form and redirect
if (isPaymentUnconfirmed || isPaymentPartiallyConfirmed || isPaymentConfirmed) { 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(); document.getElementById('server-response').submit();
} }
} }

View File

@ -60,6 +60,7 @@
<input type="hidden" name="currency" value="{{ $currency }}"> <input type="hidden" name="currency" value="{{ $currency }}">
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}"> <input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
<input type="hidden" name="txid" value=""> <input type="hidden" name="txid" value="">
<input type="hidden" name="btc_address" value="{{ $btc_address }}" />
</form> </form>

View File

@ -1,5 +1,4 @@
<div class="rounded-lg border bg-card text-card-foreground shadow-sm overflow-hidden py-5 bg-white sm:gap-4" id="blockonomics-payment"> <div class="rounded-lg border bg-card text-card-foreground shadow-sm overflow-hidden py-5 bg-white sm:gap-4" id="blockonomics-payment">
<meta name="amount" content="{{ $amount }}" /> <meta name="amount" content="{{ $amount }}" />
<meta name="btc_amount" content="{{ $btc_amount }}" /> <meta name="btc_amount" content="{{ $btc_amount }}" />
<meta name="btc_address" content="{{ $btc_address }}" /> <meta name="btc_address" content="{{ $btc_address }}" />
@ -58,6 +57,8 @@
<input type="hidden" name="amount" value="{{ $amount }}"> <input type="hidden" name="amount" value="{{ $amount }}">
<input type="hidden" name="btc_price" value="{{ $btc_price }}"> <input type="hidden" name="btc_price" value="{{ $btc_price }}">
<input type="hidden" name="btc_amount" value="{{ $btc_amount }}"> <input type="hidden" name="btc_amount" value="{{ $btc_amount }}">
<input type="hidden" name="btc_address" value="{{ $btc_address }}">
<input type="hidden" name="status" value="">
<input type="hidden" name="currency" value="{{ $currency }}"> <input type="hidden" name="currency" value="{{ $currency }}">
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}"> <input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
<input type="hidden" name="txid" value=""> <input type="hidden" name="txid" value="">