FIX_LIB PARTNER FILE

This commit is contained in:
sanjeev.p 2026-04-08 16:48:29 +05:30
parent c3e035f0be
commit f1c074e1b5

View File

@ -4,24 +4,11 @@ namespace App\Libraries;
use CodeIgniter\Database\BaseConnection; use CodeIgniter\Database\BaseConnection;
/**
* Partner (agent) grid: same data as
* SELECT prr.retention_rate AS partner_RR, prr.vehicle_type_id, pvt.vehicle_type AS partner_VT
* FROM partner_retention_rate prr
* LEFT JOIN vehicle_type vt ON vt.id = prr.vehicle_type_id
* WHERE prr.agent_id = ? AND prr.is_active = 1
* Matched grid row (vehicle type aligns with that PRR row): partner_VT, partner_RR set from DB;
* comp/tp/od = partner_RR original (null/empty base 0); result 0 '-'.
* No matching PRR row for this grid vehicle type: partner_VT, partner_RR, comp, tp, od '-'.
*
* Manager/Accounts: applyManagerAccountsDisplayToRows() comp/tp/od null/empty/zero/negative '-', no math.
*/
class PartnerPayoutGridRetention class PartnerPayoutGridRetention
{ {
/** /**
* Active partner_retention_rate rows with joined vehicle_type (one query for maps + agent grid meta). * Fetch PRR rows with vehicle_type AND segment joined.
* * Now includes segment_id for per-segment RR matching.
* @return array<int, array<string, mixed>>
*/ */
private static function fetchPrrPvtRows(BaseConnection $db, int $agentId): array private static function fetchPrrPvtRows(BaseConnection $db, int $agentId): array
{ {
@ -30,8 +17,10 @@ class PartnerPayoutGridRetention
} }
return $db->table('partner_retention_rate prr') return $db->table('partner_retention_rate prr')
->select('prr.vehicle_type_id, prr.retention_rate, vt.vehicle_type') ->select('prr.vehicle_type_id, prr.segment_id, prr.retention_rate,
vt.vehicle_type, seg.segment')
->join('vehicle_type vt', 'vt.id = prr.vehicle_type_id', 'left') ->join('vehicle_type vt', 'vt.id = prr.vehicle_type_id', 'left')
->join('partner_segment seg', 'seg.id = prr.segment_id', 'left') // join segment table
->where('prr.agent_id', $agentId) ->where('prr.agent_id', $agentId)
->where('prr.is_active', 1) ->where('prr.is_active', 1)
->get() ->get()
@ -43,58 +32,79 @@ class PartnerPayoutGridRetention
if ($s === null || $s === '') { if ($s === null || $s === '') {
return ''; return '';
} }
return strtolower(trim(preg_replace('/\s+/u', ' ', $s)));
}
public static function normalizeSegmentLabel(?string $s): string
{
if ($s === null || $s === '') {
return '';
}
return strtolower(trim(preg_replace('/\s+/u', ' ', $s))); return strtolower(trim(preg_replace('/\s+/u', ' ', $s)));
} }
/** /**
* @param array<int, array<string, mixed>> $prrRows * Build meta map keyed by:
* * 1. "vt::{normalizedVehicleType}::seg::{normalizedSegment}" most specific
* @return array<string, array{partner_VT: string, partner_RR: float}> * 2. "vt::{normalizedVehicleType}" fallback (no segment)
* 3. "id::{vehicle_type_id}::seg::{segment_id}" by IDs
* 4. "id::{vehicle_type_id}" by VT id only
*/ */
private static function partnerMetaMapFromPrrRows(array $prrRows): array private static function partnerMetaMapFromPrrRows(array $prrRows): array
{ {
$meta = []; $meta = [];
foreach ($prrRows as $r) { foreach ($prrRows as $r) {
if (! array_key_exists('retention_rate', $r) || $r['retention_rate'] === null || $r['retention_rate'] === '') { if (!array_key_exists('retention_rate', $r)
|| $r['retention_rate'] === null
|| $r['retention_rate'] === '') {
continue; continue;
} }
$partnerRr = (float) $r['retention_rate']; $partnerRr = (float) $r['retention_rate'];
$vtRaw = isset($r['vehicle_type']) ? trim((string) $r['vehicle_type']) : ''; $vtRaw = isset($r['vehicle_type']) ? trim((string) $r['vehicle_type']) : '';
$segRaw = isset($r['segment']) ? trim((string) $r['segment']) : '';
$partnerVt = $vtRaw !== '' ? $vtRaw : 'N/A'; $partnerVt = $vtRaw !== '' ? $vtRaw : 'N/A';
$entry = [
$entry = [
'partner_VT' => $partnerVt, 'partner_VT' => $partnerVt,
'partner_RR' => $partnerRr, 'partner_RR' => $partnerRr,
]; ];
if ($vtRaw !== '') {
$meta[self::normalizeVehicleTypeLabel($vtRaw)] = $entry; $normVt = self::normalizeVehicleTypeLabel($vtRaw);
$normSeg = self::normalizeSegmentLabel($segRaw);
$vid = isset($r['vehicle_type_id']) ? (int) $r['vehicle_type_id'] : 0;
$sid = isset($r['segment_id']) ? (int) $r['segment_id'] : 0;
// Key 1: most specific — vt + segment (text)
if ($normVt !== '' && $normSeg !== '') {
$meta["vt::{$normVt}::seg::{$normSeg}"] = $entry;
} }
$vid = isset($r['vehicle_type_id']) ? (int) $r['vehicle_type_id'] : 0;
// Key 2: vt only (text fallback)
if ($normVt !== '') {
// Only set if not already set (more specific wins)
$meta["vt::{$normVt}"] = $meta["vt::{$normVt}"] ?? $entry;
}
// Key 3: by IDs — most specific
if ($vid > 0 && $sid > 0) {
$meta["id::{$vid}::seg::{$sid}"] = $entry;
}
// Key 4: by VT id only (fallback)
if ($vid > 0) { if ($vid > 0) {
$meta['id:' . $vid] = $entry; $meta["id::{$vid}"] = $meta["id::{$vid}"] ?? $entry;
} }
} }
return $meta; return $meta;
} }
/**
* vehicle_type.vehicle_type as partner_VT, partner_retention_rate.retention_rate as partner_RR.
* Keys: normalized vehicle name, and id:{vehicle_type_id}. Rows without retention_rate are omitted.
*
* @return array<string, array{partner_VT: string, partner_RR: float}>
*/
public static function buildPartnerMetaMap(BaseConnection $db, int $agentId): array public static function buildPartnerMetaMap(BaseConnection $db, int $agentId): array
{ {
return self::partnerMetaMapFromPrrRows(self::fetchPrrPvtRows($db, $agentId)); return self::partnerMetaMapFromPrrRows(self::fetchPrrPvtRows($db, $agentId));
} }
/**
* Normalized master label vehicle_type.id (active rows only).
* Used when grid row text must be resolved to an id for partner_retention_rate lookup.
*
* @return array<string, int>
*/
public static function buildMasterNormLabelToVehicleTypeIdMap(BaseConnection $db): array public static function buildMasterNormLabelToVehicleTypeIdMap(BaseConnection $db): array
{ {
$rows = $db->table('vehicle_type') $rows = $db->table('vehicle_type')
@ -106,9 +116,7 @@ class PartnerPayoutGridRetention
$out = []; $out = [];
foreach ($rows as $r) { foreach ($rows as $r) {
$k = self::normalizeVehicleTypeLabel($r['vehicle_type'] ?? ''); $k = self::normalizeVehicleTypeLabel($r['vehicle_type'] ?? '');
if ($k === '') { if ($k === '') continue;
continue;
}
$out[$k] = (int) $r['id']; $out[$k] = (int) $r['id'];
} }
@ -116,87 +124,117 @@ class PartnerPayoutGridRetention
} }
/** /**
* @param array<string, array{partner_VT: string, partner_RR: float}> $metaMap * Build segment label id map for resolving grid segment text to segment_id.
* @param array<string, int>|null $masterNormLabelToVtId from buildMasterNormLabelToVehicleTypeIdMap()
*
* @return array{partner_VT: string, partner_RR: float}|null null = no row in partner_retention_rate for this grid vehicle type (agent)
*/ */
public static function resolvePartnerMetaForGridRow(array $row, array $metaMap, ?array $masterNormLabelToVtId = null): ?array public static function buildMasterNormSegmentToIdMap(BaseConnection $db): array
{ {
$key = self::normalizeVehicleTypeLabel(isset($row['vehicle_type']) ? (string) $row['vehicle_type'] : ''); // Adjust table/column name to match your actual segment table
if ($key !== '' && isset($metaMap[$key])) { $rows = $db->table('partner_segment')
return $metaMap[$key]; ->select('id, segment')
->where('is_active', 1)
->get()
->getResultArray();
$out = [];
foreach ($rows as $r) {
$k = self::normalizeSegmentLabel($r['segment'] ?? '');
if ($k === '') continue;
$out[$k] = (int) $r['id'];
} }
return $out;
}
/**
* Resolve partner meta for a grid row.
* Priority:
* 1. vt text + segment text (most specific)
* 2. vt_id + segment_id
* 3. vt text only
* 4. vt_id only
*/
public static function resolvePartnerMetaForGridRow(
array $row,
array $metaMap,
?array $masterNormLabelToVtId = null,
?array $masterNormSegToId = null
): ?array {
$normVt = self::normalizeVehicleTypeLabel(isset($row['vehicle_type']) ? (string) $row['vehicle_type'] : '');
$normSeg = self::normalizeSegmentLabel(isset($row['segment']) ? (string) $row['segment'] : '');
// 1. Most specific: vt text + segment text
if ($normVt !== '' && $normSeg !== '') {
$k = "vt::{$normVt}::seg::{$normSeg}";
if (isset($metaMap[$k])) return $metaMap[$k];
}
// 2. By IDs: vt_id + segment_id
$vid = isset($row['vehicle_type_id']) ? (int) $row['vehicle_type_id'] : 0; $vid = isset($row['vehicle_type_id']) ? (int) $row['vehicle_type_id'] : 0;
if ($vid > 0 && isset($metaMap['id:' . $vid])) { $sid = isset($row['segment_id']) ? (int) $row['segment_id'] : 0;
return $metaMap['id:' . $vid];
// Try to resolve IDs from master maps if not on the row
if ($vid <= 0 && $masterNormLabelToVtId !== null && $normVt !== '') {
$vid = $masterNormLabelToVtId[$normVt] ?? 0;
} }
// Grid text matches master vehicle_type but meta was only keyed by id (e.g. weak pvt join on prr) if ($sid <= 0 && $masterNormSegToId !== null && $normSeg !== '') {
if ($masterNormLabelToVtId !== null && $key !== '') { $sid = $masterNormSegToId[$normSeg] ?? 0;
$mid = $masterNormLabelToVtId[$key] ?? 0; }
if ($mid > 0 && isset($metaMap['id:' . $mid])) {
return $metaMap['id:' . $mid]; if ($vid > 0 && $sid > 0) {
} $k = "id::{$vid}::seg::{$sid}";
if (isset($metaMap[$k])) return $metaMap[$k];
}
// 3. Fallback: vt text only
if ($normVt !== '') {
$k = "vt::{$normVt}";
if (isset($metaMap[$k])) return $metaMap[$k];
}
// 4. Fallback: vt id only
if ($vid > 0) {
$k = "id::{$vid}";
if (isset($metaMap[$k])) return $metaMap[$k];
} }
return null; return null;
} }
/**
* Manager / Accounts: no math null, empty, '-', unparseable, zero, or negative '-';
* else return formatted positive value.
*/
public static function gridPayoutDisplayManagerAccounts($raw): string public static function gridPayoutDisplayManagerAccounts($raw): string
{ {
if ($raw === null || $raw === '' || $raw === '-') { if ($raw === null || $raw === '' || $raw === '-') return '-';
return '-';
}
$v = self::toFloat($raw); $v = self::toFloat($raw);
if ($v === null || $v <= 0) { if ($v === null || $v <= 0) return '-';
return '-';
}
return self::formatGridNumericDisplay($v); return self::formatGridNumericDisplay($v);
} }
/** /**
* Agent: only if original comp/tp/od is a positive number partner_RR value. * Agent payout: partner_RR base value.
* Original null / empty / '-' / zero / negative / unparseable '-'. * e.g. RR=1.0, comp=7.2 1.0 - 7.2 = -5.8 ... wait.
*/
public static function agentPayoutColumnFromPartnerRr($raw, float $partnerRr): string
{
if ($raw === null || $raw === '' || $raw === '-') {
return '-';
}
$base = self::toFloat($raw);
if ($base === null || $base <= 0) {
return '-';
}
$result = $partnerRr - $base;
return self::formatGridNumericDisplay($result);
}
/**
* @param array<int, array<string, mixed>> $rows
* *
* @return array<int, array<string, mixed>> * Based on your example: 1.0 - 6.8 displayed.
* So formula is: base - RR (comp minus retention).
*/ */
public static function agentPayoutColumnFromPartnerRr($raw, float $partnerRr): string
{
if ($raw === null || $raw === '' || $raw === '-') return '-';
$base = self::toFloat($raw);
if ($base === null || $base <= 0) return '-';
$result = $base - $partnerRr;
if ($result <= 0) return '-';
return self::formatGridNumericDisplay($result);
}
public static function applyManagerAccountsDisplayToRows(array $rows): array public static function applyManagerAccountsDisplayToRows(array $rows): array
{ {
foreach ($rows as &$row) { foreach ($rows as &$row) {
if (array_key_exists('comp', $row)) { if (array_key_exists('comp', $row)) $row['comp'] = self::gridPayoutDisplayManagerAccounts($row['comp'] ?? null);
$row['comp'] = self::gridPayoutDisplayManagerAccounts($row['comp'] ?? null); if (array_key_exists('tp', $row)) $row['tp'] = self::gridPayoutDisplayManagerAccounts($row['tp'] ?? null);
} if (array_key_exists('od', $row)) $row['od'] = self::gridPayoutDisplayManagerAccounts($row['od'] ?? null);
if (array_key_exists('tp', $row)) {
$row['tp'] = self::gridPayoutDisplayManagerAccounts($row['tp'] ?? null);
}
if (array_key_exists('od', $row)) {
$row['od'] = self::gridPayoutDisplayManagerAccounts($row['od'] ?? null);
}
} }
unset($row); unset($row);
return $rows; return $rows;
} }
@ -205,171 +243,127 @@ class PartnerPayoutGridRetention
if (abs($v - round($v)) < 0.00001) { if (abs($v - round($v)) < 0.00001) {
return (string) (int) round($v); return (string) (int) round($v);
} }
return rtrim(rtrim(number_format($v, 2, '.', ''), '0'), '.'); return rtrim(rtrim(number_format($v, 2, '.', ''), '0'), '.');
} }
/**
* @param array<int, array<string, mixed>> $prrRows
*
* @return array<string, float> normalized name => rate, and id:{vehicle_type_id} => rate
*/
private static function retentionMapFromPrrRows(array $prrRows): array private static function retentionMapFromPrrRows(array $prrRows): array
{ {
$map = []; $map = [];
foreach ($prrRows as $r) { foreach ($prrRows as $r) {
if (! array_key_exists('retention_rate', $r) || $r['retention_rate'] === null || $r['retention_rate'] === '') { if (!array_key_exists('retention_rate', $r)
continue; || $r['retention_rate'] === null
|| $r['retention_rate'] === '') continue;
$rate = (float) $r['retention_rate'];
$name = isset($r['vehicle_type']) ? trim((string) $r['vehicle_type']) : '';
$segName = isset($r['segment']) ? trim((string) $r['segment']) : '';
$vid = isset($r['vehicle_type_id']) ? (int) $r['vehicle_type_id'] : 0;
$sid = isset($r['segment_id']) ? (int) $r['segment_id'] : 0;
$normVt = self::normalizeVehicleTypeLabel($name);
$normSeg = self::normalizeSegmentLabel($segName);
if ($normVt !== '' && $normSeg !== '') {
$map["vt::{$normVt}::seg::{$normSeg}"] = $rate;
} }
$rate = (float) $r['retention_rate']; if ($normVt !== '') {
$name = isset($r['vehicle_type']) ? trim((string) $r['vehicle_type']) : ''; $map["vt::{$normVt}"] = $map["vt::{$normVt}"] ?? $rate;
if ($name !== '') { }
$map[self::normalizeVehicleTypeLabel($name)] = $rate; if ($vid > 0 && $sid > 0) {
$map["id::{$vid}::seg::{$sid}"] = $rate;
} }
$vid = isset($r['vehicle_type_id']) ? (int) $r['vehicle_type_id'] : 0;
if ($vid > 0) { if ($vid > 0) {
$map['id:' . $vid] = $rate; $map["id::{$vid}"] = $map["id::{$vid}"] ?? $rate;
} }
} }
return $map; return $map;
} }
/**
* @return array<string, float> normalized name => rate, and id:{vehicle_type_id} => rate
*/
public static function buildRetentionMap(BaseConnection $db, int $agentId): array public static function buildRetentionMap(BaseConnection $db, int $agentId): array
{ {
return self::retentionMapFromPrrRows(self::fetchPrrPvtRows($db, $agentId)); return self::retentionMapFromPrrRows(self::fetchPrrPvtRows($db, $agentId));
} }
/** /**
* @param array<int, array<string, mixed>> $rows * Main apply now passes segment master map for full resolution.
*
* @return array<int, array<string, mixed>>
*/ */
public static function applyToRows(array $rows, int $agentId, BaseConnection $db): array public static function applyToRows(array $rows, int $agentId, BaseConnection $db): array
{ {
if ($agentId <= 0 || $rows === []) { if ($agentId <= 0 || $rows === []) return $rows;
return $rows;
$prrRows = self::fetchPrrPvtRows($db, $agentId);
$metaMap = self::partnerMetaMapFromPrrRows($prrRows);
$masterVt = self::buildMasterNormLabelToVehicleTypeIdMap($db);
$masterSeg = self::buildMasterNormSegmentToIdMap($db);
foreach ($rows as &$row) {
// Keep originals as-is (no oa/ob/oc/raw_* aliases)
$origComp = $row['comp'] ?? null;
$origTp = $row['tp'] ?? null;
$origOd = $row['od'] ?? null;
$pm = self::resolvePartnerMetaForGridRow($row, $metaMap, $masterVt, $masterSeg);
if ($pm === null) {
$row['partner_VT'] = '-';
$row['partner_RR'] = '-';
$row['partner_comp'] = '-';
$row['partner_tp'] = '-';
$row['partner_od'] = '-';
// comp/tp/od stay as original values
continue;
} }
$prrRows = self::fetchPrrPvtRows($db, $agentId); $rr = (float) $pm['partner_RR'];
$metaMap = self::partnerMetaMapFromPrrRows($prrRows);
$master = self::buildMasterNormLabelToVehicleTypeIdMap($db);
foreach ($rows as &$row) { $row['partner_VT'] = $pm['partner_VT'];
$oa = $row['comp'] ?? null; $row['partner_RR'] = $pm['partner_RR'];
$ob = $row['tp'] ?? null;
$oc = $row['od'] ?? null;
$row['oa'] = $oa;
$row['ob'] = $ob;
$row['oc'] = $oc;
// Explicit raw aliases for UI/API consumers.
$row['raw_comp'] = $oa;
$row['raw_tp'] = $ob;
$row['raw_od'] = $oc;
$pm = self::resolvePartnerMetaForGridRow($row, $metaMap, $master); // partner_* = original RR (e.g. 7.2 1.0 = 6.2)
if ($pm === null) { $row['partner_comp'] = array_key_exists('comp', $row)
$row['partner_VT'] = '-'; ? self::agentPayoutColumnFromPartnerRr($origComp, $rr)
$row['partner_RR'] = '-'; : '-';
$row['partner_comp'] = '-'; $row['partner_tp'] = array_key_exists('tp', $row)
$row['partner_tp'] = '-'; ? self::agentPayoutColumnFromPartnerRr($origTp, $rr)
$row['partner_od'] = '-'; : '-';
if (array_key_exists('comp', $row)) { $row['partner_od'] = array_key_exists('od', $row)
$row['comp'] = '-'; ? self::agentPayoutColumnFromPartnerRr($origOd, $rr)
} : '-';
if (array_key_exists('tp', $row)) {
$row['tp'] = '-';
}
if (array_key_exists('od', $row)) {
$row['od'] = '-';
}
continue; // comp/tp/od remain as original values — DO NOT overwrite
}
$row['partner_VT'] = $pm['partner_VT'];
$row['partner_RR'] = $pm['partner_RR'];
$rr = (float) $pm['partner_RR'];
$partnerComp = array_key_exists('comp', $row)
? self::agentPayoutColumnFromPartnerRr($oa, $rr)
: '-';
$partnerTp = array_key_exists('tp', $row)
? self::agentPayoutColumnFromPartnerRr($ob, $rr)
: '-';
$partnerOd = array_key_exists('od', $row)
? self::agentPayoutColumnFromPartnerRr($oc, $rr)
: '-';
$row['partner_comp'] = $partnerComp;
$row['partner_tp'] = $partnerTp;
$row['partner_od'] = $partnerOd;
if (array_key_exists('comp', $row)) {
$row['comp'] = $partnerComp;
}
if (array_key_exists('tp', $row)) {
$row['tp'] = $partnerTp;
}
if (array_key_exists('od', $row)) {
$row['od'] = $partnerOd;
}
}
unset($row);
return $rows;
} }
unset($row);
return $rows;
}
public static function retentionForRow(array $row, array $map): ?float public static function retentionForRow(array $row, array $map): ?float
{ {
$key = self::normalizeVehicleTypeLabel(isset($row['vehicle_type']) ? (string) $row['vehicle_type'] : ''); $key = self::normalizeVehicleTypeLabel(isset($row['vehicle_type']) ? (string) $row['vehicle_type'] : '');
if ($key !== '' && isset($map[$key])) { if ($key !== '' && isset($map[$key])) return $map[$key];
return $map[$key];
}
$vid = isset($row['vehicle_type_id']) ? (int) $row['vehicle_type_id'] : 0; $vid = isset($row['vehicle_type_id']) ? (int) $row['vehicle_type_id'] : 0;
if ($vid > 0 && isset($map['id:' . $vid])) { if ($vid > 0 && isset($map['id:' . $vid])) return $map['id:' . $vid];
return $map['id:' . $vid];
}
return null; return null;
} }
/**
* @return float|int|string|null '-' when adjusted <= 0, else numeric display
*/
public static function adjustPayoutValue($raw, float $rate) public static function adjustPayoutValue($raw, float $rate)
{ {
if ($raw === null || $raw === '' || $raw === '-') { if ($raw === null || $raw === '' || $raw === '-') return $raw;
return $raw;
}
$base = self::toFloat($raw); $base = self::toFloat($raw);
if ($base === null) { if ($base === null) return $raw;
return $raw;
}
$adj = $base - $rate; $adj = $base - $rate;
if ($adj <= 0) { if ($adj <= 0) return '-';
return '-'; if (abs($adj - round($adj)) < 0.00001) return (int) round($adj);
}
if (abs($adj - round($adj)) < 0.00001) {
return (int) round($adj);
}
return rtrim(rtrim(number_format($adj, 2, '.', ''), '0'), '.'); return rtrim(rtrim(number_format($adj, 2, '.', ''), '0'), '.');
} }
private static function toFloat($raw): ?float private static function toFloat($raw): ?float
{ {
if (is_numeric($raw)) { if (is_numeric($raw)) return (float) $raw;
return (float) $raw;
}
$clean = preg_replace('/[^0-9.\-]/', '', (string) $raw); $clean = preg_replace('/[^0-9.\-]/', '', (string) $raw);
if ($clean === '' || $clean === '-' || $clean === '.') { if ($clean === '' || $clean === '-' || $clean === '.') return null;
return null;
}
return (float) $clean; return (float) $clean;
} }
} }