db_onedev = $this->load->database("onedev", true); $this->db_smartone = $this->load->database("onedev", true); } /* { "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJNX1VzZXJJRCI6IjIiLCJNX1VzZXJFbWFpbCI6Impva29AZ21haWwuY29tIiwiTV9Vc2VyVXNlcm5hbWUiOiJqb2tvQGdtYWlsLmNvbSIsIk1fVXNlckdyb3VwRGFzaGJvYXJkIjoib25lLXVpXC90ZXN0XC92dWV4XC9jcG9uZS1wcm9jZXNzLXJlc3VsdGVudHJ5LXYyMFwvIiwiTV9Vc2VyRGVmYXVsdFRfU2FtcGxlU3RhdGlvbklEIjoiMSIsIk1fU3RhZmZOYW1lIjoiQWRtaW4gQ1BPTkUiLCJpc19jb3VyaWVyIjoiTiIsIk1fQnJhbmNoSUQiOiIxIiwiTV9CcmFuY2hOYW1lIjoiV2VzdGVyaW5kbyBDaXBha3UiLCJ0aW1lX2F1dG9sb2dvdXQiOiIxNSIsImlwIjoiMTI4LjE5OS44Ni43IiwiYWdlbnQiOiJHby1odHRwLWNsaWVudFwvMS4xIiwidmVyc2lvbiI6InYyIiwibGFzdC1sb2dpbiI6IjIwMjYtMDEtMjYgMTM6NDc6MDYifQ._5Xxr2TbhEEuorjQm4xgwfVX3oom42C8FaDms4KPQBI", "selected_patient": { "divider": "N", "M_PatientID": "55927", "M_PatientNoReg": "CP2512210006", "M_PatientEmail": "", "M_PatientPrefix": "", "M_PatientSuffix": "", "M_PatientName": "Nn Lina Cyan ", "M_PatientRealName": "Lina Cyan", "M_TitleID": "5", "M_TitleName": "Nn", "M_SexName": "Perempuan", "M_PatientHP": "-", "M_PatientPOB": null, "M_PatientDOB": "1990-02-01", "dob_ina": "01-02-1990", "M_PatientAddress": "RT 04 RW 02 Desa Hayam Wuruk", "M_PatientAddressID": "", "M_PatientAddressDescription": "RT 04 RW 02 Desa Hayam Wuruk", "M_PatientIdentifierCode": "NNIDN", "M_PatientIdentifierDisplay": "Nomor Induk Kependudukan (KTP)", "M_PatientIdentifierSystem": "http://terminology.hl7.org/CodeSystem/v2-0203", "M_PatientIDNumber": "", "M_PatientAddressRegionalCd": "7171010007", "M_PatientAddressLocation": "", "M_PatientAddressCity": "Kota Manado", "M_PatientAddressRT": "", "M_PatientAddressRW": "", "M_PatientAddressVillage": "Malalayang I Barat", "M_PatientAddressDistrict": "Malalayang", "M_PatientAddressState": "Sulawesi Utara", "M_PatientAddressCountry": "Indonesia", "M_PatientAddressCountryCode": "", "M_PatientNote": "", "M_PatientPhoto": "", "hp": "-", "info": { "visit": 1, "birthday": "N" }, "M_KelurahanID": "0", "M_DistrictID": "0", "M_CityID": "0", "M_ProvinceID": "0", "M_PatientM_ReligionID": "0", "M_PatientReligionSystem": "xhis.code.religion", "M_PatientReligionCode": "", "M_PatientReligionDisplay": "", "M_PatientBloodTypeCode": "", "M_PatientBloodTypeSystem": "", "blood_type_display": "", "blood_rh_code": "", "blood_rh_system": "http://loinc.org", "blood_rh_display": "", "M_PatientEtnicCode": "", "M_PatientEtnicSystem": "xhis.code.etnicity", "etnic_display": "", "M_PatientCitizenship": "WNI", "M_PatientEducationSystem": "", "M_PatientEducationCode": "", "M_PatientEducationDisplay": "", "M_PatientNIP": "", "M_PatientJob": "", "M_PatientPosisi": "", "M_PatientDivisi": "", "M_PatientLocation": "", "M_PatientDepartement": "", "corporate_id": "1215", "corporate_name": "PT Petrolog Indah ", "patient_age": "35 tahun 11 bulan 25 hari" }, "patient_age": "35 tahun 11 bulan 25 hari", "patient_note": "", "diagnosa": "", "catatan_fo": "", "selected_icd10": {}, "selected_doctor": { "M_DoctorID": "59", "M_DoctorCode": "D240700001", "M_DoctorPrefix": "", "M_DoctorPrefix2": "dr.", "M_DoctorSuffix": "Sp.PK", "M_DoctorSuffix2": "", "M_DoctorName": "Agus Setiawan", "M_DoctorNote": "" }, "selected_language": "1", "selected_language_2": 0, "selected_project": {}, "selected_fisik_template": {}, "selected_company": { "CorporateID": "1911", "CorporateName": "Khusus Assuransi / Perusahaan (Rawat jalan)", "corporate_prices": [ { "corporate_id": "1911", "price_header_id": "115", "price_header_name": "Harga 2025", "price_header_code": "PH2501003", "corporate_price_start_date": "30-12-2025", "corporate_price_end_date": "30-12-2026", "note": "", "is_default": "Y" } ] }, "selected_mou": { "corporate_id": "1911", "price_header_id": "115", "price_header_name": "Harga 2025", "price_header_code": "PH2501003", "corporate_price_start_date": "30-12-2025", "corporate_price_end_date": "30-12-2026", "note": "", "is_default": "Y" }, "detail": [ { "t_id": "330", "t_name": "Asam Folat", "t_amount": "1212000", "t_discount": "0", "t_discount_rp": "0", "t_subtotal": "1212000", "t_total": "1212000", "t_cito": "N", "nat_test": [ 4265 ], "t_req": "N", "t_reqnote": "", "t_ispacket": "N", "t_packetid": "0", "packet_type": "", "packet_name": "", "t_px_type": "PX" }, { "t_id": "321", "t_name": "Serum Iron", "t_amount": "225000", "t_discount": "0", "t_discount_rp": "0", "t_subtotal": "225000", "t_total": "225000", "t_cito": "N", "nat_test": [ 4258 ], "t_req": "N", "t_reqnote": "", "t_ispacket": "N", "t_packetid": "0", "packet_type": "", "packet_name": "", "t_px_type": "PX" }, { "t_id": "66", "t_name": "Laju Endap Darah (LED)", "t_amount": "67000", "t_discount": "0", "t_discount_rp": "0", "t_subtotal": "67000", "t_total": "67000", "t_cito": "N", "nat_test": [ 4107 ], "t_req": "N", "t_reqnote": "", "t_ispacket": "N", "t_packetid": "0", "packet_type": "", "packet_name": "", "t_px_type": "PX" }, { "t_id": "895", "t_name": "SGPT", "t_amount": "81000", "t_discount": "0", "t_discount_rp": "0", "t_subtotal": "81000", "t_total": "81000", "t_cito": "N", "nat_test": [ 4634 ], "t_req": "N", "t_reqnote": "", "t_ispacket": "N", "t_packetid": "0", "packet_type": "", "packet_name": "", "t_px_type": "PX" }, { "t_id": "894", "t_name": "SGOT", "t_amount": "81000", "t_discount": "0", "t_discount_rp": "0", "t_subtotal": "81000", "t_total": "81000", "t_cito": "N", "nat_test": [ 4633 ], "t_req": "N", "t_reqnote": "", "t_ispacket": "N", "t_packetid": "0", "packet_type": "", "packet_name": "", "t_px_type": "PX" } ], "received_sample": "N", "received_sample_time": "", "queue": "", "deliveries": [ { "kelurahan": "0", "address_id": "0", "delivery_type": "1", "delivery_id": "1", "delivery_name": "Ambil Sendiri", "description": "", "chex": "Y", "note": "", "typeform": "origin", "type": "patient", "delivery_code": "PICKUP" }, { "kelurahan": "Malalayang I Barat", "address_id": "0", "delivery_type": "2", "delivery_id": "2", "delivery_name": "Alamat Pasien", "description": "RT 04 RW 02 Desa Hayam Wuruk Malalayang I Barat, Malalayang, Sulawesi Utara", "chex": "N", "note": "", "typeform": "origin", "type": "patient", "delivery_code": "ADDRESS" }, { "kelurahan": "0", "address_id": "0", "delivery_type": "4", "delivery_id": "6", "delivery_name": "Whatsapp Pasien", "description": "-", "chex": "N", "note": "", "typeform": "origin", "type": "patient", "delivery_code": "WHATSAPP" } ], "cito_id": "2", "schedule": [ { "JanjiHasil_Tanggal": "2026-01-27", "JanjiHasil_Waktu": "16:17:55", "JanjiHasil": "2026-01-27 16:17:55", "TestIDs": "66,321,330,894,895", "TestNames": "Laju Endap Darah (LED/BBS), Serum Iron ( SI ), Asam folat, serum, AST/SGOT, ALT/SGPT", "OrderDetailIDs": null, "ScheduleID": null, "M_ScheduleFlagAtTime": null, "M_ScheduleAtTime": null, "TAT_Menit": null, "M_ScheduleStartHourMinute": null, "M_ScheduleEndHourMinute": null } ], "req": { "status": "Y", "reqs": [] } } */ /* CREATE TABLE `inject_walk_in_error_log` ( `IwiErrorLogID` int NOT NULL AUTO_INCREMENT, `IwiErrorLogFnName` varchar(250) NOT NULL DEFAULT '', `IwiErrorLogMessage` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, `IwiErrorLogQuery` text, `IwiErrorLogJson` text, `IwiErrorLogUserID` int NOT NULL DEFAULT '999', `IwiErrorLogCreated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`IwiErrorLogID`), KEY `IwiErrorLogFnName` (`IwiErrorLogFnName`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; */ function index() { $this->load->library("Resultcalc"); $id = 946; $rows = $this->resultcalc->auto($id); echo "
 $rows";
   }

   function insert_error_log($fn_name, $message, $query, $json){
    $sql = "INSERT INTO cpone_log.inject_walk_in_error_log (IwiErrorLogFnName, IwiErrorLogMessage, IwiErrorLogQuery, IwiErrorLogJson, IwiErrorLogUserID, IwiErrorLogCreated) VALUES (?, ?, ?, ?, ?, NOW())";
    $query = $this->db_onedev->query($sql, [$fn_name, $message, $query, json_encode($json), 999]);
    if(!$query){
      echo $this->db_onedev->last_query();
      echo "Invalid query : \n";
      print_r($this->db_onedev->error());
      exit;
    }
   }

   function get_branch($branch_code) {
    $sql = "SELECT M_BranchID, M_BranchName, M_BranchCodeLab 
    FROM m_branch WHERE M_BranchCodeLab = ?";
    $query = $this->db_smartone->query($sql, [$branch_code]);
    if(!$query){
      return null;
    }
    return $query->row_array();
   }

   function gen_age($dob, $transaction_date){
    //$age = $this->gen_age('1993-10-15', '2024-01-20'); // Contoh: "30 tahun 3 bulan 18 hari"
      // Convert DOB to DateTime object if it's a string
      if (is_string($dob)) {
         $dob = new DateTime($dob);
      }
      
      // Convert transaction_date to DateTime object if it's a string
      if (is_string($transaction_date)) {
         $transaction_date = new DateTime($transaction_date);
      }
      
      $diff = $transaction_date->diff($dob);
      
      $years = $diff->y;
      $months = $diff->m;
      $days = $diff->d;
      
      $age_string = '';
      
      if ($years > 0) {
         $age_string .= $years . ' tahun';
      }
      
      if ($months > 0) {
         if ($age_string != '') {
            $age_string .= ' ';
         }
         $age_string .= $months . ' bulan';
      }
      
      if ($days > 0) {
         if ($age_string != '') {
            $age_string .= ' ';
         }
         $age_string .= $days . ' hari';
      }
      
      // If all are zero, return default message
      if ($age_string == '') {
         $age_string = '0 hari';
      }
      
      return $age_string;
   }


    function get_terminology($resource_type, $attribute_path, $code){
        $params = [];
        $filter_where = '';
        $filter_resource_type = '';
        if(!$resource_type){
        $filter_resource_type = "resource_type = ?";
        if($filter_where != ''){
            $filter_where .= " AND ";
        }else{
            $filter_where .= " WHERE ";
        }
        $filter_where .= $filter_resource_type;
        $params[] = $resource_type;
        }

        $filter_attribute_path = '';
        if(!$attribute_path){
        $filter_attribute_path = "attribute_path = ?";
        if($filter_where != ''){
            $filter_where .= " AND ";
        }else{
            $filter_where .= " WHERE ";
        }
        $filter_where .= $filter_attribute_path;
        $params[] = $attribute_path;
        }

        $filter_code = '';
        if(!$code){
        $filter_code = "code = ?";
        if($filter_where != ''){
            $filter_where .= " AND ";
        }else{
            $filter_where .= " WHERE ";
        }
        $filter_where .= $filter_code;
        $params[] = $code;
        }



        $sql = "SELECT * FROM terminology {$filter_where} limit 1";
        $query = $this->db_smartone->query($sql, $params);
        if ($query) { 
        $row = $query->row_array();
        return $row;
        } 
        else {
        return null;
        }
    }

    function get_test_by_code($test_code, $packet_code = '', $price_header_id = null) {
        if($test_code != ''){
            // Search for test by T_TestSasCode
            $sql = "SELECT T_TestID FROM t_test WHERE T_TestSasCode = ? AND T_TestIsActive = 'Y' LIMIT 1";
            $query = $this->db_smartone->query($sql, [$test_code]);
            if(!$query){
                $this->insert_error_log(__FUNCTION__, $this->db_smartone->error(), $sql, json_encode([$test_code]));
                return null;
            }
            $test = $query->row_array();
            if(!$test){
                $this->insert_error_log(__FUNCTION__, "No test found for test_code: $test_code", $sql, json_encode([$test_code]));
                return null;
            }
            $test_id = $test['T_TestID'];
            
            // Get price from ss_price_mou
            $sql = "SELECT ss_price_mou.*, nat_test.Nat_TestID, xtest.T_TestName, xtest.T_TestCode, xtest.T_TestSasCode
                FROM ss_price_mou
                    JOIN t_test xtest ON xtest.T_TestID = ss_price_mou.T_TestID AND xtest.T_TestIsActive = 'Y'
                    LEFT JOIN nat_test ON xtest.T_TestNat_TestID = nat_test.Nat_TestID
                    WHERE ss_price_mou.T_TestID = ?";
            if($price_header_id){
                $sql .= " AND ss_price_mou.Ss_PriceMouT_PriceHeaderID = ?";
                $params = [$test_id, $price_header_id];
        }else{
                $params = [$test_id];
            }
            $sql .= " LIMIT 1";
        }else{
            // Search for packet by T_PacketSasCode
            $sql = "SELECT T_PacketID FROM t_packet WHERE T_PacketSasCode = ? AND T_PacketIsActive = 'Y' LIMIT 1";
            $query = $this->db_smartone->query($sql, [$packet_code]);
            if(!$query){
                $this->insert_error_log(__FUNCTION__, $this->db_smartone->error(), $sql, json_encode([$packet_code]));
                return null;
            }
            $packet = $query->row_array();
            if(!$packet){
                $this->insert_error_log(__FUNCTION__, "No packet found for packet_code: $packet_code", $sql, json_encode([$packet_code]));
                return null;
            }
            $packet_id = $packet['T_PacketID'];
            
            // Get price from ss_price_mou
            $sql = "SELECT ss_price_mou.*, xpacket.T_PacketName, xpacket.T_PacketSasCode, xpacket.T_PacketType
                FROM ss_price_mou
                    JOIN t_packet xpacket ON xpacket.T_PacketID = ss_price_mou.packet_id AND xpacket.T_PacketIsActive = 'Y'
                    WHERE ss_price_mou.packet_id = ?";
            if($price_header_id){
                $sql .= " AND ss_price_mou.Ss_PriceMouT_PriceHeaderID = ?";
                $params = [$packet_id, $price_header_id];
            }else{
                $params = [$packet_id];
            }
            $sql .= " LIMIT 1";
        }
        
        $query = $this->db_smartone->query($sql, $params);
        if(!$query){
            $this->insert_error_log(__FUNCTION__, $this->db_smartone->error(), $sql, json_encode($params));
            return null;
        }
        $rows = $query->result_array();
        if(count($rows) == 0){
            $this->insert_error_log(__FUNCTION__, "No rows found for test_code: $test_code, packet_code: $packet_code, price_header_id: $price_header_id", $sql, json_encode($params));
            return null;
        }

        return $rows[0];
    }

   
   public function get_patient_by_noreg($noreg)
   {

      

      $sql = "SELECT 'N' divider,M_PatientID, M_PatientNoReg,M_PatientEmail,M_PatientPrefix,M_PatientSuffix,
            concat(M_TitleName,' ',IFNULL(M_PatientPrefix,''),' ',M_PatientName,' ',IFNULL(M_PatientSuffix,'')) M_PatientName,
            M_PatientName M_PatientRealName, M_TitleID, M_TitleName, 
            IF(M_PatientGender = 'male', 'Laki-laki', 'Perempuan') M_SexName,
            M_PatientHP, '' as M_PatientPOB, M_PatientDOB, DATE_FORMAT(M_PatientDOB,'%d-%m-%Y') as dob_ina,
            M_PatientAddress,
            '' as M_PatientAddressID,
            M_PatientAddress as M_PatientAddressDescription, 'NNIDN' M_PatientIdentifierCode,
            'Nomor Induk Kependudukan (KTP)' M_PatientIdentifierDisplay,
            'http://terminology.hl7.org/CodeSystem/v2-0203' M_PatientIdentifierSystem,
            M_PatientIdentifierValue M_PatientIDNumber,
            M_PatientAddressRegionalCd,
            '' as M_PatientAddressLocation,
            M_PatientAddressCity,
            M_PatientAddressRT,
            M_PatientAddressRW,
            M_PatientAddressVillage,
            M_PatientAddressDistrict,
            M_PatientAddressState,
            M_PatientAddressCountry,
            '' as M_PatientAddressCountryCode,
            M_PatientAddOnPOB as M_PatientPOB,
            IFNULL(M_PatientAddOnNote, '') M_PatientNote, 
            M_PatientPhoto, 
            M_PatientHP hp,
            '' as info,
            0 as M_KelurahanID, 0 M_DistrictID, 0 M_CityID, 0 M_ProvinceID, 0 M_PatientM_ReligionID, 
            'xhis.code.religion' as M_PatientReligionSystem,
            M_PatientReligionCode as M_PatientReligionCode,
            M_PatientReligionCode as M_PatientReligionDisplay,
            M_PatientBloodTypeCode,
            M_PatientBloodTypeSystem,
            '' as blood_type_display,
            M_PatientBloodRhCode as blood_rh_code,
            'http://loinc.org' as blood_rh_system,
            '' as blood_rh_display,
            M_PatientEtnicCode,
            'xhis.code.etnicity' as M_PatientEtnicSystem,
            '' as etnic_display,
            M_PatientCitizenship,
            M_PatientEducationSystem,
            M_PatientEducationCode,
            M_PatientEducationCode as M_PatientEducationDisplay,
            M_PatientNIP,
            M_PatientJob,
            M_PatientPosisi,
            M_PatientDivisi,
            M_PatientLocation,
            M_PatientDepartement,
            M_PatientRegisteredByCorporateID as corporate_id,
            '' as corporate_name
            FROM m_patient 
            JOIN m_title on M_PatientM_TitleID = M_TitleID
            LEFT JOIN m_patient_addon ON M_PatientAddOnM_PatientID = M_PatientID AND M_PatientAddOnIsActive = 'Y'
            WHERE 
            M_PatientIsActive = 'Y'
            AND M_PatientNoReg = '{$noreg}'
            GROUP BY M_PatientID
            limit 1";
      $query = $this->db_smartone->query($sql);
      if(!$query){
        $this->insert_error_log(__FUNCTION__, $this->db_smartone->error(), $sql, json_encode($params));
        return null;
      }

      if ($query) { 
        $rows = $query->result_array();
        if(count($rows) == 0){
          $this->insert_error_log(__FUNCTION__, "No rows found for noreg: $noreg", $sql, json_encode($params));
          return null;
        }

        foreach ($rows as $k => $v)
        {
			   $rows[$k]['M_PatientName'] = stripslashes($rows[$k]['M_PatientName']);
			   $rows[$k]['M_PatientAddress'] = stripslashes($rows[$k]['M_PatientAddressDescription']);
                $info = $this->db_smartone->query("SELECT fn_fo_patient_visit(?) info", [$v['M_PatientID']])->row();
                $rows[$k]['info'] = json_decode($info->info);

                if($v['corporate_id'] > 0){
                $corporate = $this->db_smartone->query("SELECT CorporateName FROM corporate WHERE CorporateID = ? AND CorporateIsActive = 'Y'", [$v['corporate_id']])->row();
                $rows[$k]['corporate_name'] = $corporate->CorporateName;
                }

                if($v['M_PatientBloodTypeCode']){
                $blood_type = $this->get_terminology('Patient', 'Patient.blood.type', $v['M_PatientBloodTypeCode']);
                $rows[$k]['M_PatientBloodTypeCode'] = $blood_type['code'];
                $rows[$k]['M_PatientBloodTypeDisplay'] = $blood_type['display'];
                $rows[$k]['M_PatientBloodTypeSystem'] = $blood_type['code_system'];
                }

                if($v['M_PatientBloodRhCode']){
                $blood_rh = $this->get_terminology('Patient', 'Patient.blood.rhesus', $v['M_PatientBloodRhCode']);
                $rows[$k]['M_PatientBloodRhCode'] = $blood_rh['code'];
                $rows[$k]['M_PatientBloodRhDisplay'] = $blood_rh['display'];
                $rows[$k]['M_PatientBloodRhSystem'] = $blood_rh['code_system'];
                }

                if($v['M_PatientEtnicCode']){
                $etnic = $this->get_terminology('Patient', 'Patient.etnicity', $v['M_PatientEtnicCode']);
                $rows[$k]['M_PatientEtnicCode'] = $etnic['code'];
                $rows[$k]['M_PatientEtnicDisplay'] = $etnic['display'];
                $rows[$k]['M_PatientEtnicSystem'] = $etnic['code_system'];
                }
                
                if($v['M_PatientEducationCode']){
                $education = $this->get_terminology('Person', 'Person.education', $v['M_PatientEducationCode']);
                $rows[$k]['M_PatientEducationCode'] = $education['code'];
                $rows[$k]['M_PatientEducationDisplay'] = $education['display'];
                $rows[$k]['M_PatientEducationSystem'] = $education['code_system'];
                }

                if($v['M_PatientReligionCode']){
                $religion = $this->get_terminology('Patient', 'Patient.religion.code', $v['M_PatientReligionCode']);
                $rows[$k]['M_PatientReligionCode'] = $religion['code'];
                $rows[$k]['M_PatientReligionDisplay'] = $religion['display'];
                $rows[$k]['M_PatientReligionSystem'] = $religion['code_system'];
                }
            }
		   return $rows[0];
      } 
     

      
   }

   function get_sender($sender_code) {
    $sql = "SELECT * FROM m_doctor WHERE M_DoctorCode = ?";
    $query = $this->db_smartone->query($sql, [$sender_code]);
    if(!$query){
      return null;
    }
    $rows = $query->result_array();
    if(count($rows) == 0){
      return null;
    }
    $sender = $rows[0];
    return [
      'sender_id' => $sender['M_DoctorID'],
      'sender_name' => $sender['M_DoctorName'],
      'sender_code' => $sender['M_DoctorCode']
    ];
   }


   function get_project($project_code) {
    $sql = "SELECT * FROM mgm_mcu WHERE Mgm_McuNumber = ?";
    $query = $this->db_smartone->query($sql, [$project_code]);
    if(!$query){
      return null;
    }
    $rows = $query->result_array();
    if(count($rows) == 0){
      return null;
    }
    $project = $rows[0];
    return [
      'project_id' => $project['Mgm_McuID'],
      'project_name' => $project['Mgm_McuLabel'],
      'project_code' => $project['Mgm_McuNumber']
    ];
   }

   function get_corportate($corporate_id) {
    $sql = "SELECT *
            FROM corporate
            WHERE CorporateOldCompanyID = ? AND CorporateIsActive = 'Y'";
    $query = $this->db_smartone->query($sql, [$corporate_id]);
    if(!$query){
      $this->insert_error_log(__FUNCTION__, $this->db_smartone->error(), $sql, json_encode($params));
      return null;
    }
    $rows = $query->result_array();
    if(count($rows) == 0){
      $this->insert_error_log(__FUNCTION__, "No rows found for corporate_id: $corporate_id", $sql, json_encode($params));
      return null;
    }
    return $rows[0];
   }

   function get_price_header($price_header_code) {
    $sql = "SELECT *
            FROM t_priceheader
            WHERE T_PriceHeaderCode = ? AND T_PriceHeaderIsActive = 'Y'";
    $query = $this->db_smartone->query($sql, [$price_header_code]);
    if(!$query){
      $this->insert_error_log(__FUNCTION__, $this->db_smartone->error(), $sql, json_encode($params));
      return null;
    }
    $rows = $query->result_array();
    if(count($rows) == 0){
      $this->insert_error_log(__FUNCTION__, "No rows found for price_header_id: $price_header_id", $sql, json_encode($params));
      return null;
    }
    return $rows[0];
   }

   function get_fisik_template($fisik_template_name) {
    $sql = "SELECT * 
            FROM fisik_template_mapping 
            WHERE FisikTemplateMappingName = ?
            AND FisikTemplateMappingIsActive = 'Y'";
    $query = $this->db_smartone->query($sql, [$fisik_template_name]);
    if(!$query){
      return null;
    }
    $rows = $query->result_array();
    if(count($rows) == 0){
      return null;
    }
    $fisik_template = $rows[0];
    return [
      'fisik_template_id' => $fisik_template['FisikTemplateMappingID'],
      'fisik_template_name' => $fisik_template['FisikTemplateMappingName']
    ];
   }

   function generate_walkin() {

    $sql = "SELECT *
            FROM inject_order_walk_in
            WHERE
            Trx_Status = 'N' AND Trx_T_OrderHeaderID = 0
            ORDER BY Trx_OWIID ASC
            LIMIT 10";

    $query = $this->db_onedev->query($sql);
    if (!$query) {
      echo $this->db_onedev->last_query();
      echo "Invalid query : \n";
      print_r($this->db_onedev->error());
      exit;
    }

    

    $rows = $query->result_array();
    foreach ($rows as $row) {
      $data_order = [];
      $data_patient = $this->get_patient_by_noreg($row['Trx_PID']);
      if(!$data_patient){
        echo "No patient found for noreg: {$row['Trx_PID']}\n";
        continue;
      }
      $patient_age = $this->gen_age($data_patient['M_PatientDOB'], date('Y-m-d'));

      $branch_code = $row['Trx_Branch_Code'];
      $branch = $this->get_branch($branch_code);
      if(!$branch){
        echo "No branch found for branch_code: {$branch_code}\n";
        continue;
      }
      $data_order['branch_id'] = $branch['M_BranchID'];
      $data_order['branch_name'] = $branch['M_BranchName'];
      $data_order['branch_code'] = $branch['M_BranchCodeLab'];
      $data_order['patient_age'] = $patient_age;

      $data_order['diagnosa'] = $row['Trx_Diagnosa'];
      $data_order['catatan_fo'] = '';
      $data_order['cito_id'] = 0;
      $data_order['mcu_pre_id'] = 0;
      $data_order['received_sample'] = 'N';
      $data_order['received_sample_time'] = '';
      $data_order['queue'] = '';
      $data_order['queue_id'] = 0;
      $data_order['is_cito'] = 'N';
      $data_order['patient_note'] = '';
      
      $data_order['req'] = [
        'status' => 'N',
        'reqs' => []
      ];
      $data_order['selected_language'] = '1';
      $data_order['selected_language_2'] = 0;

      if($row['Trx_Project_Code']){
         $selected_project = $this->get_project($row['Trx_Project_Code']);
         if(!$selected_project){
         echo "No project found for project_code: {$row['Trx_Project_Code']}\n";
         continue;
         }
      }
      
      $data_order['selected_project']['project_id'] = $selected_project['project_id'];
      $data_order['selected_project']['project_name'] = $selected_project['project_name'];
      $data_order['selected_project']['project_code'] = $selected_project['project_code'];
      if($row['Trx_Fisik_Template_Name']){
         $selected_fisik_template = $this->get_fisik_template($row['Trx_Fisik_Template_Name']);
         if(!$selected_fisik_template){
            echo "No fisik template found for fisik_template_name: {$row['Trx_Fisik_Template_Name']}\n";
            continue;
         }
      }
      $data_order['selected_fisik_template']['fisik_template_id'] = $selected_fisik_template['fisik_template_id'];
      $data_order['selected_fisik_template']['fisik_template_name'] = $selected_fisik_template['fisik_template_name'];
      $data_order['selected_patient'] = $data_patient;
      $corporate = $this->get_corportate($row['Trx_Corporate_LIS']);

      if(!$corporate){
        echo "No corporate found for corporate_id: {$row['Trx_Corporate_LIS']}\n";
        continue;
      }
      $data_order['selected_company'] = [];
      $data_order['selected_company']['corporate_id'] = $corporate['CorporateID'];
      $data_order['selected_company']['corporate_name'] = $corporate['CorporateName'];
      
      $price_header = $this->get_price_header($row['Trx_Price_Header']);
      if(!$price_header){
        echo "No price header found for price_header_code: {$row['Trx_Price_Header']}\n";
        continue;
      }
      $data_order['selected_mou'] = [];
      $data_order['selected_mou']['corporate_id'] = $corporate['CorporateID'];
      $data_order['selected_mou']['price_header_id'] = $price_header['T_PriceHeaderID'];
      $data_order['selected_mou']['price_header_name'] = $price_header['T_PriceHeaderName'];
      $data_order['selected_mou']['price_header_code'] = $price_header['T_PriceHeaderCode'];

      $sender = $this->get_sender($row['Trx_Doctor_Sender_Code']);
      if(!$sender){
        echo "No sender found for sender_id: {$row['Trx_Doctor_Sender_Code']}\n";
        continue;
      }
      $data_order['selected_sender'] = [];
      $data_order['selected_sender'] = $sender;
      $data_order['deliveries'] = [];
      $data_order['deliveries'][] = [
        'kelurahan' => '0',
        'address_id' => '0',
        'delivery_type' => '1',
        'delivery_id' => '1',
        'delivery_name' => 'Ambil Sendiri',
        'description' => '',
        'chex' => 'Y',
        'note' => '',
        'typeform' => 'origin',
        'type' => 'patient',
        'delivery_code' => 'PICKUP'
      ];

      $details = [];
      $test_ids = [];
      $test_names = [];
      $tests = explode(',', $row['Trx_Order_Tests']);
      foreach ($tests as $test) {
        // Trim spasi
        $test = trim($test);
        
        // Initialize variables
        $test_code = null;
        $packet_code = null;
        $is_packet = 'N';
        
        if(substr($test, 0, 2) == 'PN' || substr($test, 0, 2) == 'PR'){
          $is_packet = 'Y';
          $packet_code = $test; // Full code including PN/PR prefix
        }else{
          $test_code = $test;
        }

        $dt_test = $this->get_test_by_code($test_code, $packet_code, $price_header['T_PriceHeaderID']);
        if(!$dt_test){
          echo "No test found for test_code: $test (test_code: $test_code, packet_code: $packet_code, price_header_id: {$price_header['T_PriceHeaderID']})\n";
          continue;
        }

        if($is_packet == 'N'){
            $details[] = [
                "t_id" => $dt_test['T_TestID'],
                "t_name" => $dt_test['T_TestName'],
                "t_amount" => $dt_test['T_PriceAmount'],
                "t_discount" => $dt_test['T_PriceDisc'],
                "t_discount_rp" => $dt_test['T_PriceDiscRp'],
                "t_subtotal" => $dt_test['T_PriceSubTotal'],
                "t_total" => $dt_test['T_PriceTotal'],
                "t_cito" => 'N',
                "nat_test" => [$dt_test['Nat_TestID']],
                "t_req" => 'N',
                "t_reqnote" => '',
                "t_ispacket" => 'N',
                "t_packetid" => '0',
                "packet_type" => '',
                "packet_name" => '',
                "t_px_type" => 'PX'
            ];
            $test_ids[] = $dt_test['T_TestID'];
            $test_names[] = $dt_test['T_TestName'];
        }else{
            $packet_id = $dt_test['packet_id'];
            $packet_name = $dt_test['T_PacketName'];
            $packet_type = $dt_test['T_PacketType'];

            $childs = json_decode($dt_test['child_test'],true);
            foreach ($childs as $child) {
                $details[] = [
                    "t_id" => $child['T_TestID'],
                    "t_name" => $child['T_TestName'],
                    "t_amount" => $child['T_PriceAmount'],
                    "t_discount" => $child['T_PriceDisc'],
                    "t_discount_rp" => $child['T_PriceDiscRp'],
                    "t_subtotal" => $child['T_PriceSubTotal'],
                    "t_total" => $child['T_PriceTotal'],
                    "t_cito" => 'N',
                    "nat_test" => [$child['Nat_TestID']],
                    "t_req" => 'N',
                    "t_reqnote" => '',
                    "t_ispacket" => 'Y',
                    "t_packetid" => $packet_id,
                    "packet_type" => $packet_type,
                    "packet_name" => $packet_name,
                    "t_px_type" => 'PX'
                ];
                $test_ids[] = $child['T_TestID'];
                $test_names[] = $child['T_TestName'];
            }
            }
        }

      // Set detail array ke data_order
      $data_order['detail'] = $details;

        $data_order['trx_date'] = $row['Trx_Order_Date'].' '.date('H:i:s');
        $janji_hasil = date('Y-m-d H:i:s', strtotime($data_order['trx_date'] . ' +1 day'));
        $janji_hasil_tanggal = date('Y-m-d', strtotime($data_order['trx_date'] . ' +1 day'));
        $janji_hasil_waktu = date('H:i:s', strtotime($data_order['trx_date'] . ' +1 day'));
        $data_order['schedule'] = [
            [
                "JanjiHasil_Tanggal" => $janji_hasil_tanggal,
                "JanjiHasil_Waktu" => $janji_hasil_waktu,
                "JanjiHasil" => $janji_hasil,
                "TestIDs" => implode(',', $test_ids),
                "TestNames" => implode(',', $test_names),
                "OrderDetailIDs" => null,
                "ScheduleID" => null,
                "M_ScheduleFlagAtTime" => null,
                "M_ScheduleAtTime" => null,
                "TAT_Menit" => null,
                "M_ScheduleStartHourMinute" => null,
                "M_ScheduleEndHourMinute" => null
            ]
        ];

      $data_order['Trx_Payment_Type'] = isset($row['Trx_Payment_Type']) ? $row['Trx_Payment_Type'] : 'CASH';
      $data_order['Trx_Payment_Card_Bank'] = isset($row['Trx_Payment_Card_Bank']) ? $row['Trx_Payment_Card_Bank'] : '';
      $data_order['Trx_Payment_EDC_Bank'] = isset($row['Trx_Payment_EDC_Bank']) ? $row['Trx_Payment_EDC_Bank'] : '';
      $data_order['Trx_Payment_No_Rek'] = isset($row['Trx_Payment_No_Rek']) ? $row['Trx_Payment_No_Rek'] : '';
      $data_order['Trx_Payment_Total'] = isset($row['Trx_Payment_Total']) ? $row['Trx_Payment_Total'] : 0;

      $insert_order = $this->insert_order($data_order);
      if(!$insert_order['status']){
        echo "Error insert order: " . $insert_order['message'] . "\n";
        continue;
      }

      // Debug: print values before update
      echo "Updating Trx_OWIID: {$row['Trx_OWIID']} with order_id: {$insert_order['order_id']}, lab_number: {$insert_order['lab_number']}\n";

      $sql = "UPDATE inject_order_walk_in SET 
              Trx_Status = ?, 
              Trx_T_OrderHeaderID = ?,
              Trx_T_OrderHeaderLabNumber = ?
              WHERE Trx_OWIID = ?";
      $query = $this->db_onedev->query($sql, [
        'Y', 
        $insert_order['order_id'], 
        $insert_order['lab_number'],
        $row['Trx_OWIID']
      ]);
      if(!$query){
        $error = $this->db_onedev->error();
        echo "Error update status: " . print_r($error, true) . "\n";
        echo "SQL: $sql\n";
        echo "Params: " . print_r(['Y', $insert_order['order_id'], $insert_order['lab_number'], $row['Trx_OWIID']], true) . "\n";
        continue;
      }

      echo "Order inserted successfully: " . $data_patient['M_PatientNoReg'] . ' - ' . $row['Trx_Order_Date'] .' : '.$insert_order['lab_number']. "\n";
      
    }
   }

   function insert_order($data_order) {
      $userid = 55588;
      
    
      $branch_id = $data_order['branch_id'];
      $branch_code_lab = $data_order['branch_code'];
      
      // Get default doctors (PJ)
      $sql = "SELECT M_DoctorID, M_DoctorName, M_DoctorPjIsDefaultPJ
            FROM m_doctorpj
            JOIN m_doctor ON M_DoctorPjM_DoctorID = M_DoctorID AND M_DoctorIsActive = 'Y'
            JOIN m_user ON M_DoctorPjM_BranchID = M_UserLoginM_BranchID
            AND M_UserID = ?
            WHERE M_DoctorPjIsActive = 'Y'";
      $query = $this->db_smartone->query($sql, [$userid]);
      if(!$query){
         return ["status" => false, "message" => "Error get doctor PJ: " . $this->db_smartone->error()["message"]];
         $this->insert_error_log("insert_order", "Error get doctor PJ: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), []);
      }
      $doctorpjs = $query->result_array();
      if(count($doctorpjs) == 0){
         $sql = "SELECT M_DoctorID, M_DoctorName, M_DoctorPjIsDefaultPJ
               FROM m_doctorpj
               JOIN m_doctor ON M_DoctorPjM_DoctorID = M_DoctorID AND M_DoctorIsActive = 'Y'
               WHERE M_DoctorPjIsActive = 'Y' AND M_DoctorPjM_BranchID = 1";
         $query = $this->db_smartone->query($sql);
         if(!$query){
            return ["status" => false, "message" => "Error get doctor default: " . $this->db_smartone->error()["message"]];
            $this->insert_error_log("insert_order", "Error get doctor default: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), []);
         }
         $doctorpjs = $query->result_array();
      }

      $pj1 = $doctorpjs[0]['M_DoctorID'];
      $pj2 = count($doctorpjs) > 1 ? $doctorpjs[1]['M_DoctorID'] : 0;

      // Start transaction
      $this->db_smartone->trans_begin();

      // Generate lab number manually
      $nolab = $this->generate_lab_number_manual($branch_code_lab, $data_order['trx_date'], $branch_id);
      if(!$nolab){
         $this->db_smartone->trans_rollback();
         $this->insert_error_log("insert_order", "Error generate lab number ", '', [$branch_code_lab, $data_order['trx_date'], $branch_id]);
         return ["status" => false, "message" => "Error generate lab number"];
      }

      // Prepare header data
      $header = [];
      $header['T_OrderHeaderLabNumber'] = $nolab;
      $header['T_OrderHeaderM_BranchID'] = $branch_id;
      $header['T_OrderHeaderDate'] = date('Y-m-d H:i:s', strtotime($data_order['trx_date']));
      $header['T_OrderHeaderM_PatientID'] = $data_order['selected_patient']['M_PatientID'];
      $header['T_OrderHeaderM_PatientAge'] = $data_order['patient_age'];
      $header['T_OrderHeaderCorporateID'] = $data_order['selected_company']['corporate_id'];
      $header['T_OrderHeaderMgm_McuID'] = isset($data_order['selected_project']) ? $data_order['selected_project']['id'] : 0;
      $header['T_OrderHeaderPjM_DoctorID'] = $pj1;
      $header['T_OrderHeaderPj2M_DoctorID'] = $pj2;
      $header['T_OrderHeaderDiagnose'] = isset($data_order['diagnosa']) ? $data_order['diagnosa'] : '';
      $header['T_OrderHeaderFoNote'] = isset($data_order['catatan_fo']) ? $data_order['catatan_fo'] : '';
      $header['T_OrderHeaderFoNoteM_UserID'] = $userid;
      $header['T_OrderHeaderCreated'] = date('Y-m-d H:i:s');
      $header['T_OrderHeaderCreatedUserID'] = $userid;

      // Insert t_orderheader
      $fn_save_order_header = $this->db_smartone->insert('t_orderheader', $header);
      
      $header_id = $this->db_smartone->insert_id();
      if(!$header_id){
         $this->db_smartone->trans_rollback();
         $this->insert_error_log("insert_order", "Error insert t_orderheader: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$header]);
         return ["status" => false, "message" => "Error insert t_orderheader: " . $this->db_smartone->error()["message"]];
      }

      // Insert t_orderheaderaddon
      $fisik_template_mapping_id = isset($data_order['selected_fisik_template']['fisik_template_id']) ? $data_order['selected_fisik_template']['fisik_template_id'] : 0;
      $icd10_code = isset($data_order['selected_icd10']['code']) ? $data_order['selected_icd10']['code'] : '';
      $icd10_display = isset($data_order['selected_icd10']['display']) ? $data_order['selected_icd10']['display'] : '';
      $price_header_id = isset($data_order['selected_mou']['price_header_id']) ? $data_order['selected_mou']['price_header_id'] : 0;
      $cito_id = isset($data_order['cito_id']) ? $data_order['cito_id'] : 0;

      $sql = "INSERT INTO t_orderheaderaddon(
            T_OrderHeaderAddOnT_OrderHeaderID,
            T_OrderHeaderAddOnT_PriceHeaderID,
            T_OrderHeaderAddOnM_DoctorSenderID,
            T_OrderHeaderAddOnFisikTemplateMappingID,
            T_OrderHeaderAddOnICD10Code,
            T_OrderHeaderAddOnICD10Display,
            T_OrderHeaderAddOnReceiveSample,
            T_OrderHeaderAddOnReceiveSampleTime,
            T_OrderHeaderAddonNat_CitoID,
            T_OrderHeaderAddOnCreated,
            T_OrderHeaderAddOnCreatedUserID
         ) VALUES(?,?,?,?,?,?,?,?,?,NOW(),?)";
      $prm_orderheaderaddon = [
         $header_id,
         $price_header_id,
         $data_order['selected_sender']['sender_id'],
         $fisik_template_mapping_id,
         $icd10_code,
         $icd10_display,
         isset($data_order['received_sample']) && $data_order['received_sample'] == 'Y' ? 'Y' : 'N',
         isset($data_order['received_sample_time']) ? $data_order['received_sample_time'] : null,
         $cito_id,
         $userid
      ];

      $query_orderheaderaddon = $this->db_smartone->query($sql, $prm_orderheaderaddon);
      if(!$query_orderheaderaddon){
         $this->insert_error_log("insert_order", "Error insert t_orderheaderaddon: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$prm_orderheaderaddon]);
         $this->db_smartone->trans_rollback();
         //$this->insert_error_log("insert_order", "Error insert t_orderheaderaddon: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$prm_orderheaderaddon]);
         return ["status" => false, "message" => "Error insert t_orderheaderaddon: " . $this->db_smartone->error()["message"]];
      }

      // Prepare test orders (group packets and tests)
      $test_orders = $this->prepare_test_orders($data_order['detail']);

      // Save order detail order
      $save_order_detail_order = $this->save_orderdetail_order($test_orders, $header_id, $userid);
      if(!$save_order_detail_order['status']){
         $this->insert_error_log("insert_order", "Error save order detail order: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$test_orders]);
         $this->db_smartone->trans_rollback();
         return ["status" => false, "message" => $save_order_detail_order['message']];
      }

      // Save order detail
      $fn_save_order_detail = $this->save_order_detail($data_order['detail'], $header_id, $userid);
      if(!$fn_save_order_detail['status']){
         $this->insert_error_log("insert_order", "Error save order detail: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$data_order['detail']]);
         $this->db_smartone->trans_rollback();
         return ["status" => false, "message" => $fn_save_order_detail['message']];
      }

      // Generate sample lab
      $fn_generate_sample_lab = $this->generate_sample_lab($header_id, $userid);
      if(!$fn_generate_sample_lab['status']){
         $this->insert_error_log("insert_order", "Error generate sample lab: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$header_id, $userid]);
         $this->db_smartone->trans_rollback();
         return ["status" => false, "message" => $fn_generate_sample_lab['message']];
      }

      // Generate location
      $fn_generate_location = $this->generate_location($header_id, $userid);
      if(!$fn_generate_location['status']){
         $this->insert_error_log("insert_order", "Error generate location: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$header_id, $userid]);
         $this->db_smartone->trans_rollback();
         return ["status" => false, "message" => $fn_generate_location['message']];
      }

      // Generate req
      $fn_generate_req = $this->generate_req($header_id, $data_order['req'], $userid);
      if(!$fn_generate_req['status']){
         $this->insert_error_log("insert_order", "Error generate req: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$header_id, $data_order['req'], $userid]);
         $this->db_smartone->trans_rollback();
         return ["status" => false, "message" => $fn_generate_req['message']];
      }

      // Generate promise (default: trx_date + 1 day)
      $promise_datetime = date('Y-m-d H:i:s', strtotime($data_order['trx_date'] . ' +1 day'));
      
      // Get all test IDs
      $test_ids = array_column($data_order['detail'], 't_id');
      $test_ids_string = implode(',', $test_ids);

      // Insert single promise per order
      $sql = "INSERT INTO t_orderpromises(
         T_OrderPromisesT_OrderHeaderID,
         T_OrderPromisesDateTime,
         T_OrderPromisesTestIDs,
         T_OrderPromisesCreated,
         T_OrderPromisesCreatedUserID
      ) VALUES (?,?,?,NOW(),?)";
      $query = $this->db_smartone->query($sql, [
         $header_id,
         $promise_datetime,
         $test_ids_string,
         $userid
      ]);
      if(!$query){
         $this->insert_error_log("insert_order", "Error insert t_orderpromises: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$header_id, $promise_datetime, $test_ids_string, $userid]);
         $this->db_smartone->trans_rollback();
         return ["status" => false, "message" => "Error insert t_orderpromises: " . $this->db_smartone->error()["message"]];
      }
      $promise_id = $this->db_smartone->insert_id();

      // Link all order details to this promise
      $sql = "SELECT T_OrderDetailID 
            FROM t_orderdetail 
            WHERE T_OrderDetailT_OrderHeaderID = ? 
            AND T_OrderDetailIsActive = 'Y'
            AND T_OrderDetailT_TestIsPrice = 'Y'";
      $query_details = $this->db_smartone->query($sql, [$header_id]);
      if($query_details && $query_details->num_rows() > 0){
         $order_details = $query_details->result_array();
         foreach($order_details as $detail){
            $sql = "INSERT INTO t_orderdetail_promise(
               T_OrderDetailPromiseT_OrderHeaderID,
               T_OrderDetailPromiseT_OrderDetailID,
               T_OrderDetailPromiseT_OrderPromiseID,
               T_OrderDetailPromiseCreated,
               T_OrderDetailPromiseCreatedUserID
            ) VALUES (?, ?, ?, NOW(), ?)";
            $query = $this->db_smartone->query($sql, [$header_id, $detail['T_OrderDetailID'], $promise_id, $userid]);
            if(!$query){
               $this->insert_error_log("insert_order", "Error insert t_orderdetail_promise: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$header_id, $detail['T_OrderDetailID'], $promise_id, $userid]);
               $this->db_smartone->trans_rollback();
               return ["status" => false, "message" => "Error insert t_orderdetail_promise: " . $this->db_smartone->error()["message"]];
            }
         }
      }else{
         $this->insert_error_log("insert_order", "Error select t_orderdetail: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$header_id]);
         $this->db_smartone->trans_rollback();
         return ["status" => false, "message" => "Error select t_orderdetail: " . $this->db_smartone->error()["message"]];
      }

      // Save delivery
      $fn_order_delivery = $this->save_delivery($header_id, $data_order['deliveries'], $userid);
      if(!$fn_order_delivery['status']){
         $this->db_smartone->trans_rollback();
         return ["status" => false, "message" => $fn_order_delivery['message']];
      }

      // Save language
      $data_lang = array(
         array(
            'T_OrderHeaderLangT_OrderHeaderID' => $header_id,
            'T_OrderHeaderLangM_LangID' => 1,
            'T_OrderHeaderLangCreated' => date('Y-m-d H:i:s'),
            'T_OrderHeaderLangCreatedUserID' => $userid
         )
      );

      if(isset($data_order['selected_language_2']) && intval($data_order['selected_language_2']) > 0){
         $data_lang[] = array(
            'T_OrderHeaderLangT_OrderHeaderID' => $header_id,
            'T_OrderHeaderLangM_LangID' => $data_order['selected_language_2'],
            'T_OrderHeaderLangCreated' => date('Y-m-d H:i:s'),
            'T_OrderHeaderLangCreatedUserID' => $userid
         );
      }

      $save_lang = $this->db_smartone->insert_batch('t_orderheaderlang', $data_lang);
      if(!$save_lang){
         $this->insert_error_log("insert_order", "Error insert t_orderheaderlang: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$data_lang]);
         $this->db_smartone->trans_rollback();
         return ["status" => false, "message" => "Error insert t_orderheaderlang: " . $this->db_smartone->error()["message"]];
      }

      // Update t_ordersample if received sample
      $received_sample = isset($data_order['received_sample']) && $data_order['received_sample'] == 'Y' ? 'Y' : 'N';
      $received_sample_time = isset($data_order['received_sample_time']) ? $data_order['received_sample_time'] : '0000-00-00 00:00:00';
      if($received_sample == 'Y' && $received_sample_time != '0000-00-00 00:00:00'){
         $received_sample_time = date('Y-m-d H:i:s', strtotime($received_sample_time));
         $sql = "UPDATE t_ordersample SET 
               T_OrderSampleSampling = 'Y', 
               T_OrderSampleSamplingDate = DATE(?), 
               T_OrderSampleSamplingTime = TIME(?), 
               T_OrderSampleSamplingUserID = ?, 
               T_OrderSampleReceive = 'Y', 
               T_OrderSampleReceiveDate = DATE(?), 
               T_OrderSampleReceiveTime = TIME(?), 
               T_OrderSampleReadyToProcessDateTime = ?, 
               T_OrderSampleProcessing = 'Y',
               T_OrderSampleProcessingTime = TIME(?),
               T_OrderSampleProcessingUserID = ?,
               T_OrderSampleReceiveUserID = ?,
               T_OrderSampleProcessingDate = DATE(?)
            WHERE T_OrderSampleT_OrderHeaderID = ? AND T_OrderSampleIsActive = 'Y'";
         $query = $this->db_smartone->query($sql, [
            $received_sample_time, $received_sample_time, $userid,
            $received_sample_time, $received_sample_time, $received_sample_time,
            $received_sample_time, $userid, $userid, $received_sample_time, $header_id
         ]);
         if(!$query){
            $this->insert_error_log("insert_order", "Error update t_ordersample: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$received_sample_time, $received_sample_time, $userid, $received_sample_time, $received_sample_time, $received_sample_time, $received_sample_time, $userid, $userid, $received_sample_time, $header_id]);
            $this->db_smartone->trans_rollback();
            return ["status" => false, "message" => "Error update t_ordersample: " . $this->db_smartone->error()["message"]];
         }
      }

      // Insert order log
      $sql = "SELECT t_orderdetail.*, t_orderheader.*
            FROM t_orderdetail 
            JOIN t_test ON T_OrderDetailT_TestID = T_TestID AND T_TestIsActive = 'Y' AND T_TestIsPrice = 'Y'
            JOIN t_orderheader ON T_OrderDetailT_OrderHeaderID = T_OrderHeaderID 
            WHERE T_OrderDetailT_OrderHeaderID = ? AND T_OrderDetailIsActive = 'Y'";
      $query_orderdetail = $this->db_smartone->query($sql, [$header_id]);
      if(!$query_orderdetail){
         $this->insert_error_log("insert_order", "Error select t_orderdetail: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$header_id]);
         $this->db_smartone->trans_rollback();
         return ["status" => false, "message" => "Error select t_orderdetail: " . $this->db_smartone->error()["message"]];
      }
      $data_log = $query_orderdetail->result_array();

      $sqllog = "INSERT INTO order_log(
            orderLogType,	
            orderLogT_OrderHeaderID,
            orderLogJSONBefore,
            orderLogJSONAfter,
            orderLogCreated,	
            orderLogUserID)
         VALUES ('REGISTER',?,'',?,now(),?)";
      $querylog = $this->db_smartone->query($sqllog, [$header_id, json_encode($data_log), $userid]);
      if(!$querylog){
         $this->insert_error_log("insert_order", "Error insert order_log: " . $this->db_smartone->error()["message"], $this->db_smartone->last_query(), [$header_id, json_encode($data_log), $userid]);
         $this->db_smartone->trans_rollback();
         return ["status" => false, "message" => "Error insert order_log: " . $this->db_smartone->error()["message"]];
      }

      // Commit transaction
      $this->db_smartone->trans_commit();

      // Generate QR codes after successful commit
      $genqrcode = $this->genqrcode($nolab, $header_id);
      $genpatientqrcode = $this->genpatientqrcode($nolab);

      // Check if fisik template exists and generate form QR code
      if($fisik_template_mapping_id > 0){
         $sql = "SELECT COUNT(DISTINCT FisikTemplateID) as jumlah_fisik_template
                 FROM fisik_template_mapping 
                 JOIN fisik_template_mapping_detail ON FisikTemplateMappingDetailFisikTemplateMappingID = FisikTemplateMappingID AND FisikTemplateMappingDetailIsActive = 'Y'
                 JOIN fisik_template ON FisikTemplateID = FisikTemplateMappingDetailFisikTemplateID AND FisikTemplateIsActive = 'Y' AND
                 FisikTemplateType = 'Riwayat'
                 WHERE FisikTemplateMappingID = ? AND FisikTemplateMappingIsActive = 'Y'";
         $query_fisik_template_mapping = $this->db_smartone->query($sql, [$fisik_template_mapping_id]);
         
         if($query_fisik_template_mapping){
            $dt_fisik_template_mapping = $query_fisik_template_mapping->row_array();
            $jumlah_fisik_template = $dt_fisik_template_mapping['jumlah_fisik_template'];

            if($jumlah_fisik_template > 0){
               $pre_registerid = 0;
               $genformqrcode = '';
               $uuid = '';
               $form_code = '';
               $gen_uuid = $this->generate_code_form($pre_registerid, $header_id, $userid);
               if ($gen_uuid && isset($gen_uuid['uuid']) && $gen_uuid['uuid'] != '') {
                  $uuid = $gen_uuid['uuid'];
                  $form_code = $gen_uuid['code'];
                  $genformqrcode = $this->genformqrcode($gen_uuid['uuid']);
               }
            }
         }
      }

      if(isset($data_order['Trx_Payment_Total']) && floatval($data_order['Trx_Payment_Total']) > 0){
         $this->save_payment($header_id, $data_order['Trx_Payment_Type'], $data_order['Trx_Payment_Card_Bank'], $data_order['Trx_Payment_EDC_Bank'], $data_order['Trx_Payment_No_Rek'], $data_order['Trx_Payment_Total'], $userid);
      }

      return [
         "status" => true,
         "message" => "Order berhasil disimpan",
         "order_id" => $header_id,
         "lab_number" => $nolab,
         "order_date" => $header['T_OrderHeaderDate']
      ];
   }

    function save_payment($header_id, $payment_type, $payment_card_bank_code, $payment_edc_bank_code, $payment_no_rek, $payment_total, $userid) {
      // Get payment type ID
      $sql = "SELECT M_PaymentTypeID FROM m_paymenttype WHERE M_PaymentTypeCode = ? AND M_PaymentTypeIsActive = 'Y' LIMIT 1";
      $query = $this->db_smartone->query($sql, [$payment_type]);
      if(!$query || $query->num_rows() == 0){
         echo "Payment type not found: $payment_type\n";
         return false;
      }
      $payment_type_id = $query->row_array()['M_PaymentTypeID'];

      // Use provided payment total
      $amount = floatval($payment_total);
      $actual = 0;
      $change = 0;

      // Initialize bank IDs
      $card_bank_id = 0;
      $edc_bank_id = 0;
      $bank_account_id = 0;

      // Process bank account for non-CASH payment
      if($payment_type != 'CASH'){
         // Get card bank ID if provided
         if(!empty($payment_card_bank_code)){
            $sql = "SELECT Nat_BankID FROM nat_bank WHERE Nat_BankCode = ? AND Nat_BankIsActive = 'Y' LIMIT 1";
            $query = $this->db_smartone->query($sql, [$payment_card_bank_code]);
            if($query && $query->num_rows() > 0){
               $card_bank_id = $query->row_array()['Nat_BankID'];
            }
         }

         // Get EDC/account bank ID if provided
         if(!empty($payment_edc_bank_code)){
            $sql = "SELECT Nat_BankID FROM nat_bank WHERE Nat_BankCode = ? AND Nat_BankIsActive = 'Y' LIMIT 1";
            $query = $this->db_smartone->query($sql, [$payment_edc_bank_code]);
            if($query && $query->num_rows() > 0){
               $edc_bank_id = $query->row_array()['Nat_BankID'];
            }
         }

         // For TRANSFER, use edc_bank_id as account selector
         if($payment_type == 'TRANSFER' && $edc_bank_id > 0){
            $bank_account_id = $edc_bank_id;
         }

         // Check and create bank account if needed (for no rekening yang diinput)
         $bank_id_for_account = $card_bank_id > 0 ? $card_bank_id : ($edc_bank_id > 0 ? $edc_bank_id : 0);
         if($bank_id_for_account > 0 && !empty($payment_no_rek)){
            // Check if bank account exists
            $sql = "SELECT M_BankAccountID FROM m_bank_account 
                    WHERE M_BankAccountNat_BankID = ? 
                    AND M_BankAccountNo = ? 
                    AND M_BankAccountIsActive = 'Y' 
                    LIMIT 1";
            $query = $this->db_smartone->query($sql, [$bank_id_for_account, $payment_no_rek]);
            
            if($query && $query->num_rows() > 0){
               $existing_account = $query->row_array()['M_BankAccountID'];
               echo "Bank account already exists: $existing_account\n";
            } else {
               // Insert new bank account
               $sql = "INSERT INTO m_bank_account (
                        M_BankAccountNat_BankID,
                        M_BankAccountNo,
                        M_BankAccountIsActive,
                        M_BankAccountUserID,
                        M_BankAccountCreated,
                        M_BankAccountLastUpdated,
                        M_BankAccountIsDefault,
                        M_BankAccountName
                     ) VALUES (?, ?, 'Y', ?, NOW(), NOW(), 'N', 'Auto Generated')";
               $query = $this->db_smartone->query($sql, [$bank_id_for_account, $payment_no_rek, $userid]);
               if($query){
                  $new_account_id = $this->db_smartone->insert_id();
                  echo "New bank account created: $new_account_id\n";
               }
            }
         }
      } else {
         // For CASH payment
         $actual = $amount;
         $change = 0; // Default no change
      }

      // Insert f_payment
      $sql = "INSERT INTO f_payment (
               F_PaymentT_OrderHeaderID,
               F_PaymentDate,
               F_PaymentTotal,
               F_PaymentCreated,
               F_PaymentM_UserID
            ) VALUES (?, CURDATE(), ?, NOW(), ?)";
      $query = $this->db_smartone->query($sql, [$header_id, $amount, $userid]);
      
      if(!$query){
         echo "Error insert f_payment: " . print_r($this->db_smartone->error(), true) . "\n";
         return false;
      }
      
      $payment_id = $this->db_smartone->insert_id();

      // Insert f_paymentdetail based on payment type
      if($payment_type == 'CASH'){
         $sql = "INSERT INTO f_paymentdetail (
                  F_PaymentDetailF_PaymentID,
                  F_PaymentDetailM_PaymentTypeID,
                  F_PaymentDetailAmount,
                  F_PaymentDetailActual,
                  F_PaymentDetailChange,
                  F_PaymentDetailCreated,
                  F_PaymentDetailLastUpdated,
                  F_PaymentDetailUserID
               ) VALUES (?, ?, ?, ?, ?, NOW(), NOW(), ?)";
         $query = $this->db_smartone->query($sql, [
            $payment_id,
            $payment_type_id,
            $amount,
            $actual,
            $change,
            $userid
         ]);
      } else {
         // Non-CASH: DEBIT, CREDIT, TRANSFER
         $sql = "INSERT INTO f_paymentdetail (
                  F_PaymentDetailF_PaymentID,
                  F_PaymentDetailM_PaymentTypeID,
                  F_PaymentDetailAmount,
                  F_PaymentDetailActual,
                  F_PaymentDetailChange,
                  F_PaymentDetailCardNat_BankID,
                  F_PaymentDetailEDCNat_BankID,
                  F_PaymentDetailM_BankAccountID,
                  F_PaymentDetailCreated,
                  F_PaymentDetailLastUpdated,
                  F_PaymentDetailUserID
               ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW(), ?)";
         $query = $this->db_smartone->query($sql, [
            $payment_id,
            $payment_type_id,
            $amount,
            $actual,
            $change,
            $card_bank_id,
            0, // EDC always 0 in reference
            $edc_bank_id, // This is actually account_id for TRANSFER
            $userid
         ]);
      }

      if(!$query){
         echo "Error insert f_paymentdetail: " . print_r($this->db_smartone->error(), true) . "\n";
         return false;
      }

      // Get order total for last_statuspayment
      $sql = "SELECT T_OrderHeaderTotal FROM t_orderheader WHERE T_OrderHeaderID = ? LIMIT 1";
      $query = $this->db_smartone->query($sql, [$header_id]);
      $order_total = 0;
      if($query && $query->num_rows() > 0){
         $order_total = $query->row_array()['T_OrderHeaderTotal'];
      }

      // Calculate payment status
      $sql = "SELECT SUM(F_PaymentTotal) as total_payment
              FROM f_payment 
              WHERE F_PaymentT_OrderHeaderID = ? 
              AND F_PaymentIsActive = 'Y'";
      $query = $this->db_smartone->query($sql, [$header_id]);
      $total_payment = 0;
      if($query && $query->num_rows() > 0){
         $result = $query->row_array();
         $total_payment = $result['total_payment'] ? floatval($result['total_payment']) : 0;
      }

      $paid = $total_payment;
      $unpaid = $order_total - $total_payment;
      $lunas = ($total_payment >= $order_total) ? 'Y' : 'N';

      // Insert or update last_statuspayment
      $sql = "SELECT Last_StatusPaymentID
              FROM last_statuspayment
              WHERE Last_StatusPaymentT_OrderHeaderID = ? 
              AND Last_StatusPaymentIsActive = 'Y'
              LIMIT 1";
      $query = $this->db_smartone->query($sql, [$header_id]);
      
      if($query && $query->num_rows() > 0){
         // Update existing
         $last_payment_id = $query->row_array()['Last_StatusPaymentID'];
         $sql = "UPDATE last_statuspayment SET 
                  Last_StatusPaymentPaid = ?, 
                  Last_StatusPaymentUnpaid = ?, 
                  Last_StatusPaymentIsLunas = ? 
                  WHERE Last_StatusPaymentID = ?";
         $this->db_smartone->query($sql, [$paid, $unpaid, $lunas, $last_payment_id]);
      } else {
         // Insert new
         $sql = "INSERT INTO last_statuspayment (
                  Last_StatusPaymentT_OrderHeaderID,
                  Last_StatusPaymentBillTotal,
                  Last_StatusPaymentPaid,
                  Last_StatusPaymentUnpaid,
                  Last_StatusPaymentIsLunas,
                  Last_StatusPaymentCreated,
                  Last_StatusPaymentUserID
               ) VALUES (?, ?, ?, ?, ?, NOW(), ?)";
         $this->db_smartone->query($sql, [
            $header_id,
            $order_total,
            $paid,
            $unpaid,
            $lunas,
            $userid
         ]);
      }

      echo "Payment saved successfully: Payment ID = $payment_id, Lunas = $lunas\n";
      return true;
   }

   function generate_lab_number_manual($branch_code_lab, $trx_date, $branch_id) {
      // Format: R26012700007
      // R = branch_code_lab
      // 26 = 2 digit tahun
      // 01 = 2 digit bulan
      // 27 = 2 digit tanggal
      // 00007 = counter (4 digit)

      $date = date('Y-m-d', strtotime($trx_date));
      $year = date('y', strtotime($trx_date));
      $month = date('m', strtotime($trx_date));
      $day = date('d', strtotime($trx_date));

      // Get max counter for today
      $sql = "SELECT MAX(CAST(SUBSTRING(T_OrderHeaderLabNumber, -4) AS UNSIGNED)) as max_counter
            FROM t_orderheader
            WHERE DATE(T_OrderHeaderDate) = ? 
            AND T_OrderHeaderM_BranchID = ?
            AND T_OrderHeaderLabNumber LIKE ?";
      $query = $this->db_smartone->query($sql, [$date, $branch_id, $branch_code_lab . $year . $month . $day . '%']);
      
      if(!$query){
         return false;
      }

      $result = $query->row_array();
      $counter = isset($result['max_counter']) && $result['max_counter'] ? intval($result['max_counter']) + 1 : 1;
      $counter_str = str_pad($counter, 4, '0', STR_PAD_LEFT);

      $lab_number = $branch_code_lab . $year . $month . $day . $counter_str;

      return $lab_number;
   }

   function prepare_test_orders($details) {
      $test_orders = [];
      foreach($details as $k => $v){
         if(isset($v['t_ispacket']) && $v['t_ispacket'] == 'Y'){
            // Check if packet with same packetid already exists
            $packet_exists = false;
            foreach($test_orders as $test_order){
               if($test_order['packet_id'] == $v['t_packetid']){
                  $packet_exists = true;
                  break;
               }
            }
            if(!$packet_exists){
               $test_orders[] = array(
                  't_testid' => '0',
                  't_testname' => '',
                  'is_packet' => 'Y',
                  'packet_id' => $v['t_packetid'],
                  'packet_type' => $v['packet_type'],
                  'packet_name' => $v['packet_name']
               );
            }
         }else{
            // Check if test with same testid already exists
            $test_exists = false;
            foreach($test_orders as $test_order){
               if($test_order['t_testid'] == $v['t_id']){
                  $test_exists = true;
                  break;
               }
            }
            if(!$test_exists){
               $test_orders[] = array(
                  't_testid' => $v['t_id'],
                  't_testname' => $v['t_name'],
                  'is_packet' => 'N',
                  'packet_id' => '0',
                  'packet_type' => '',
                  'packet_name' => ''
               );
            }
         }
      }
      return $test_orders;
   }

   function save_orderdetail_order($test_orders, $header_id, $userid){
      $return = [
         "status" => true,
         "message" => "",
         "data" => []
      ];
      foreach($test_orders as $test_order){
         $sql = "INSERT INTO t_orderdetailorder(
               T_OrderDetailOrderT_OrderHeaderID,
               T_OrderDetailOrderT_TestID,
               T_OrderDetailOrderT_TestName,
               T_OrderDetailOrderIsPacket,
               T_OrderDetailOrderPacketType,
               T_OrderDetailOrderT_PacketID,
               T_OrderDetailOrderT_PacketName,
               T_OrderDetailOrderCreated,
               T_OrderDetailOrderCreatedUserID
         ) VALUES(?,?,?,?,?,?,?,NOW(),?)";
         $query = $this->db_smartone->query($sql, [
            $header_id, 
            $test_order['t_testid'], 
            $test_order['t_testname'], 
            $test_order['is_packet'], 
            $test_order['packet_type'], 
            $test_order['packet_id'], 
            $test_order['packet_name'], 
            $userid
         ]);
         if(!$query){
            $return['status'] = false;
            $return['message'] = "Terjadi kesalahan saat menyimpan data detail order: " . $this->db_smartone->error()["message"];
            return $return;
         }
      }

      $return['status'] = true;
      $return['message'] = "Data detail order berhasil disimpan";
      return $return;
   }

   function save_order_detail($details, $header_id, $userid){
      $return = [
         "status" => true,
         "message" => "",
         "data" => []
      ];

      $sql = "SELECT T_OrderDetailOrderID as d_oid,
            T_OrderDetailOrderT_TestID as d_otid,
            T_OrderDetailOrderIsPacket as d_oispacket,
            T_OrderDetailOrderT_PacketID as d_opacketid
            FROM t_orderdetailorder
            WHERE 
            T_OrderDetailOrderT_OrderHeaderID = ? AND
            T_OrderDetailOrderIsActive = 'Y'";
      $query = $this->db_smartone->query($sql, [$header_id]);
      if(!$query){
         $return['status'] = false;
         $return['message'] = "Error select t_orderdetailorder: " . $this->db_smartone->error()["message"];
         return $return;
      }

      $orderdetailorders = $query->result_array();
      if(count($orderdetailorders) == 0){
         $return['status'] = false;
         $return['message'] = "Data detail order tidak ditemukan";
         return $return;
      }

      foreach($details as $k => $v){
         $detail_order = [];
         foreach($orderdetailorders as $orderdetailorder){
            if(($orderdetailorder['d_oispacket'] == 'N' && intval($orderdetailorder['d_otid']) == intval($v['t_id'])) ||
               ($orderdetailorder['d_oispacket'] == 'Y' && intval($orderdetailorder['d_opacketid']) == intval($v['t_packetid']))){
               $detail_order = $orderdetailorder;
               break;
            }
         }

         $detail_order_id = $detail_order['d_oid'];
         $insert_order_detail = $this->insert_order_detail($header_id, $detail_order_id, $v, $userid);

         if(!$insert_order_detail['status']){
            $return['status'] = false;
            $return['message'] = $insert_order_detail['message'];
            return $return;
         }
      }

      return $return;
   }

   function insert_order_detail($header_id, $detail_order_id, $detail, $userid){
      $result = [
         'status' => true,
         'message' => 'Success',
         'test_name' => isset($detail['t_name']) ? $detail['t_name'] : '',
         'test_id' => isset($detail['t_id']) ? $detail['t_id'] : ''
      ];

      // Get test data
      $sql = "SELECT * FROM t_test WHERE T_TestID = ? AND T_TestIsActive = 'Y' LIMIT 1";
      $query = $this->db_smartone->query($sql, [$detail['t_id']]);

      if (!$query) {
         $result['status'] = false;
         $result['message'] = 'Terjadi kesalahan saat mengambil data test: ' . $this->db_smartone->error()["message"];
         return $result;
      }

      $rows_test = $query->result_array();
      if(count($rows_test) == 0){
         $result['status'] = false;
         $result['message'] = 'Test tidak ditemukan';
         return $result;
      }

      $dt_test = $rows_test[0];

      // Get unit data
      $sql = "SELECT Nat_UnitID, Nat_UnitName 
            FROM t_test
            JOIN nat_test ON T_TestNat_TestID = Nat_TestID
            JOIN nat_unit ON Nat_TestNat_UnitID = Nat_UnitID
            WHERE T_TestID = ? LIMIT 1";
      $query = $this->db_smartone->query($sql, [$detail['t_id']]);
      if(!$query){
         $result['status'] = false;
         $result['message'] = 'Unit tidak ditemukan: ' . $this->db_smartone->error()["message"];
         return $result;
      }
      $dt_unit = $query->row_array();

      // Insert order detail
      $sql_orderdetail = "INSERT INTO t_orderdetail(
         T_OrderDetailT_OrderHeaderID,
         T_OrderDetailT_OrderDetailOrderID,
         T_OrderDetailT_TestID,
         T_OrderDetailT_TestCode,
         T_OrderDetailT_TestSasCode,
         T_OrderDetailT_TestName,
         T_OrderDetailT_TestIsResult,
         T_OrderDetailT_TestIsPanel,
         T_OrderDetailT_TestIsPanelChildren,
         T_OrderDetailT_TestIsPanelChildrenPrintNota,
         T_OrderDetailT_TestIsPrice,
         T_OrderDetailIsCito,
         T_OrderDetailPrice,
         T_OrderDetailPriceForDisc,
         T_OrderDetailDisc,
         T_OrderDetailDiscAmount,
         T_OrderDetailDiscTotal,
         T_OrderDetailTotal,
         T_OrderDetailReq,
         T_OrderDetailReqNote,
         T_OrderDetailNat_UnitID,
         T_OrderDetailNat_UnitName,
         T_OrderDetailCreatedUserID,
         T_OrderDetailCreated
      ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,'N','',?,?,?,NOW())";

      $prm_orderdetail = [
         $header_id,
         $detail_order_id,
         $dt_test['T_TestID'],
         $dt_test['T_TestCode'],
         $dt_test['T_TestSasCode'],
         $dt_test['T_TestName'],
         $dt_test['T_TestIsResult'],
         'N',
         'N',
         'N',
         $dt_test['T_TestIsPrice'],
         isset($detail['t_cito']) ? $detail['t_cito'] : 'N',
         $dt_test['T_TestIsPrice'] == 'N' ? 0 : $detail['t_amount'],
         $dt_test['T_TestIsPrice'] == 'N' ? 0 : $detail['t_amount'],
         $dt_test['T_TestIsPrice'] == 'N' ? 0 : $detail['t_discount'],
         $dt_test['T_TestIsPrice'] == 'N' ? 0 : $detail['t_discount_rp'],
         $dt_test['T_TestIsPrice'] == 'N' ? 0 : $detail['t_subtotal'],
         $dt_test['T_TestIsPrice'] == 'N' ? 0 : $detail['t_total'],
         $dt_unit['Nat_UnitID'],
         $dt_unit['Nat_UnitName'],
         $userid
      ];

      $query_orderdetail = $this->db_smartone->query($sql_orderdetail, $prm_orderdetail);
      if (!$query_orderdetail) {
         $result['status'] = false;
         $result['message'] = 'Terjadi kesalahan saat menyimpan data detail order: ' . $this->db_smartone->error()["message"];
         return $result;
      }

      // Get child tests
      $sql = "SELECT * FROM t_test WHERE T_TestSasCode LIKE ? AND T_TestIsActive = 'Y' AND T_TestSasCode != ?";
      $query = $this->db_smartone->query($sql, [$dt_test['T_TestSasCode'] . '%', $dt_test['T_TestSasCode']]);

      if (!$query) {
         $result['status'] = false;
         $result['message'] = 'Terjadi kesalahan saat mengambil data child test: ' . $this->db_smartone->error()["message"];
         return $result;
      }

      $rows_test_child = $query->result_array();
      if (count($rows_test_child) > 0) {
         foreach ($rows_test_child as $test_child) {
            $sql = "SELECT Nat_UnitID, Nat_UnitName 
                  FROM t_test
                  JOIN nat_test ON T_TestNat_TestID = Nat_TestID
                  JOIN nat_unit ON Nat_TestNat_UnitID = Nat_UnitID
                  WHERE T_TestID = ? LIMIT 1";
            $dt_child_unit = $this->db_smartone->query($sql, [$test_child['T_TestID']])->row_array();
            
            $sql_orderdetail = "INSERT INTO t_orderdetail(
               T_OrderDetailT_OrderHeaderID,
               T_OrderDetailT_OrderDetailOrderID,
               T_OrderDetailT_TestID,
               T_OrderDetailT_TestCode,
               T_OrderDetailT_TestSasCode,
               T_OrderDetailT_TestName,
               T_OrderDetailT_TestIsResult,
               T_OrderDetailT_TestIsPanel,
               T_OrderDetailT_TestIsPanelChildren,
               T_OrderDetailT_TestIsPanelChildrenPrintNota,
               T_OrderDetailT_TestIsPrice,
               T_OrderDetailIsCito,
               T_OrderDetailPrice,
               T_OrderDetailPriceForDisc,
               T_OrderDetailDisc,
               T_OrderDetailDiscAmount,
               T_OrderDetailDiscTotal,
               T_OrderDetailTotal,
               T_OrderDetailReq,
               T_OrderDetailReqNote,
               T_OrderDetailCreated,
               T_OrderDetailNat_UnitID,
               T_OrderDetailNat_UnitName,
               T_OrderDetailCreatedUserID
            ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,'N','',NOW(),?,?,?)";

            $prm_orderdetail = [
               $header_id,
               $detail_order_id,
               $test_child['T_TestID'],
               $test_child['T_TestCode'],
               $test_child['T_TestSasCode'],
               $test_child['T_TestName'],
               $test_child['T_TestIsResult'],
               'N',
               'N',
               'N',
               $test_child['T_TestIsPrice'],
               'N',
               0, 0, 0, 0, 0, 0,
               $dt_child_unit['Nat_UnitID'],
               $dt_child_unit['Nat_UnitName'],
               $userid
            ];

            $query_child = $this->db_smartone->query($sql_orderdetail, $prm_orderdetail);
            if (!$query_child) {
               $result['status'] = false;
               $result['message'] = 'Terjadi kesalahan saat menyimpan data child test: ' . $this->db_smartone->error()["message"];
               return $result;
            }
         }
      }

      return $result;
   }

   function generate_sample_lab($header_id, $userid){
      $result = [
         'status' => true,
         'message' => 'Success'
      ];

      $counter_barcode = 1;
      $sql = "SELECT T_OrderHeaderLabNumber, 
               T_TestID, 
               T_SampleTypeID, 
               T_SampleTypeSuffix, 
               T_SampleStationIsNonLab, 
               T_SampleStationID
            FROM t_orderheader
            JOIN t_orderdetail ON t_orderheaderid = t_orderdetailt_orderheaderid AND t_orderdetailIsActive = 'Y'
            JOIN t_test ON t_orderdetailt_testid = t_testid AND T_TestIsResult = 'Y'
            JOIN t_sampletype ON T_TestT_SampleTypeID = T_SampleTypeID
            JOIN t_bahan ON T_SampleTypeT_BahanID = T_BahanID
            JOIN t_samplestation ON T_BahanT_SampleStationID = T_SampleStationID
            JOIN group_resultdetail ON Group_ResultDetailT_TestID = T_TestID AND Group_ResultDetailIsActive = 'Y'
            JOIN group_result ON Group_ResultID = Group_ResultDetailGroup_ResultID AND Group_ResultIsActive = 'Y' AND 
            Group_ResultFlagNonLab = 'N'
            WHERE T_OrderHeaderID = ?
            GROUP BY T_SampleTypeID";
      $qry = $this->db_smartone->query($sql, [$header_id]);
      if (!$qry) {
         $result['status'] = false;
         $result['message'] = 'Terjadi kesalahan saat mengambil data sample: ' . $this->db_smartone->error()["message"];
         return $result;
      }

      $data_samples = $qry->result_array();

      if (count($data_samples) > 0) {
         foreach ($data_samples as $k => $v) {
            $counter_barcode = 1;
            $lab_no = $v['T_OrderHeaderLabNumber'];
            $test_id = $v['T_TestID'];
            $sample_id = $v['T_SampleTypeID'];
            $sample_code = $v['T_SampleTypeSuffix'];
            $barcode = $lab_no . $sample_code;
            $isnonlab = $v['T_SampleStationIsNonLab'];
            $samplestation_id = $v['T_SampleStationID'];

            if ($counter_barcode == 1) {
               $barcode = $barcode . $counter_barcode;
               $sql = "INSERT INTO t_barcodelab(
                  T_BarcodeLabT_OrderHeaderID,
                  T_BarcodeLabBarcode,
                  T_BarcodeLabT_SampleTypeID,
                  T_BarcodeLabCounter)
                  VALUES (?,?,?,?)";
               $prm_barcode = [$header_id, $barcode, $sample_id, $counter_barcode];
               $qry = $this->db_smartone->query($sql, $prm_barcode);

               if (!$qry) {
                  $result['status'] = false;
                  $result['message'] = 'Terjadi kesalahan saat menyimpan data barcode lab: ' . $this->db_smartone->error()["message"];
                  return $result;
               }

               $last_id_barcode = $this->db_smartone->insert_id();
               if ($isnonlab == "") {
                  $sql = "INSERT INTO t_ordersample(
                     T_OrderSampleT_OrderHeaderID,
                     T_OrderSampleT_SampleTypeID,
                     T_OrderSampleT_BarcodeLabID,
                     T_OrderSampleBarcode,
                     T_OrderSampleT_SampleStationID,
                     T_OrderSampleCreated)
                     VALUES (?,?,?,?,?,NOW())";
                  $prm_ordersample = [$header_id, $sample_id, $last_id_barcode, $barcode, $samplestation_id];
                  $qry = $this->db_smartone->query($sql, $prm_ordersample);
                  if (!$qry) {
                     $result['status'] = false;
                     $result['message'] = 'Terjadi kesalahan saat menyimpan data sample: ' . $this->db_smartone->error()["message"];
                     return $result;
                  }
               }
            }

            $sql = "SELECT MAX(T_BarcodeLabCounter) as ctr
                  FROM t_barcodelab 
                  WHERE T_BarcodeLabT_OrderHeaderID = ? AND 
                  T_BarcodeLabBarcode LIKE CONCAT(?, '%')
                  AND T_BarcodeLabIsActive = 'Y'";
            $qry = $this->db_smartone->query($sql, [$header_id, $barcode]);

            if ($qry) {
               $ctr = $qry->row()->ctr;
               $counter_barcode = $ctr + 1;
            } else {
               $result['status'] = false;
               $result['message'] = 'Terjadi kesalahan saat mengambil data counter barcode: ' . $this->db_smartone->error()["message"];
               return $result;
            }
         }
      }

      return $result;
   }

   function generate_location($header_id, $userid){
      $result = [
         'status' => true,
         'message' => 'Success'
      ];

      $sql = "SELECT T_SampleStationID, T_SampleStationName
            FROM t_orderdetail
            JOIN t_test ON T_OrderDetailT_TestID = T_TestID AND T_TestIsActive = 'Y'
            JOIN t_sampletype ON T_TestT_SampleTypeID = T_SampleTypeID
            JOIN t_bahan ON T_SampleTypeT_BahanID = T_BahanID
            JOIN t_samplestation ON T_BahanT_SampleStationID = T_SampleStationID
            WHERE T_OrderDetailT_OrderHeaderID = ?
            GROUP BY T_SampleStationID";
      $qry = $this->db_smartone->query($sql, [$header_id]);

      if (!$qry) {
         $result['status'] = false;
         $result['message'] = 'Terjadi kesalahan saat mengambil data station: ' . $this->db_smartone->error()["message"];
         return $result;
      }

      $data_samples = $qry->result_array();
      foreach ($data_samples as $k => $v) {
         $sample_id = $v['T_SampleStationID'];
         $sql = "SELECT M_LocationID as loc_id 
               FROM m_location
               WHERE M_LocationT_SampleStationID = ?
               ORDER BY M_LocationPriority DESC, M_LocationID ASC
               LIMIT 1";
         $qry = $this->db_smartone->query($sql, [$sample_id]);
         if (!$qry) {
            $result['status'] = false;
            $result['message'] = 'Terjadi kesalahan saat mengambil data lokasi: ' . $this->db_smartone->error()["message"];
            return $result;
         }
         $loc_id = $qry->row()->loc_id;

         $sql = "INSERT INTO t_order_location(
               T_OrderLocationT_OrderHeaderID,	
               T_OrderLocationM_LocationID,
               T_OrderLocationT_SampleStationID,
               T_OrderLocationCreated,	
               T_OrderLocationLastUpdated,	
               T_OrderLocationUserID)
            VALUES (?,?,?,NOW(),NOW(),?)";
         $prm_orderlocation = [$header_id, $loc_id, $sample_id, $userid];
         $qry = $this->db_smartone->query($sql, $prm_orderlocation);
         if (!$qry) {
            $result['status'] = false;
            $result['message'] = 'Terjadi kesalahan saat menyimpan data lokasi: ' . $this->db_smartone->error()["message"];
            return $result;
         }
      }

      return $result;
   }

   function generate_req($header_id, $req, $userid){
      $result = [
         'status' => true,
         'message' => 'Success'
      ];

      $sql = "SELECT Nat_PositionID as req_id FROM nat_position WHERE Nat_PositionCode = 'FO'";
      $query = $this->db_smartone->query($sql);
      if(!$query){
         $result['status'] = false;
         $result['message'] = 'Terjadi kesalahan saat mengambil data position: ' . $this->db_smartone->error()["message"];
         return $result;
      }
      $req_data = $query->row();
      $req_id = $req_data->req_id;

      $req_status = $req['status'];
      $req_tmp = "0";
      $req['reqs'] = is_array($req['reqs']) ? $req['reqs'] : json_decode($req['reqs'], true);
      if (count($req['reqs']) > 0) {
         foreach ($req['reqs'] as $value) {
            $req_tmp .= "," . $value;
         }
      }
      $reqid = "[" . $req_tmp . "]";

      $sql = "INSERT INTO t_orderreq(
            T_OrderReqT_OrderHeaderID,
            T_OrderReqNat_PositionID,
            T_OrderReqStatus,
            T_OrderReqT_TestID,
            T_OrderReqs)
         VALUES (?,?,?,?,?)";
      $prm_orderreq = [$header_id, $req_id, $req_status, '[]', $reqid];
      $qry = $this->db_smartone->query($sql, $prm_orderreq);

      if (!$qry) {
         $result['status'] = false;
         $result['message'] = 'Terjadi kesalahan saat menyimpan data request: ' . $this->db_smartone->error()["message"];
         return $result;
      }

      return $result;
   }

   function save_delivery($header_id, $deliveries, $userid){
      $result = [
         'status' => true,
         'message' => 'Success'
      ];

      if(count($deliveries) > 0){
         foreach($deliveries as $key => $value){
            if($value['chex'] == 'Y'){
               $sql = "INSERT INTO t_orderdelivery(
                  T_OrderDeliveryT_OrderHeaderID,
                  T_OrderDeliveryM_DeliveryTypeID,
                  T_OrderDeliveryM_DeliveryID,
                  T_OrderDeliveryDestination,
                  T_OrderDeliveryNote,
                  T_OrderDeliveryCreated,
                  T_OrderDeliveryCreatedUserID
               ) VALUES (?,?,?,?,?,NOW(),?)";
               $query = $this->db_smartone->query($sql, [
                  $header_id,
                  $value['delivery_type'],
                  $value['delivery_id'],
                  isset($value['description']) ? $value['description'] : '',
                  isset($value['note']) ? $value['note'] : '',
                  $userid
               ]);
               if(!$query){
                  $result['status'] = false;
                  $result['message'] = 'Terjadi kesalahan saat menyimpan data delivery: ' . $this->db_smartone->error()["message"];
                  return $result;
               }
            }
         }
      }

      return $result;
   }

   function generate_code_string() {
      $length = 5;
      $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
      $code = '';
      for ($i = 0; $i < $length; $i++) {
         $code .= $characters[rand(0, strlen($characters) - 1)];
      }
      return $code;
   }

   function generate_uuid() {
      // Generate 16 bytes (128 bits) of random data
      $data = random_bytes(16);

      // Set version to 0100
      $data[6] = chr(ord($data[6]) & 0x0f | 0x40);
      // Set bits 6-7 to 10
      $data[8] = chr(ord($data[8]) & 0x3f | 0x80);

      // Output the 36 character UUID
      return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
   }

   function generate_code_form($preid = 0, $orderid, $userid) {
      $sql = "SELECT COUNT(*) as total 
              FROM form_riwayat_pasien 
              WHERE FormRiwayatPasienT_OrderHeaderID = ? AND
              FormRiwayatPasienIsActive = 'Y'";
      $qry = $this->db_onedev->query($sql, [$orderid]);
      
      if ($qry) {
         $total = $qry->result_array()[0]['total'];
         if ($total == 0) {
            $code = $this->generate_code_string();
            $uuid = $this->generate_uuid();

            $sql = "INSERT INTO form_riwayat_pasien (
                     FormRiwayatPasienPreregisterID, 
                     FormRiwayatPasienCode, 
                     FormRiwayatPasienUUID,
                     FormRiwayatPasienT_OrderHeaderID,
                     FormRiwayatPasienCreated,
                     FormRiwayatPasienCreatedUserID) 
                  VALUES (?, ?, ?, ?, NOW(), ?)";
            $qry = $this->db_onedev->query($sql, [$preid, $code, $uuid, $orderid, $userid]);
            
            if (!$qry) {
               return '';
            }
            return array('uuid' => $uuid, 'code' => $code);
         }
      } else {
         return '';
      }
   }

   function genqrcode($nomorlab, $id) {
      $this->load->library('ciqrcode');
      $home_dir = "/home/one/project/one/";
      $target_dir = $home_dir . "one-media/one-qrcontrolcard/";
      $config['cacheable'] = false;
      $config['imagedir'] = $target_dir;
      $config['quality'] = true;
      $config['size'] = '1024';
      $config['black'] = array(224, 255, 255);
      $config['white'] = array(70, 130, 180);
      $this->ciqrcode->initialize($config);

      $image_name = "qrcode_" . $nomorlab . ".png";

      $params['data'] = "https://devcpone.aplikasi.web.id/one-ui/test/vuex/cpone-control-card/?noreg=" . $nomorlab . "&id=" . $id;
      $params['level'] = 'H';
      $params['size'] = 10;
      $params['savename'] = $config['imagedir'] . $image_name;
      $this->ciqrcode->generate($params);
      
      return "https://devcpone.aplikasi.web.id/one-api-lab/assets/images/" . $image_name;
   }

   function genpatientqrcode($nomorlab) {
      $this->load->library('ciqrcode');
      $home_dir = "/home/one/project/one/";
      $target_dir = $home_dir . "one-media/one-qrpatient/";
      $config['cacheable'] = false;
      $config['imagedir'] = $target_dir;
      $config['quality'] = true;
      $config['size'] = '1024';
      $config['black'] = array(224, 255, 255);
      $config['white'] = array(70, 130, 180);
      $this->ciqrcode->initialize($config);

      $image_name = "patient_qr_" . $nomorlab . ".png";

      $params['data'] = $nomorlab;
      $params['level'] = 'H';
      $params['size'] = 10;
      $params['savename'] = $config['imagedir'] . $image_name;
      $this->ciqrcode->generate($params);
      
      return "https://devcpone.aplikasi.web.id/one-media/one-qrpatient/" . $image_name;
   }

   function genformqrcode($uuid) {
      $this->load->library('ciqrcode');
      $home_dir = "/home/one/project/one/";
      $target_dir = $home_dir . "one-media/one-qrpatient/";
      $config['cacheable'] = false;
      $config['imagedir'] = $target_dir;
      $config['quality'] = true;
      $config['size'] = '1024';
      $config['black'] = array(224, 255, 255);
      $config['white'] = array(70, 130, 180);
      $this->ciqrcode->initialize($config);

      $image_name = "form_qr_" . $uuid . ".png";

      $params['data'] = "https://devcpone.aplikasi.web.id/one-ui/test/vuex/cpone-riwayat-form/?id=" . $uuid;
      $params['level'] = 'H';
      $params['size'] = 10;
      $params['savename'] = $config['imagedir'] . $image_name;
      $this->ciqrcode->generate($params);
      
      return array('image' => "https://devcpone.aplikasi.web.id/one-media/one-qrpatient/" . $image_name, 'url' => $params['data']);
   }

}