From f63dd0c7e266064f80b0d17b130fd390d9aaec91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zieli=C5=84ski?= Date: Tue, 26 Aug 2025 11:16:43 +0200 Subject: [PATCH] PaymentStates fix --- modules/EcmPaymentStates/summaryNew.php | 468 +++++++++++------------- 1 file changed, 223 insertions(+), 245 deletions(-) diff --git a/modules/EcmPaymentStates/summaryNew.php b/modules/EcmPaymentStates/summaryNew.php index aa81f9d0..f14abbac 100644 --- a/modules/EcmPaymentStates/summaryNew.php +++ b/modules/EcmPaymentStates/summaryNew.php @@ -18,22 +18,20 @@ $db->query('FLUSH QUERY CACHE'); // Initialize variables with defaults $account_type = ''; $saldo_type = ''; -$and = ''; -$type = ''; $data = array(); $sum = array(); $idToPdf = ''; if (!empty($_REQUEST['submit'])) { // Sanitize and validate inputs - $account_type = isset($_REQUEST['account_type']) ? $db->quote($_REQUEST['account_type']) : ''; + $account_type = isset($_REQUEST['account_type']) ? trim($_REQUEST['account_type']) : ''; if ($account_type == 'a') { $account_type = ''; } - $saldo_type = isset($_REQUEST['saldo_type']) ? $db->quote($_REQUEST['saldo_type']) : ''; - $type2 = isset($_REQUEST['type2']) ? $db->quote($_REQUEST['type2']) : ''; - $user_id = isset($_REQUEST['user_id']) ? $db->quote($_REQUEST['user_id']) : ''; + $saldo_type = isset($_REQUEST['saldo_type']) ? trim($_REQUEST['saldo_type']) : ''; + $type2 = isset($_REQUEST['type2']) ? $db->quote(trim($_REQUEST['type2'])) : ''; + $user_id = isset($_REQUEST['user_id']) ? $db->quote(trim($_REQUEST['user_id'])) : ''; // Build WHERE conditions safely $conditions = array("t.deleted='0'"); @@ -43,7 +41,7 @@ if (!empty($_REQUEST['submit'])) { } if (!empty($type2)) { - $conditions[] = "account_type2='" . $type2 . "'"; + $conditions[] = "a.account_type2='" . $type2 . "'"; } if (!empty($user_id)) { @@ -53,7 +51,7 @@ if (!empty($_REQUEST['submit'])) { // Build account type condition $account_condition = ''; if ($account_type != '') { - $account_condition = " AND (a.account_type='rs' OR a.account_type = '" . $account_type . "')"; + $account_condition = " AND (a.account_type='rs' OR a.account_type = '" . $db->quote($account_type) . "')"; } // Optimized query - get all needed data in one go @@ -69,16 +67,33 @@ if (!empty($_REQUEST['submit'])) { ORDER BY a.index_dbf"; $clients = $db->query($query); + $client_ids = array(); + $clients_data = array(); + + // First pass - collect all client IDs and data + while ($c = $db->fetchByAssoc($clients)) { + if (!empty($c['parent_id'])) { + $client_ids[] = $c['parent_id']; + $clients_data[] = $c; + } + } + + // Get all financial data in one batch + $financial_batch = getAllFinancialData($client_ids); // Cache currency objects to avoid repeated database calls $currency_cache = array(); - while ($c = $db->fetchByAssoc($clients)) { - // Skip invalid accounts - if (empty($c['parent_id'])) continue; + foreach ($clients_data as $c) { + $parent_id = $c['parent_id']; + + // Skip if no financial data + if (!isset($financial_batch[$parent_id])) { + continue; + } $row = array(); - $row['id'] = $c['parent_id']; + $row['id'] = $parent_id; $row['name'] = $c['account_name']; $row['index'] = $c['index_dbf']; @@ -91,16 +106,17 @@ if (!empty($_REQUEST['submit'])) { } $row['currency_id'] = $currency_cache[$currency_id]; - // Get financial data (these functions need optimization too) - $row['unsettled'] = getData($c['parent_id'], 0); - $row['not_overdue'] = getData($c['parent_id'], 7); - $row['overdue'] = getData($c['parent_id'], 1); - $row['2'] = getData2($c['parent_id'], 2); - $row['3'] = getData2($c['parent_id'], 3); - $row['4'] = getData2($c['parent_id'], 4); - $row['5'] = getData2($c['parent_id'], 5); - $row['6'] = getData2($c['parent_id'], 6); - $row['saldo'] = getData($c['parent_id'], 8); + // Use pre-calculated financial data + $fin_data = $financial_batch[$parent_id]; + $row['unsettled'] = $fin_data['unsettled']; + $row['not_overdue'] = $fin_data['not_overdue']; + $row['overdue'] = $fin_data['overdue']; + $row['2'] = $fin_data['2']; + $row['3'] = $fin_data['3']; + $row['4'] = $fin_data['4']; + $row['5'] = $fin_data['5']; + $row['6'] = $fin_data['6']; + $row['saldo'] = $fin_data['saldo']; $row['today_saldo'] = 0; // Apply saldo filters @@ -143,12 +159,15 @@ if (!empty($_REQUEST['submit'])) { } } -// Get user list with single query +// Get user list with single optimized query $user_list = array(); -$users_query = "SELECT id, first_name, last_name FROM users WHERE deleted=0"; +$users_query = "SELECT id, CONCAT(COALESCE(first_name, ''), ' ', COALESCE(last_name, '')) as full_name + FROM users + WHERE deleted=0 + ORDER BY first_name, last_name"; $users_result = $db->query($users_query); while ($user_data = $db->fetchByAssoc($users_result)) { - $user_list[$user_data['id']] = trim($user_data['first_name'] . ' ' . $user_data['last_name']); + $user_list[$user_data['id']] = trim($user_data['full_name']); } // Initialize Smarty template @@ -158,7 +177,7 @@ global $mod_strings, $app_list_strings; $ss->assign("MOD", $mod_strings); $ss->assign("DATA", $data); $ss->assign("SUM", $sum); -$ss->assign("SORT", array()); // Initialize empty sort array +$ss->assign("SORT", array()); $ss->assign("account_type", $account_type); $app_list_strings['account_type_dom']['a'] = 'Wszystkie'; @@ -173,245 +192,177 @@ $ss->assign("users", $user_list); echo $ss->display('modules/EcmPaymentStates/tpls/summary1.tpl'); -// OPTIMIZED HELPER FUNCTIONS -function getData($id, $expired) { - static $cache = array(); - $cache_key = $id . '_' . $expired; +// OPTIMIZED CORE FUNCTION - Gets all financial data in one query +function getAllFinancialData($client_ids) { + static $global_cache = null; - if (isset($cache[$cache_key])) { - return $cache[$cache_key]; + if ($global_cache !== null && !empty($global_cache)) { + return $global_cache; + } + + if (empty($client_ids)) { + return array(); } $db = $GLOBALS['db']; $today = date('Y-m-d'); + $ids_string = "'" . implode("','", array_unique($client_ids)) . "'"; - $settled_condition = "t.settled!='1' AND"; - $date_condition = "1=1"; - $is_saldo = false; - - switch ($expired) { - case 0: - $date_condition = "1=1"; - break; - case 1: - $date_condition = "t.payment_date <= '$today'"; - $is_saldo = true; - break; - case 7: - $date_condition = "t.payment_date >= '$today'"; - break; - case 8: - case 9: - $date_condition = "t.payment_date <= '$today'"; - $settled_condition = "1=1 AND"; - $is_saldo = true; - break; - default: - return getData2($id, $expired); - } - - // Get type 1 transactions (MA) - $query_ma = " - SELECT SUM(t.value) AS sum - FROM ecmtransactions AS t - WHERE t.parent_id = '$id' - AND t.deleted='0' - AND $settled_condition - t.type='1' - AND $date_condition + // Single comprehensive query for all financial calculations + $comprehensive_query = " + SELECT + t.parent_id, + t.type, + t.settled, + t.value, + t.payment_date, + COALESCE(settled_data.settled_amount, 0) as settled_amount + FROM ecmtransactions t + LEFT JOIN ( + SELECT + parent_trans.id as transaction_id, + SUM( + CASE + WHEN parent_trans.type = '0' AND rel_trans.type = '0' AND parent_trans.value < 0 AND r.value < 0 + THEN ABS(r.value) + WHEN parent_trans.type = '0' + THEN r.value + ELSE ABS(r.value) + END + ) as settled_amount + FROM ecmtransactions parent_trans + LEFT JOIN ecmtransactions_rel r ON (r.ecmtransaction_a_id = parent_trans.id OR r.ecmtransaction_b_id = parent_trans.id) + LEFT JOIN ecmtransactions rel_trans ON ( + rel_trans.id = CASE + WHEN r.ecmtransaction_a_id = parent_trans.id THEN r.ecmtransaction_b_id + ELSE r.ecmtransaction_a_id + END + AND rel_trans.deleted = '0' + ) + WHERE parent_trans.parent_id IN ($ids_string) + AND parent_trans.deleted = '0' + GROUP BY parent_trans.id + ) settled_data ON settled_data.transaction_id = t.id + WHERE t.parent_id IN ($ids_string) + AND t.deleted = '0' + ORDER BY t.parent_id, t.payment_date "; - $result_ma = $db->query($query_ma); - $ma_sum = 0; - if ($row = $db->fetchByAssoc($result_ma)) { - $ma_sum = floatval($row['sum']); + $result = $db->query($comprehensive_query); + $financial_data = array(); + + while ($row = $db->fetchByAssoc($result)) { + $parent_id = $row['parent_id']; + $type = $row['type']; + $settled = $row['settled']; + $value = floatval($row['value']); + $settled_amount = floatval($row['settled_amount']); + $payment_date = $row['payment_date']; + + if (!isset($financial_data[$parent_id])) { + $financial_data[$parent_id] = array( + 'unsettled' => 0, + 'not_overdue' => 0, + 'overdue' => 0, + '2' => 0, '3' => 0, '4' => 0, '5' => 0, '6' => 0, + 'saldo' => 0 + ); + } + + // Calculate effective value based on settlement + $effective_value = ($settled == '1') ? $value : ($value - $settled_amount); + + // Determine date category + $days_diff = (strtotime($today) - strtotime($payment_date)) / (60 * 60 * 24); + + // Apply business logic based on type and date + if ($type == '1') { // MA (receivable) + $financial_data[$parent_id]['saldo'] += $effective_value; + if ($days_diff < 0) { // Future date + $financial_data[$parent_id]['not_overdue'] += $effective_value; + } + if ($settled != '1') { + $financial_data[$parent_id]['unsettled'] += $effective_value; + } + } else { // WINIEN (payable) + $financial_data[$parent_id]['saldo'] -= $effective_value; + if ($days_diff >= 0 && $settled != '1') { // Past due and not settled + $financial_data[$parent_id]['overdue'] += $effective_value; + } + if ($settled != '1') { + $financial_data[$parent_id]['unsettled'] += $effective_value; + } + } + + // Categorize by aging periods (only for non-settled) + if ($settled != '1') { + if ($days_diff >= 1 && $days_diff <= 30) { + $financial_data[$parent_id]['2'] += $effective_value; + } elseif ($days_diff >= 31 && $days_diff <= 60) { + $financial_data[$parent_id]['3'] += $effective_value; + } elseif ($days_diff >= 61 && $days_diff <= 90) { + $financial_data[$parent_id]['4'] += $effective_value; + } elseif ($days_diff >= 91 && $days_diff <= 180) { + $financial_data[$parent_id]['5'] += $effective_value; + } elseif ($days_diff > 180) { + $financial_data[$parent_id]['6'] += $effective_value; + } + } } - if (!$is_saldo) { - $cache[$cache_key] = $ma_sum; - return $ma_sum; - } - - // Get type 0 transactions (WINIEN) for saldo calculation - $query_winien = " - SELECT SUM(t.value) AS sum - FROM ecmtransactions AS t - WHERE t.parent_id = '$id' - AND t.deleted='0' - AND $settled_condition - t.type='0' - AND $date_condition - "; - - $result_winien = $db->query($query_winien); - $winien_sum = 0; - if ($row = $db->fetchByAssoc($result_winien)) { - $winien_sum = floatval($row['sum']); - } - - $result = $ma_sum - $winien_sum; - - // Special case for expired = 1 - if ($expired == 1 && $result > 0) { - $result = 0; - } - - $cache[$cache_key] = $result; - return $result; + $global_cache = $financial_data; + return $financial_data; } -function getData2($id, $expired, $dates = null) { - static $cache = array(); - $cache_key = $id . '_' . $expired . '_' . $dates; +// Legacy function wrappers for backward compatibility (now use cached data) +function getData($id, $expired) { + static $batch_data = null; - if (isset($cache[$cache_key])) { - return $cache[$cache_key]; + if ($batch_data === null) { + $batch_data = getAllFinancialData(array($id)); } - $db = $GLOBALS['db']; - - // Prepare date conditions based on expired type - $date_conditions = getDateConditions($expired, $dates); - if ($date_conditions === false) { + if (!isset($batch_data[$id])) { return 0; } - $settled_condition = ($expired == 9) ? "" : "t.settled!='1' AND"; - - // Get type 0 transactions (WINIEN) - $query_winien = " - SELECT SUM(t.value) AS sum - FROM ecmtransactions AS t - WHERE t.parent_id = '$id' - AND t.deleted='0' - AND $settled_condition - t.type='0' - $date_conditions - "; - - $result_winien = $db->query($query_winien); - $winien_sum = 0; - if ($row = $db->fetchByAssoc($result_winien)) { - $winien_sum = floatval($row['sum']); - } - - // Calculate settled amounts for type 0 - $settled_winien = 0; - $rel_query_winien = " - SELECT r.value - FROM ecmtransactions AS t - LEFT JOIN ecmtransactions_rel AS r ON (r.ecmtransaction_a_id=t.id OR r.ecmtransaction_b_id=t.id) - LEFT JOIN ecmtransactions AS t2 ON ( - t2.id = CASE - WHEN r.ecmtransaction_a_id = t.id THEN r.ecmtransaction_b_id - ELSE r.ecmtransaction_a_id - END - ) - WHERE t.parent_id = '$id' - AND t.deleted='0' - AND $settled_condition - t.type='0' - $date_conditions - AND t2.deleted='0' - "; - - if ($expired == 9 && $dates) { - $target_date = date('Y-m-d', strtotime($dates)); - $rel_query_winien .= " AND t2.payment_date <= '$target_date'"; - } - - $rel_result_winien = $db->query($rel_query_winien); - while ($rel_row = $db->fetchByAssoc($rel_result_winien)) { - $settled_winien += floatval($rel_row['value']); - } - - // Get type 1 transactions (MA) - $query_ma = " - SELECT SUM(t.value) AS sum - FROM ecmtransactions AS t - WHERE t.parent_id = '$id' - AND t.deleted='0' - AND $settled_condition - t.type='1' - $date_conditions - "; - - $result_ma = $db->query($query_ma); - $ma_sum = 0; - if ($row = $db->fetchByAssoc($result_ma)) { - $ma_sum = floatval($row['sum']); - } - - // Calculate settled amounts for type 1 - $settled_ma = 0; - $rel_query_ma = " - SELECT r.value - FROM ecmtransactions AS t - LEFT JOIN ecmtransactions_rel AS r ON (r.ecmtransaction_a_id=t.id OR r.ecmtransaction_b_id=t.id) - LEFT JOIN ecmtransactions AS t2 ON ( - t2.id = CASE - WHEN r.ecmtransaction_a_id = t.id THEN r.ecmtransaction_b_id - ELSE r.ecmtransaction_a_id - END - ) - WHERE t.parent_id = '$id' - AND t.deleted='0' - AND $settled_condition - t.type='1' - $date_conditions - AND t2.deleted='0' - "; - - if ($expired == 9 && $dates) { - $target_date = date('Y-m-d', strtotime($dates)); - $rel_query_ma .= " AND t2.payment_date <= '$target_date'"; - } - - $rel_result_ma = $db->query($rel_query_ma); - while ($rel_row = $db->fetchByAssoc($rel_result_ma)) { - $settled_ma += abs(floatval($rel_row['value'])); - } - - $result_value = $settled_ma - $winien_sum + $ma_sum - $settled_winien; - $cache[$cache_key] = $result_value; - - return $result_value; -} - -function getDateConditions($expired, $dates = null) { - $today = date('Y-m-d'); + $data = $batch_data[$id]; switch ($expired) { - case 1: - return "AND t.payment_date <= '$today'"; - case 2: - $date_from = date('Y-m-d', strtotime('-30 days')); - return "AND t.payment_date >= '$date_from' AND t.payment_date < '$today'"; - case 3: - $date_to = date('Y-m-d', strtotime('-31 days')); - $date_from = date('Y-m-d', strtotime('-60 days')); - return "AND t.payment_date >= '$date_from' AND t.payment_date <= '$date_to'"; - case 4: - $date_to = date('Y-m-d', strtotime('-61 days')); - $date_from = date('Y-m-d', strtotime('-90 days')); - return "AND t.payment_date >= '$date_from' AND t.payment_date <= '$date_to'"; - case 5: - $date_to = date('Y-m-d', strtotime('-91 days')); - $date_from = date('Y-m-d', strtotime('-180 days')); - return "AND t.payment_date >= '$date_from' AND t.payment_date <= '$date_to'"; - case 6: - $date = date('Y-m-d', strtotime('-181 days')); - return "AND t.payment_date <= '$date'"; - case 9: - $target_date = $dates ? date('Y-m-d', strtotime($dates)) : $today; - return "AND t.payment_date <= '$target_date'"; - default: - return "AND 1=1"; + case 0: return $data['unsettled']; // All unsettled + case 1: return $data['overdue']; // Overdue + case 7: return $data['not_overdue']; // Not overdue + case 8: + case 9: return $data['saldo']; // Saldo + default: return getData2($id, $expired); } } +function getData2($id, $expired, $dates = null) { + static $batch_data = null; + + if ($batch_data === null) { + $batch_data = getAllFinancialData(array($id)); + } + + if (!isset($batch_data[$id])) { + return 0; + } + + $data = $batch_data[$id]; + + switch ($expired) { + case 2: return $data['2']; // 1-30 days + case 3: return $data['3']; // 31-60 days + case 4: return $data['4']; // 61-90 days + case 5: return $data['5']; // 91-180 days + case 6: return $data['6']; // 180+ days + case 9: return $data['saldo']; // Saldo with date + default: return 0; + } +} -// Comparison functions (compatible with PHP 5.6) +// Comparison functions (PHP 5.6 compatible) function cmpUnsettled($a, $b) { if ($a['unsettled'] == $b['unsettled']) return 0; return ($a['unsettled'] < $b['unsettled']) ? -1 : 1; @@ -470,7 +421,34 @@ function cmpTodaySaldoDesc($a, $b) { return ($a['today_saldo'] < $b['today_saldo']) ? 1 : -1; } -// Legacy functions (marked for removal - currently unused) -function getSaldo($id) { /* Implementation removed - function appears unused */ } -function unsettledFormatValue($settled, $val) { /* Implementation removed - function appears unused */ } -function unsettledValue($settled, $val) { /* Implementation removed - function appears unused */ } \ No newline at end of file +// Helper function for date conditions (now unused but kept for compatibility) +function getDateConditions($expired, $dates = null) { + $today = date('Y-m-d'); + + switch ($expired) { + case 1: return "AND t.payment_date <= '$today'"; + case 2: + $date_from = date('Y-m-d', strtotime('-30 days')); + return "AND t.payment_date >= '$date_from' AND t.payment_date < '$today'"; + case 3: + $date_to = date('Y-m-d', strtotime('-31 days')); + $date_from = date('Y-m-d', strtotime('-60 days')); + return "AND t.payment_date >= '$date_from' AND t.payment_date <= '$date_to'"; + case 4: + $date_to = date('Y-m-d', strtotime('-61 days')); + $date_from = date('Y-m-d', strtotime('-90 days')); + return "AND t.payment_date >= '$date_from' AND t.payment_date <= '$date_to'"; + case 5: + $date_to = date('Y-m-d', strtotime('-91 days')); + $date_from = date('Y-m-d', strtotime('-180 days')); + return "AND t.payment_date >= '$date_from' AND t.payment_date <= '$date_to'"; + case 6: + $date = date('Y-m-d', strtotime('-181 days')); + return "AND t.payment_date <= '$date'"; + case 9: + $target_date = $dates ? date('Y-m-d', strtotime($dates)) : $today; + return "AND t.payment_date <= '$target_date'"; + default: + return "AND 1=1"; + } +} \ No newline at end of file