Type casting causing 1 pence difference
Replicate:
- Create a contribution page with an amount 161.70
- Submit the form and create a mandate
Expected results
- Contribution recur amount in Civi = 161.70
- Subscription amount in GC = 161.70
Actual result:
- Contribution recur amount in Civi = 161.70
- Subscription amount in GC = 161.69
The reason for failure is because of type casting
Ref: https://stackoverflow.com/a/13104146/4286907
eg:
pradeep@Pradpnayak Documents % php -r '$a=161.70; $b = (100.00 * $a); var_dump($b);'
float(16169.999999999998)
Solution:
diff --git a/CRM/GoCardlessUtils.php b/CRM/GoCardlessUtils.php
index 3cfbdca..7b04338 100644
--- a/CRM/GoCardlessUtils.php
+++ b/CRM/GoCardlessUtils.php
@@ -134,6 +134,20 @@ class CRM_GoCardlessUtils {
return $redirect_flow;
}
+ /**
+ * Get the amount for the GC API formatted in lowest (ie. cents / pennies).
+ *
+ * @param float $amount
+ *
+ * @return int
+ */
+ public static function getAmount($amount): int {
+ $amount = number_format((float) $amount ?? 0.0, CRM_Utils_Money::getCurrencyPrecision(), '.', '');
+ // Stripe amount required in cents.
+ $amount = preg_replace('/[^\d]/', '', strval($amount));
+ return (int) $amount;
+ }
+
/**
* Complete a GoCardless redirect flow, set up subscription from details given.
*
@@ -213,7 +227,7 @@ class CRM_GoCardlessUtils {
$metadata = json_encode(array_intersect_key($deets, array_flip(['contactID', 'contributionRecurID'])));
$params = [
// Convert amount to pennies.
- 'amount' => (int) (100 * $deets['amount']),
+ 'amount' => self::getAmount($deets['amount']),
'currency' => 'GBP',
'name' => $deets['description'],
'interval' => $interval,
Edited by Pradeep Nayak