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;
/**
* 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
{
/**
* Active partner_retention_rate rows with joined vehicle_type (one query for maps + agent grid meta).
*
* @return array<int, array<string, mixed>>
* Fetch PRR rows with vehicle_type AND segment joined.
* Now includes segment_id for per-segment RR matching.
*/
private static function fetchPrrPvtRows(BaseConnection $db, int $agentId): array
{
@ -30,8 +17,10 @@ class PartnerPayoutGridRetention
}
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('partner_segment seg', 'seg.id = prr.segment_id', 'left') // join segment table
->where('prr.agent_id', $agentId)
->where('prr.is_active', 1)
->get()
@ -43,58 +32,79 @@ class PartnerPayoutGridRetention
if ($s === null || $s === '') {
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)));
}
/**
* @param array<int, array<string, mixed>> $prrRows
*
* @return array<string, array{partner_VT: string, partner_RR: float}>
* Build meta map keyed by:
* 1. "vt::{normalizedVehicleType}::seg::{normalizedSegment}" most specific
* 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
{
$meta = [];
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;
}
$partnerRr = (float) $r['retention_rate'];
$vtRaw = isset($r['vehicle_type']) ? trim((string) $r['vehicle_type']) : '';
$segRaw = isset($r['segment']) ? trim((string) $r['segment']) : '';
$partnerVt = $vtRaw !== '' ? $vtRaw : 'N/A';
$entry = [
$entry = [
'partner_VT' => $partnerVt,
'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) {
$meta['id:' . $vid] = $entry;
$meta["id::{$vid}"] = $meta["id::{$vid}"] ?? $entry;
}
}
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
{
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
{
$rows = $db->table('vehicle_type')
@ -106,9 +116,7 @@ class PartnerPayoutGridRetention
$out = [];
foreach ($rows as $r) {
$k = self::normalizeVehicleTypeLabel($r['vehicle_type'] ?? '');
if ($k === '') {
continue;
}
if ($k === '') continue;
$out[$k] = (int) $r['id'];
}
@ -116,87 +124,117 @@ class PartnerPayoutGridRetention
}
/**
* @param array<string, array{partner_VT: string, partner_RR: float}> $metaMap
* @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)
* Build segment label id map for resolving grid segment text to segment_id.
*/
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'] : '');
if ($key !== '' && isset($metaMap[$key])) {
return $metaMap[$key];
// Adjust table/column name to match your actual segment table
$rows = $db->table('partner_segment')
->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;
if ($vid > 0 && isset($metaMap['id:' . $vid])) {
return $metaMap['id:' . $vid];
$sid = isset($row['segment_id']) ? (int) $row['segment_id'] : 0;
// 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 ($masterNormLabelToVtId !== null && $key !== '') {
$mid = $masterNormLabelToVtId[$key] ?? 0;
if ($mid > 0 && isset($metaMap['id:' . $mid])) {
return $metaMap['id:' . $mid];
}
if ($sid <= 0 && $masterNormSegToId !== null && $normSeg !== '') {
$sid = $masterNormSegToId[$normSeg] ?? 0;
}
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;
}
/**
* Manager / Accounts: no math null, empty, '-', unparseable, zero, or negative '-';
* else return formatted positive value.
*/
public static function gridPayoutDisplayManagerAccounts($raw): string
{
if ($raw === null || $raw === '' || $raw === '-') {
return '-';
}
if ($raw === null || $raw === '' || $raw === '-') return '-';
$v = self::toFloat($raw);
if ($v === null || $v <= 0) {
return '-';
}
if ($v === null || $v <= 0) return '-';
return self::formatGridNumericDisplay($v);
}
/**
* Agent: only if original comp/tp/od is a positive number partner_RR value.
* Original null / empty / '-' / zero / negative / unparseable '-'.
* Agent payout: partner_RR base value.
* e.g. RR=1.0, comp=7.2 1.0 - 7.2 = -5.8 ... wait.
*
* 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 '-';
}
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);
}
$result = $base - $partnerRr;
if ($result <= 0) return '-';
return self::formatGridNumericDisplay($result);
}
/**
* @param array<int, array<string, mixed>> $rows
*
* @return array<int, array<string, mixed>>
*/
public static function applyManagerAccountsDisplayToRows(array $rows): array
{
foreach ($rows as &$row) {
if (array_key_exists('comp', $row)) {
$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('comp', $row)) $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);
}
unset($row);
return $rows;
}
@ -205,171 +243,127 @@ class PartnerPayoutGridRetention
if (abs($v - round($v)) < 0.00001) {
return (string) (int) round($v);
}
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
{
$map = [];
foreach ($prrRows as $r) {
if (! array_key_exists('retention_rate', $r) || $r['retention_rate'] === null || $r['retention_rate'] === '') {
continue;
if (!array_key_exists('retention_rate', $r)
|| $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'];
$name = isset($r['vehicle_type']) ? trim((string) $r['vehicle_type']) : '';
if ($name !== '') {
$map[self::normalizeVehicleTypeLabel($name)] = $rate;
if ($normVt !== '') {
$map["vt::{$normVt}"] = $map["vt::{$normVt}"] ?? $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) {
$map['id:' . $vid] = $rate;
$map["id::{$vid}"] = $map["id::{$vid}"] ?? $rate;
}
}
return $map;
}
/**
* @return array<string, float> normalized name => rate, and id:{vehicle_type_id} => rate
*/
public static function buildRetentionMap(BaseConnection $db, int $agentId): array
{
return self::retentionMapFromPrrRows(self::fetchPrrPvtRows($db, $agentId));
}
/**
* @param array<int, array<string, mixed>> $rows
*
* @return array<int, array<string, mixed>>
* Main apply now passes segment master map for full resolution.
*/
public static function applyToRows(array $rows, int $agentId, BaseConnection $db): array
{
if ($agentId <= 0 || $rows === []) {
return $rows;
{
if ($agentId <= 0 || $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);
$metaMap = self::partnerMetaMapFromPrrRows($prrRows);
$master = self::buildMasterNormLabelToVehicleTypeIdMap($db);
$rr = (float) $pm['partner_RR'];
foreach ($rows as &$row) {
$oa = $row['comp'] ?? null;
$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;
$row['partner_VT'] = $pm['partner_VT'];
$row['partner_RR'] = $pm['partner_RR'];
$pm = self::resolvePartnerMetaForGridRow($row, $metaMap, $master);
if ($pm === null) {
$row['partner_VT'] = '-';
$row['partner_RR'] = '-';
$row['partner_comp'] = '-';
$row['partner_tp'] = '-';
$row['partner_od'] = '-';
if (array_key_exists('comp', $row)) {
$row['comp'] = '-';
}
if (array_key_exists('tp', $row)) {
$row['tp'] = '-';
}
if (array_key_exists('od', $row)) {
$row['od'] = '-';
}
// partner_* = original RR (e.g. 7.2 1.0 = 6.2)
$row['partner_comp'] = array_key_exists('comp', $row)
? self::agentPayoutColumnFromPartnerRr($origComp, $rr)
: '-';
$row['partner_tp'] = array_key_exists('tp', $row)
? self::agentPayoutColumnFromPartnerRr($origTp, $rr)
: '-';
$row['partner_od'] = array_key_exists('od', $row)
? self::agentPayoutColumnFromPartnerRr($origOd, $rr)
: '-';
continue;
}
$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;
// comp/tp/od remain as original values — DO NOT overwrite
}
unset($row);
return $rows;
}
public static function retentionForRow(array $row, array $map): ?float
{
$key = self::normalizeVehicleTypeLabel(isset($row['vehicle_type']) ? (string) $row['vehicle_type'] : '');
if ($key !== '' && isset($map[$key])) {
return $map[$key];
}
if ($key !== '' && isset($map[$key])) return $map[$key];
$vid = isset($row['vehicle_type_id']) ? (int) $row['vehicle_type_id'] : 0;
if ($vid > 0 && isset($map['id:' . $vid])) {
return $map['id:' . $vid];
}
if ($vid > 0 && isset($map['id:' . $vid])) return $map['id:' . $vid];
return null;
}
/**
* @return float|int|string|null '-' when adjusted <= 0, else numeric display
*/
public static function adjustPayoutValue($raw, float $rate)
{
if ($raw === null || $raw === '' || $raw === '-') {
return $raw;
}
if ($raw === null || $raw === '' || $raw === '-') return $raw;
$base = self::toFloat($raw);
if ($base === null) {
return $raw;
}
if ($base === null) return $raw;
$adj = $base - $rate;
if ($adj <= 0) {
return '-';
}
if (abs($adj - round($adj)) < 0.00001) {
return (int) round($adj);
}
if ($adj <= 0) return '-';
if (abs($adj - round($adj)) < 0.00001) return (int) round($adj);
return rtrim(rtrim(number_format($adj, 2, '.', ''), '0'), '.');
}
private static function toFloat($raw): ?float
{
if (is_numeric($raw)) {
return (float) $raw;
}
if (is_numeric($raw)) return (float) $raw;
$clean = preg_replace('/[^0-9.\-]/', '', (string) $raw);
if ($clean === '' || $clean === '-' || $clean === '.') {
return null;
}
if ($clean === '' || $clean === '-' || $clean === '.') return null;
return (float) $clean;
}
}
}