PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.14
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.14
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
← All changes | app/Services/Report/ReportHelper.php +103 -49 6.2.46.2.14 View file →
@@ -1239,76 +1239,130 @@
1239 1239
1240 1240 return ['dates' => $dates, 'labels' => $labels];
1241 1241 }
1242 1242
1243 - public static function getPaymentsByType($startDate, $endDate, $type, $formId = 0)
1243 + /**
1244 + * All payment figures in ONE transaction scan, keyed 'onetime' / 'subscription'
1245 + * / 'all' (disabled module → each empty []). 'all' counts every transaction type
1246 + * with no filter, preserving getPaymentsByType()'s legacy no-type-filter contract.
1247 + * Each block keeps getPaymentsByType()'s shape — blended per-status totals for the
1248 + * admin consumer — plus a by_currency split for callers that must not blend
1249 + * currencies (MCP). One scan so consumers needing both types don't pay for two.
1250 + */
1251 + public static function getPaymentBreakdown($startDate, $endDate, $formId = 0)
1244 1252 {
1245 1253 $paymentSettings = get_option('__fluentform_payment_module_settings');
1246 1254 if (!$paymentSettings || !Arr::isTrue($paymentSettings, 'status')) {
1247 - return []; // Return empty if payment module is disabled
1255 + return ['onetime' => [], 'subscription' => [], 'all' => []];
1248 1256 }
1249 1257 list($startDate, $endDate) = self::processDateRange($startDate, $endDate);
1250 -
1251 - // Base query for transactions
1258 +
1252 1259 $query = \FluentForm\App\Models\Transaction::whereBetween('created_at', [$startDate, $endDate]);
1253 -
1254 - // Filter by transaction type if specified
1255 - if ($type === 'subscription') {
1256 - $query->whereIn('transaction_type', ['subscription', 'subscription_signup_fee']);
1257 - } elseif ($type === 'onetime') {
1258 - $query->where('transaction_type', 'onetime');
1259 - }
1260 -
1261 1260 self::scopeQueryToAllowedForms($query, $formId);
1262 -
1263 - // Get payments grouped by status
1264 - $payments = $query->select('status')
1261 + $payments = $query->select('transaction_type', 'status', 'currency')
1265 1262 ->selectRaw('SUM(payment_total) as total_amount')
1266 1263 ->selectRaw('COUNT(*) as count')
1267 - ->groupBy('status')
1264 + ->groupBy('transaction_type', 'status', 'currency')
1268 1265 ->get();
1269 -
1270 - // Get the total payment amount
1271 - $totalAmount = 0;
1266 +
1267 + $daysInRange = self::getDateDifference($startDate, $endDate);
1268 + $weeksInRange = max(1, round($daysInRange / 7, 1));
1269 + $currencySign = Arr::get(PaymentHelper::getCurrencyConfig($formId), 'currency_sign', '$');
1270 + $defaultCurrency = strtoupper((string) Arr::get(PaymentHelper::getCurrencyConfig($formId), 'currency', 'USD'));
1271 +
1272 + $blended = ['onetime' => [], 'subscription' => [], 'all' => []];
1273 + $perCurrency = ['onetime' => [], 'subscription' => [], 'all' => []];
1272 1274 foreach ($payments as $payment) {
1273 - $totalAmount += $payment->total_amount;
1275 + $status = strtolower((string) $payment->status);
1276 + $cents = (int) $payment->total_amount;
1277 + $count = (int) $payment->count;
1278 + $currency = strtoupper(trim((string) $payment->currency));
1279 + if ('' === $currency) {
1280 + $currency = $defaultCurrency;
1281 + }
1282 +
1283 + self::addPaymentRow($blended['all'], $perCurrency['all'], $status, $currency, $cents, $count);
1284 +
1285 + if ('onetime' === $payment->transaction_type) {
1286 + $type = 'onetime';
1287 + } elseif (in_array($payment->transaction_type, ['subscription', 'subscription_signup_fee'], true)) {
1288 + $type = 'subscription';
1289 + } else {
1290 + continue;
1291 + }
1292 + self::addPaymentRow($blended[$type], $perCurrency[$type], $status, $currency, $cents, $count);
1274 1293 }
1275 -
1276 - $formattedData = [];
1277 - foreach ($payments as $payment) {
1278 - $status = strtolower($payment->status);
1279 - $amount = $payment->total_amount / 100; // Convert from cents to dollars
1280 - $percentage = $totalAmount > 0 ? round(($payment->total_amount / $totalAmount) * 100, 2) : 0;
1281 -
1282 - $formattedData[$status] = [
1283 - 'amount' => $amount,
1284 - 'percentage' => $percentage,
1285 - 'count' => $payment->count
1286 - ];
1294 +
1295 + $out = [];
1296 + foreach (['onetime', 'subscription', 'all'] as $type) {
1297 + $byCurrency = [];
1298 + foreach ($perCurrency[$type] as $currency => $statuses) {
1299 + $symbol = html_entity_decode(PaymentHelper::getCurrencySymbol($currency), ENT_QUOTES);
1300 + $byCurrency[$currency] = self::formatPaymentStatuses($statuses, $weeksInRange, $symbol);
1301 + }
1302 + $block = self::formatPaymentStatuses($blended[$type], $weeksInRange, $currencySign);
1303 + $block['by_currency'] = $byCurrency;
1304 + $out[$type] = $block;
1287 1305 }
1288 -
1289 - // Calculate weekly average paid amount
1290 - $daysInRange = self::getDateDifference($startDate, $endDate);
1291 - $weeksInRange = max(1, round($daysInRange / 7, 1));
1292 -
1306 +
1307 + return $out;
1308 + }
1309 +
1310 + private static function addPaymentRow(array &$blended, array &$perCurrency, $status, $currency, $cents, $count)
1311 + {
1312 + if (!isset($blended[$status])) {
1313 + $blended[$status] = ['amount' => 0, 'count' => 0];
1314 + }
1315 + $blended[$status]['amount'] += $cents;
1316 + $blended[$status]['count'] += $count;
1317 +
1318 + if (!isset($perCurrency[$currency][$status])) {
1319 + $perCurrency[$currency][$status] = ['amount' => 0, 'count' => 0];
1320 + }
1321 + $perCurrency[$currency][$status]['amount'] += $cents;
1322 + $perCurrency[$currency][$status]['count'] += $count;
1323 + }
1324 +
1325 + public static function getPaymentsByType($startDate, $endDate, $type, $formId = 0)
1326 + {
1327 + return Arr::get(self::getPaymentBreakdown($startDate, $endDate, $formId), $type, []);
1328 + }
1329 +
1330 + /**
1331 + * Shape a status => ['amount' => cents, 'count' => int] map into the payment
1332 + * block used by both the admin Reports payment overview and MCP: whole-unit
1333 + * amounts (cents ÷ 100), per-status share of the block total, integer counts,
1334 + * and the paid weekly average. One formatter so the two callers can never drift.
1335 + */
1336 + private static function formatPaymentStatuses(array $statuses, $weeksInRange, $currencySymbol)
1337 + {
1338 + $totalCents = 0;
1339 + foreach ($statuses as $bucket) {
1340 + $totalCents += $bucket['amount'];
1341 + }
1342 +
1343 + $formatted = [];
1293 1344 $paidAmount = 0;
1294 - foreach ($formattedData as $status => $data) {
1295 - if ($status === 'paid') {
1296 - $paidAmount = $data['amount'];
1297 - break;
1345 + foreach ($statuses as $status => $bucket) {
1346 + $amount = $bucket['amount'] / 100; // Convert from cents to dollars
1347 + $formatted[$status] = [
1348 + 'amount' => $amount,
1349 + 'percentage' => $totalCents > 0 ? round(($bucket['amount'] / $totalCents) * 100, 2) : 0,
1350 + 'count' => (int) $bucket['count'],
1351 + ];
1352 + if ('paid' === $status) {
1353 + $paidAmount = $amount;
1298 1354 }
1299 1355 }
1300 -
1301 - $weeklyAverage = $paidAmount / $weeksInRange;
1302 -
1356 +
1303 1357 return [
1304 - 'currency_symbol' => Arr::get(PaymentHelper::getCurrencyConfig($formId), 'currency_sign', '$'),
1305 - 'payment_statuses' => $formattedData,
1306 - 'total_amount' => $totalAmount / 100, // Convert from cents to dollars
1307 - 'weekly_average' => round($weeklyAverage, 2)
1358 + 'currency_symbol' => $currencySymbol,
1359 + 'payment_statuses' => $formatted,
1360 + 'total_amount' => $totalCents / 100, // Convert from cents to dollars
1361 + 'weekly_average' => round($paidAmount / $weeksInRange, 2),
1308 1362 ];
1309 1363 }
1310 -
1364 +
1311 1365 /**
1312 1366 * Format payment method name for display
1313 1367 */
1314 1368 protected static function formatPaymentMethodName($paymentMethod)