db = db_connect(); } public function insertOpd(array $data): int { $pId = (int) ($data['p_id'] ?? 0); $docId = (int) ($data['doc_id'] ?? 0); if ($pId <= 0 || $docId <= 0) { return 0; } $duplicate = $this->db->table('opd_master') ->where('apointment_date', date('Y-m-d')) ->where('p_id', $pId) ->where('doc_id', $docId) ->groupStart() ->where('payment_status', 0) ->orWhere('opd_status', 1) ->groupEnd() ->countAllResults(); if ($duplicate > 0) { return 0; } $this->db->table('opd_master')->insert($data); $insertId = (int) $this->db->insertID(); if ($insertId <= 0) { return 0; } $opdNoRow = $this->db->table('opd_master') ->select('count(*) as no_max') ->where('apointment_date', date('Y-m-d')) ->where('doc_id', $docId) ->get() ->getRow(); $opdNo = (int) ($opdNoRow->no_max ?? 1); if ($opdNo <= 0) { $opdNo = 1; } $pidSuffix = str_pad(substr((string) $insertId, -7, 7), 7, '0', STR_PAD_LEFT); $opdCode = 'D' . date('ym') . $pidSuffix; $runningOpd = 0; $lastOpdId = 0; $isZeroValueRunning = ((int) ($data['opd_fee_type'] ?? 0) === 3) || ((float) ($data['opd_fee_amount'] ?? 0) <= 0); if ((int) ($data['opd_fee_type'] ?? 0) === 3) { $runningOpd = 1; $lastOpdRow = $this->db->table('opd_master') ->select('max(opd_id) as last_opd_id') ->where('apointment_date >=', $this->resolveRunningLookupDate($docId)) ->where('apointment_date <=', date('Y-m-d')) ->where('running_opd', 0) ->where('opd_fee_type <>', 3) ->where('coalesce(opd_fee_amount,0) >', 0, false) ->where('doc_id', $docId) ->where('p_id', $pId) ->get() ->getRow(); $lastOpdId = (int) ($lastOpdRow->last_opd_id ?? 0); } $opdTimesBuilder = $this->db->table('opd_master') ->select('count(*) as xtimes') ->where('opd_id <=', $insertId) ->where('p_id', $pId); if ($isZeroValueRunning && $lastOpdId > 0) { // For zero-value running OPD, keep visit count within the same paid OPD validity cycle. $opdTimesBuilder ->where('opd_id >=', $lastOpdId) ->where('doc_id', $docId); } $opdTimesRow = $opdTimesBuilder->get()->getRow(); $opdTimes = (int) ($opdTimesRow->xtimes ?? 0); $update = [ 'opd_code' => $opdCode, 'no_visit' => $opdTimes, 'running_opd' => $runningOpd, 'running_opd_id' => $lastOpdId, 'opd_no' => $opdNo, ]; $this->db->table('opd_master') ->where('opd_id', $insertId) ->update($update); return $insertId; } private function resolveRunningLookupDate(int $docId): string { $docRow = $this->db->table('doctor_master') ->select('opd_valid_no_days') ->where('id', $docId) ->get() ->getRow(); $validDays = (int) ($docRow->opd_valid_no_days ?? 0); if ($validDays <= 0) { $validDays = $this->getHospitalDefaultOpdValidityDays(); } $spanDays = max(0, $validDays - 1); return date('Y-m-d', strtotime('-' . $spanDays . ' days')); } private function getHospitalDefaultOpdValidityDays(): int { if (! $this->db->tableExists('hospital_setting')) { return 5; } $keys = [ 'OPD_VALID_NO_DAYS', 'OPD_VALIDITY_DAYS', 'DEFAULT_OPD_VALID_NO_DAYS', 'DEFAULT_OPD_VALIDITY_DAYS', ]; $rows = $this->db->table('hospital_setting') ->select('s_name,s_value') ->whereIn('s_name', $keys) ->get() ->getResultArray(); $map = []; foreach ($rows as $row) { $name = strtoupper(trim((string) ($row['s_name'] ?? ''))); if ($name === '') { continue; } $map[$name] = (string) ($row['s_value'] ?? ''); } foreach ($keys as $key) { $value = (int) ($map[$key] ?? 0); if ($value > 0) { return min(365, $value); } } return 5; } }