PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.15
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.15
6.2.15 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 All 197 releases
← All changes | app/Services/Report/ReportHelper.php +117 -49 6.2.2 → 6.2.15 View file →
@@ -75,8 +75,22 @@
75 75 foreach ($reports as $reportKey => $report) {
76 76 $reports[$reportKey]['label'] = $inputLabels[$reportKey];
77 77 $reports[$reportKey]['element'] = Arr::get($inputs, $reportKey, []);
78 78 $reports[$reportKey]['options'] = $formInputs[$reportKey]['options'];
79 +
80 + // Per-element override hook. Safe with no listener (default
81 + // payload is returned unchanged). Pro hooks the ranking
82 + // variant; third-party fields can extend the same pattern.
83 + $element = $reports[$reportKey]['element'];
84 + if (is_string($element) && $element !== '') {
85 + $reports[$reportKey] = apply_filters(
86 + 'fluentform/reports/format_field_' . $element,
87 + $reports[$reportKey],
88 + array_merge($formInputs[$reportKey], ['name' => $reportKey]),
89 + $form->id,
90 + $statuses
91 + );
92 + }
79 93 }
80 94
81 95 return [
82 96 'report_items' => $reports,
@@ -1225,76 +1239,130 @@
1225 1239
1226 1240 return ['dates' => $dates, 'labels' => $labels];
1227 1241 }
1228 1242
1229 - 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)
1230 1252 {
1231 1253 $paymentSettings = get_option('__fluentform_payment_module_settings');
1232 1254 if (!$paymentSettings || !Arr::isTrue($paymentSettings, 'status')) {
1233 - return []; // Return empty if payment module is disabled
1255 + return ['onetime' => [], 'subscription' => [], 'all' => []];
1234 1256 }
1235 1257 list($startDate, $endDate) = self::processDateRange($startDate, $endDate);
1236 -
1237 - // Base query for transactions
1258 +
1238 1259 $query = \FluentForm\App\Models\Transaction::whereBetween('created_at', [$startDate, $endDate]);
1239 -
1240 - // Filter by transaction type if specified
1241 - if ($type === 'subscription') {
1242 - $query->whereIn('transaction_type', ['subscription', 'subscription_signup_fee']);
1243 - } elseif ($type === 'onetime') {
1244 - $query->where('transaction_type', 'onetime');
1245 - }
1246 -
1247 1260 self::scopeQueryToAllowedForms($query, $formId);
1248 -
1249 - // Get payments grouped by status
1250 - $payments = $query->select('status')
1261 + $payments = $query->select('transaction_type', 'status', 'currency')
1251 1262 ->selectRaw('SUM(payment_total) as total_amount')
1252 1263 ->selectRaw('COUNT(*) as count')
1253 - ->groupBy('status')
1264 + ->groupBy('transaction_type', 'status', 'currency')
1254 1265 ->get();
1255 -
1256 - // Get the total payment amount
1257 - $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' => []];
1258 1274 foreach ($payments as $payment) {
1259 - $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);
1260 1293 }
1261 -
1262 - $formattedData = [];
1263 - foreach ($payments as $payment) {
1264 - $status = strtolower($payment->status);
1265 - $amount = $payment->total_amount / 100; // Convert from cents to dollars
1266 - $percentage = $totalAmount > 0 ? round(($payment->total_amount / $totalAmount) * 100, 2) : 0;
1267 -
1268 - $formattedData[$status] = [
1269 - 'amount' => $amount,
1270 - 'percentage' => $percentage,
1271 - 'count' => $payment->count
1272 - ];
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;
1273 1305 }
1274 -
1275 - // Calculate weekly average paid amount
1276 - $daysInRange = self::getDateDifference($startDate, $endDate);
1277 - $weeksInRange = max(1, round($daysInRange / 7, 1));
1278 -
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 = [];
1279 1344 $paidAmount = 0;
1280 - foreach ($formattedData as $status => $data) {
1281 - if ($status === 'paid') {
1282 - $paidAmount = $data['amount'];
1283 - 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;
1284 1354 }
1285 1355 }
1286 -
1287 - $weeklyAverage = $paidAmount / $weeksInRange;
1288 -
1356 +
1289 1357 return [
1290 - 'currency_symbol' => Arr::get(PaymentHelper::getCurrencyConfig($formId), 'currency_sign', '$'),
1291 - 'payment_statuses' => $formattedData,
1292 - 'total_amount' => $totalAmount / 100, // Convert from cents to dollars
1293 - '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),
1294 1362 ];
1295 1363 }
1296 -
1364 +
1297 1365 /**
1298 1366 * Format payment method name for display
1299 1367 */
1300 1368 protected static function formatPaymentMethodName($paymentMethod)