1

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

Here's a link to the Clover Docs

Any assistance would be greatly appreciated

  • This is likely to be closed or migrated as it is a programming question rather than running a website. But...what does the module log tell you about what happens when you try to submit? – Steve May 07 '23 at 23:36

0 Answers0