07-26-2023, 06:39 PM
So I've been trying to figure this out for a while now but haven't been able to fix it. My payment processor is Clover, which there isn't a pre-built WHMCS gateway for. So I am attempting to make my own but I'm doing something wrong but I can't figure out what it is that I'm doing wrong. I will say that I am new to this.
I created a `clovergateway.php` file in the `modules/gateways` directory and a `clovergateway.php` file in the `modules/gateways/callbacks` directory.
Here's the code from the `clovergateway.php` file in the `modules/gateways` directory:
<?php
if (!defined("WHMCS")) {
die("This file cannot be accessed directly");
}
function clovergateway_MetaData()
{
return [
'DisplayName' => 'Clover Gateway',
'APIVersion' => '1.0',
'DisableLocalCredtCardInput' => true,
'TokenisedStorage' => true,
];
}
function clovergateway_config()
{
return [
'FriendlyName' => [
'Type' => 'System',
'Value' => 'Clover Gateway',
],
'apiKey' => [
'FriendlyName' => 'API Key',
'Type' => 'text',
'Size' => '25',
'Default' => '',
'Description' => 'Enter your Clover API Key here.',
],
'merchantId' => [
'FriendlyName' => 'Merchant ID',
'Type' => 'text',
'Size' => '25',
'Default' => '',
'Description' => 'Enter your Clover Merchant ID here.',
],
'publicKey' => [
'FriendlyName' => 'Public Key',
'Type' => 'text',
'Size' => '25',
'Default' => '',
'Description' => 'Enter your Clover Public Key here.',
],
];
}
function clovergateway_remoteinput($params)
{
$tokenForm = <<<HTML
<form id="paymentfrm" method="post" action="{$params['systemurl']}/creditcard.php">
<input type="hidden" name="invoiceid" value="{$params['invoiceid']}" />
<input type="hidden" name="gatewayid" value="{$params['gatewayid']}" />
<label for="cardNumber">Card Number</label>
<input type="text" id="cardNumber" />
<label for="cardExpiryMonth">Expiry Month</label>
<input type="text" id="cardExpiryMonth" />
<label for="cardExpiryYear">Expiry Year</label>
<input type="text" id="cardExpiryYear" />
<label for="cardCVV">CVV</label>
<input type="text" id="cardCVV" />
<button type="button" id="submitButton">Submit</button>
</form>
<script src="https://checkout.clover.com/sdk.js"></script>
<script>
// Replace with your public key
const publicKey = "{$params['publicKey']}";
const clover = new Clover(publicKey);
const elements = clover.elements();
document.getElementById('submitButton').addEventListener('click', function() {
clover.createToken({
cardNumber: document.getElementById('cardNumber').value,
expMonth: document.getElementById('cardExpiryMonth').value,
expYear: document.getElementById('cardExpiryYear').value,
cvv: document.getElementById('cardCVV').value
}).then(function(response) {
document.getElementById('gatewayid').value = response.token;
document.getElementById('paymentfrm').submit();
}).catch(function(error) {
// Handle the error
alert(error.message);
});
});
</script>
HTML;
return $tokenForm;
}
function clovergateway_storeremote($params)
{
// Store the remote token and return success
return [
'success' => true,
'gatewayid' => $params['card_token'],
];
}
function clovergateway_capture($params)
{
// Fetch the API Key, Merchant ID, and other required parameters
$apiKey = $params['apiKey'];
$merchantId = $params['merchantId'];
$cloverApiUrl = "https://api.clover.com"; // Replace with the appropriate API URL
// Fetch the card details and invoice amount
$token = $params['gatewayid'];
$amount = $params['amount'];
// Set the required headers for Clover API requests
$headers = [
"Content-Type: application/json",
"Authorization: Bearer {$apiKey}"
];
// Create the charge
$url = "{$cloverApiUrl}/v1/merchant/{$merchantId}/charges";
$method = "POST";
$data = [
'token' => $token,
'amount' => $amount * 100 // Convert to cents
];
$response = cloverApiRequest($url, $method, $headers, $data);
// Check if the charge was successful
if (isset($response['id'])) {
return [
'status' => 'success',
'transid' => $response['id'],
'rawdata' => $response,
];
} else {
return [
'status' => 'error',
'rawdata' => $response,
];
}
}
function cloverApiRequest($url, $method, $headers, $data)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
if (curl_errno($ch)) {
throw new Exception('Curl error: ' . curl_error($ch));
}
curl_close($ch);
return json_decode($response, true);
}
Here's the code from the `clovergateway.php` file in the `modules/gateways/callbacks` directory:
<?php
use WHMCS\Database\Capsule;
require '../../../init.php';
require '../../../includes/gatewayfunctions.php';
require '../../../includes/invoicefunctions.php';
$gatewayModuleName = basename(__FILE__, '.php');
$gatewayParams = getGatewayVariables($gatewayModuleName);
if (!$gatewayParams['type']) {
die('Module not activated');
}
$invoiceId = $_POST['invoiceid'];
$gatewayId = $_POST['gatewayid'];
$invoiceData = Capsule::table('tblinvoices')
->where('id', $invoiceId)
->first();
$userId = $invoiceData->userid;
$success = checkCbInvoiceID($invoiceId, $gatewayParams['name']);
if ($success) {
$result = Capsule::table('tblclients')
->where('id', $userId)
->update([
'gatewayid' => $gatewayId,
]);
header('Location: ' . $gatewayParams['systemurl'] . '/clientarea.php?action=invoices');
} else {
header('Location: ' . $gatewayParams['systemurl'] . '/clientarea.php?action=invoices&status=error');
}
I was able to activate and configure the module with no issue but when I went to try testing it on the client side by trying to pay an invoice using it, that's when the issues began. When you click the "Pay Now" button on the invoice page, you are taken to another page where you are prompted to enter the payment info but on that page, there is a weird embed of the page underneath the payment form. The payment form doesn't work either. Pressing the submit button doesn't do anything.
I have attached a screenshot
[![screenshot of payment page][2]][2]
Here's a link to the [Clover Docs][3]
Any assistance would be greatly appreciated
[1]:
[3]:
I created a `clovergateway.php` file in the `modules/gateways` directory and a `clovergateway.php` file in the `modules/gateways/callbacks` directory.
Here's the code from the `clovergateway.php` file in the `modules/gateways` directory:
<?php
if (!defined("WHMCS")) {
die("This file cannot be accessed directly");
}
function clovergateway_MetaData()
{
return [
'DisplayName' => 'Clover Gateway',
'APIVersion' => '1.0',
'DisableLocalCredtCardInput' => true,
'TokenisedStorage' => true,
];
}
function clovergateway_config()
{
return [
'FriendlyName' => [
'Type' => 'System',
'Value' => 'Clover Gateway',
],
'apiKey' => [
'FriendlyName' => 'API Key',
'Type' => 'text',
'Size' => '25',
'Default' => '',
'Description' => 'Enter your Clover API Key here.',
],
'merchantId' => [
'FriendlyName' => 'Merchant ID',
'Type' => 'text',
'Size' => '25',
'Default' => '',
'Description' => 'Enter your Clover Merchant ID here.',
],
'publicKey' => [
'FriendlyName' => 'Public Key',
'Type' => 'text',
'Size' => '25',
'Default' => '',
'Description' => 'Enter your Clover Public Key here.',
],
];
}
function clovergateway_remoteinput($params)
{
$tokenForm = <<<HTML
<form id="paymentfrm" method="post" action="{$params['systemurl']}/creditcard.php">
<input type="hidden" name="invoiceid" value="{$params['invoiceid']}" />
<input type="hidden" name="gatewayid" value="{$params['gatewayid']}" />
<label for="cardNumber">Card Number</label>
<input type="text" id="cardNumber" />
<label for="cardExpiryMonth">Expiry Month</label>
<input type="text" id="cardExpiryMonth" />
<label for="cardExpiryYear">Expiry Year</label>
<input type="text" id="cardExpiryYear" />
<label for="cardCVV">CVV</label>
<input type="text" id="cardCVV" />
<button type="button" id="submitButton">Submit</button>
</form>
<script src="https://checkout.clover.com/sdk.js"></script>
<script>
// Replace with your public key
const publicKey = "{$params['publicKey']}";
const clover = new Clover(publicKey);
const elements = clover.elements();
document.getElementById('submitButton').addEventListener('click', function() {
clover.createToken({
cardNumber: document.getElementById('cardNumber').value,
expMonth: document.getElementById('cardExpiryMonth').value,
expYear: document.getElementById('cardExpiryYear').value,
cvv: document.getElementById('cardCVV').value
}).then(function(response) {
document.getElementById('gatewayid').value = response.token;
document.getElementById('paymentfrm').submit();
}).catch(function(error) {
// Handle the error
alert(error.message);
});
});
</script>
HTML;
return $tokenForm;
}
function clovergateway_storeremote($params)
{
// Store the remote token and return success
return [
'success' => true,
'gatewayid' => $params['card_token'],
];
}
function clovergateway_capture($params)
{
// Fetch the API Key, Merchant ID, and other required parameters
$apiKey = $params['apiKey'];
$merchantId = $params['merchantId'];
$cloverApiUrl = "https://api.clover.com"; // Replace with the appropriate API URL
// Fetch the card details and invoice amount
$token = $params['gatewayid'];
$amount = $params['amount'];
// Set the required headers for Clover API requests
$headers = [
"Content-Type: application/json",
"Authorization: Bearer {$apiKey}"
];
// Create the charge
$url = "{$cloverApiUrl}/v1/merchant/{$merchantId}/charges";
$method = "POST";
$data = [
'token' => $token,
'amount' => $amount * 100 // Convert to cents
];
$response = cloverApiRequest($url, $method, $headers, $data);
// Check if the charge was successful
if (isset($response['id'])) {
return [
'status' => 'success',
'transid' => $response['id'],
'rawdata' => $response,
];
} else {
return [
'status' => 'error',
'rawdata' => $response,
];
}
}
function cloverApiRequest($url, $method, $headers, $data)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
if (curl_errno($ch)) {
throw new Exception('Curl error: ' . curl_error($ch));
}
curl_close($ch);
return json_decode($response, true);
}
Here's the code from the `clovergateway.php` file in the `modules/gateways/callbacks` directory:
<?php
use WHMCS\Database\Capsule;
require '../../../init.php';
require '../../../includes/gatewayfunctions.php';
require '../../../includes/invoicefunctions.php';
$gatewayModuleName = basename(__FILE__, '.php');
$gatewayParams = getGatewayVariables($gatewayModuleName);
if (!$gatewayParams['type']) {
die('Module not activated');
}
$invoiceId = $_POST['invoiceid'];
$gatewayId = $_POST['gatewayid'];
$invoiceData = Capsule::table('tblinvoices')
->where('id', $invoiceId)
->first();
$userId = $invoiceData->userid;
$success = checkCbInvoiceID($invoiceId, $gatewayParams['name']);
if ($success) {
$result = Capsule::table('tblclients')
->where('id', $userId)
->update([
'gatewayid' => $gatewayId,
]);
header('Location: ' . $gatewayParams['systemurl'] . '/clientarea.php?action=invoices');
} else {
header('Location: ' . $gatewayParams['systemurl'] . '/clientarea.php?action=invoices&status=error');
}
I was able to activate and configure the module with no issue but when I went to try testing it on the client side by trying to pay an invoice using it, that's when the issues began. When you click the "Pay Now" button on the invoice page, you are taken to another page where you are prompted to enter the payment info but on that page, there is a weird embed of the page underneath the payment form. The payment form doesn't work either. Pressing the submit button doesn't do anything.
I have attached a screenshot
[![screenshot of payment page][2]][2]
Here's a link to the [Clover Docs][3]
Any assistance would be greatly appreciated
[1]:
[To see links please register here]
[2]:[3]:
[To see links please register here]