This commit is contained in:
mikael-zakaria 2025-10-16 10:47:31 +07:00
commit 3290d24e05
23 changed files with 1163 additions and 989 deletions

View File

@ -57,8 +57,8 @@ $routes->delete('/api/location', 'Location::delete');
$routes->get('/api/contact', 'Contact::index'); $routes->get('/api/contact', 'Contact::index');
$routes->get('/api/contact/(:num)', 'Contact::show/$1'); $routes->get('/api/contact/(:num)', 'Contact::show/$1');
$routes->post('/api/contact', 'Contact::save'); $routes->post('/api/contact', 'Contact::create');
$routes->patch('/api/contact', 'Contact::save'); $routes->patch('/api/contact', 'Contact::update');
$routes->delete('/api/contact', 'Contact::delete'); $routes->delete('/api/contact', 'Contact::delete');
$routes->get('/api/occupation', 'Occupation::index'); $routes->get('/api/occupation', 'Occupation::index');

View File

@ -2,43 +2,33 @@
namespace App\Controllers; namespace App\Controllers;
use CodeIgniter\API\ResponseTrait; use CodeIgniter\API\ResponseTrait;
use CodeIgniter\Controller; use App\Controllers\BaseController;
use App\Models\Contact\ContactModel; use App\Models\Contact\ContactModel;
use App\Models\Contact\ContactDetailModel;
class Contact extends Controller { class Contact extends BaseController {
use ResponseTrait; use ResponseTrait;
protected $db; protected $db;
protected $model; protected $model;
protected $rule; protected $rules;
public function __construct() { public function __construct() {
$this->db = \Config\Database::connect(); $this->db = \Config\Database::connect();
$this->model = new ContactModel(); $this->model = new ContactModel();
$this->rule = [ 'NameFirst' => 'required' ]; $this->rules = [ 'NameFirst' => 'required' ];
} }
public function index() { public function index() {
$ContactName = $this->request->getVar('ContactName'); $ContactName = $this->request->getVar('ContactName');
$Specialty = $this->request->getVar('Specialty'); $Specialty = $this->request->getVar('Specialty');
$rows = $this->model->getContacts($ContactName, $Specialty); $rows = $this->model->getContacts($ContactName, $Specialty);
//$rows = $model->getContacts();
if (empty($rows)) { if (empty($rows)) {
return $this->respond([ return $this->respond([ 'status' => 'success', 'message' => "no Data.", 'data' => [] ], 200);
'status' => 'success',
'message' => "no Data.",
'data' => $rows,
], 200);
} }
return $this->respond([ return $this->respond([ 'status' => 'success', 'message'=> "fetch success", 'data' => $rows ], 200);
'status' => 'success',
'message'=> "fetch success",
'data' => $rows,
], 200);
} }
public function show($ContactID = null) { public function show($ContactID = null) {
@ -46,90 +36,44 @@ class Contact extends Controller {
$rows = $model->getContactWithDetail($ContactID); $rows = $model->getContactWithDetail($ContactID);
if (empty($rows)) { if (empty($rows)) {
return $this->respond([ return $this->respond([ 'status' => 'success', 'message' => "no Data.", 'data' => [] ], 200);
'status' => 'success',
'message' => "Data not found.",
'data' => [],
], 200);
} }
return $this->respond([ return $this->respond([ 'status' => 'success', 'message'=> "fetch success", 'data' => $rows ], 200);
'status' => 'success',
'message'=> "Data fetched successfully",
'data' => $rows,
], 200);
} }
public function delete() { public function delete() {
try { try {
$input = $this->request->getJSON(true); $input = $this->request->getJSON(true);
$ContactID = $input["ContactID"]; $ContactID = $input["ContactID"];
if (!$ContactID) { if (!$ContactID) { return $this->failValidationErrors('ContactID is required.'); }
return $this->failValidationErrors('ContactID is required.'); $this->model->delete($ContactID);
} return $this->respondDeleted([ 'status' => 'success', 'message' => "Contact with {$ContactID} deleted successfully."]);
$contact = $this->db->table('contact')->where('ContactID', $ContactID)->get()->getRow();
if (!$contact) {
return $this->failNotFound("data with {$ContactID} not found.");
}
$this->db->table('contact')->where('ContactID', $ContactID)->update(['EndDate' => NOW()]);
return $this->respondDeleted([
'status' => 'success',
'message' => "Contact with {$ContactID} deleted successfully."
]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
// Ensure rollback if something goes wrong
if ($this->db->transStatus() !== false) {
$this->db->transRollback();
}
return $this->failServerError('Something went wrong: ' . $e->getMessage()); return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }
} }
public function save() { public function create() {
$input = $this->request->getJSON(true); $input = $this->request->getJSON(true);
$contactModel = new ContactModel(); if (!$this->validateData($input, $this->rules)) { return $this->failValidationErrors($this->validator->getErrors()); }
$detailModel = new ContactDetailModel();
$db = \Config\Database::connect();
$db->transStart();
try { try {
if (!empty($input['ContactID'])) { $id = $this->model->saveContact($input,true);
$ContactID = $input['ContactID']; return $this->respondCreated([ 'status' => 'success', 'message' => 'data created successfully', 'data' => $id ], 201);
if (!$contactModel->update($ContactID, $input)) { throw new \RuntimeException('Failed to update contact'); }
} else {
$ContactID = $contactModel->insert($input, true);
if (!$ContactID) { throw new \RuntimeException('Failed to insert contact'); }
}
if(isset($input['Details'])) {
$result = $detailModel->syncDetails($ContactID, $input['Details']);
if ($result['status'] !== 'success') {
throw new \RuntimeException('Failed to sync details: ' . $result['message']);
}
}
$db->transComplete();
if ($db->transStatus() === false) {
throw new \RuntimeException('Transaction failed');
}
return $this->respondCreated([
'status' => 'success',
'ContactID' => $ContactID,
]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
$db->transRollback(); return $this->failServerError('Something went wrong: ' . $e->getMessage());
log_message('error', 'saveContact error: ' . $e->getMessage()); }
return $this->fail([ }
'status' => 'error',
'message' => $e->getMessage(), public function update() {
], 500); $input = $this->request->getJSON(true);
if (!$this->validateData($input, $this->rules)) { return $this->failValidationErrors($this->validator->getErrors()); }
try {
$this->model->saveContact($input);
$id = $input['ContactID'];
return $this->respondCreated([ 'status' => 'success', 'message' => 'data updated successfully', 'data' => $id ], 201);
} catch (\Throwable $e) {
return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }
} }
} }

View File

@ -2,7 +2,7 @@
namespace App\Controllers; namespace App\Controllers;
use CodeIgniter\API\ResponseTrait; use CodeIgniter\API\ResponseTrait;
use CodeIgniter\BaseController; use App\Controllers\BaseController;
use App\Models\Contact\OccupationModel; use App\Models\Contact\OccupationModel;
class Occupation extends BaseController { class Occupation extends BaseController {
@ -40,8 +40,9 @@ class Occupation extends BaseController {
public function create() { public function create() {
$input = $this->request->getJSON(true); $input = $this->request->getJSON(true);
try { try {
$insert = $this->model->insert($input); $this->model->insert($input);
return $this->respondCreated([ 'status' => 'success', 'message' => 'data created successfully', 'data' => $input ], 201); $id = $this->model->getInsertID();
return $this->respondCreated([ 'status' => 'success', 'message' => 'data created successfully', 'data' => $id ], 201);
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->db->transRollback(); $this->db->transRollback();
return $this->failServerError('Exception : ' . $e->getMessage()); return $this->failServerError('Exception : ' . $e->getMessage());
@ -51,10 +52,9 @@ class Occupation extends BaseController {
public function update() { public function update() {
$input = $this->request->getJSON(true); $input = $this->request->getJSON(true);
try { try {
$this->modelOccupation->update($input['OccupationID'], $input); $this->model->update($input['OccupationID'], $input);
return $this->respondCreated([ 'status' => 'success', 'message' => 'Data updated successfully', 'data' => $input ], 201); return $this->respondCreated([ 'status' => 'success', 'message' => 'Data updated successfully', 'data' => $input['OccupationID'] ], 201);
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->db->transRollback();
return $this->failServerError('Exception : ' . $e->getMessage()); return $this->failServerError('Exception : ' . $e->getMessage());
} }
} }

View File

@ -2,157 +2,64 @@
namespace App\Controllers; namespace App\Controllers;
use CodeIgniter\API\ResponseTrait; use CodeIgniter\API\ResponseTrait;
use CodeIgniter\Controller; use App\Controllers\BaseController;
use CodeIgniter\Database\RawSql; use App\Models\CounterModel;
class Counter extends Controller { class Counter extends BaseController {
use ResponseTrait; use ResponseTrait;
protected $db;
protected $model; protected $model;
public function __construct() { public function __construct() {
$this->db = \Config\Database::connect(); $this->model = new CounterModel();
} }
public function index() { public function index() {
$rows = $this->db->table('counter')->select("*")->get()->getResultArray(); $rows = $this->model->findAll();
if (empty($rows)) { if (empty($rows)) {
return $this->respond([ return $this->respond([ 'status' => 'success', 'message' => "No Data.", 'data' => [] ], 200);
'status' => 'success',
'message' => "No Data.",
'data' => [],
], 200);
} }
return $this->respond([ return $this->respond([ 'status' => 'success', 'message'=> "Data fetched successfully", 'data' => $rows ], 200);
'status' => 'success',
'message'=> "Data fetched successfully",
'data' => $rows,
], 200);
} }
public function show($CounterID = null) { public function show($CounterID = null) {
$rows = $this->db->table('counter')->select("*")->where('CounterID', (int) $CounterID)->get()->getResultArray(); $rows = $this->model->find($CounterID);
if (empty($rows)) { if (empty($rows)) {
return $this->respond([ return $this->respond([ 'status' => 'success', 'message' => "No Data.", 'data' => [] ], 200);
'status' => 'success',
'message' => "Data not found.",
'data' => [],
], 200);
} }
return $this->respond([ return $this->respond([ 'status' => 'success', 'message'=> "Data fetched successfully", 'data' => $rows ], 200);
'status' => 'success',
'message'=> "Data fetched successfully",
'data' => $rows,
], 200);
} }
public function create() { public function create() {
$input = $this->request->getJSON(true); $input = $this->request->getJSON(true);
$dataCounter = $this->prepareCounterData($input);
try { try {
$this->db->transStart(); $id = $this->model->insert($input,true);
$this->db->table('counter')->insert($dataCounter); return $this->respondCreated([ 'status' => 'success', 'message' => 'Data created successfully', 'data' => $id ], 201);
$this->db->transComplete();
if ($this->db->transStatus() === false) {
$dbError = $this->db->error();
return $this->failServerError(
'Failed to create data (transaction rolled back): ' . ($dbError['message'] ?? 'Unknown database error')
);
}
return $this->respondCreated([
'status' => 'success',
'message' => 'Data created successfully',
'data' => $dataCounter,
], 201);
} catch (\Throwable $e) { } catch (\Throwable $e) {
// Ensure rollback if something goes wrong
if ($this->db->transStatus() !== false) {
$this->db->transRollback();
}
return $this->failServerError('Something went wrong: ' . $e->getMessage()); return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }
} }
public function update() { public function update() {
$input = $this->request->getJSON(true);
try { try {
$input = $this->request->getJSON(true); $this->model->update($input['CounterID'], $input);
$dataCounter = $this->prepareCounterData($input); return $this->respondCreated([ 'status' => 'success', 'message' => 'Data updated successfully', 'data' => $input['CounterID'] ], 201);
$this->db->transStart();
$this->db->table('counter')->where('CounterID', $dataCounter["CounterID"])->update($dataCounter);
$this->db->transComplete();
if ($this->db->transStatus() === false) {
$dbError = $this->db->error();
return $this->failServerError(
'Failed to update data (transaction rolled back): ' . ($dbError['message'] ?? 'Unknown database error')
);
}
return $this->respondCreated([
'status' => 'success',
'message' => 'Data updated successfully',
'data' => $dataCounter,
], 201);
} catch (\Throwable $e) { } catch (\Throwable $e) {
// Ensure rollback if something goes wrong
if ($this->db->transStatus() !== false) {
$this->db->transRollback();
}
return $this->failServerError('Something went wrong: ' . $e->getMessage()); return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }
} }
public function delete() { public function delete() {
$input = $this->request->getJSON(true);
try { try {
$input = $this->request->getJSON(true); $this->model->delete($input['CounterID'], $input);
$CounterID = $input["CounterID"]; return $this->respondCreated([ 'status' => 'success', 'message' => 'Data deleted successfully', 'data' => $input['CounterID'] ], 201);
if (!$CounterID) {
return $this->failValidationErrors('CounterID is required.');
}
$location = $this->db->table('counter')->where('CounterID', $CounterID)->get()->getRow();
if (!$location) {
return $this->failNotFound("Data not found.");
}
$this->db->table('counter')->where('CounterID', $CounterID)->update(['EndDate' => NOW()]);
return $this->respondDeleted([
'status' => 'success',
'message' => "Counter deleted successfully."
]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
// Ensure rollback if something goes wrong
if ($this->db->transStatus() !== false) {
$this->db->transRollback();
}
return $this->failServerError('Something went wrong: ' . $e->getMessage()); return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }
} }
private function prepareCounterData(array $input): array {
$data = [
"CounterValue" => $input['CounterValue'] ?? null,
"CounterStart" => $input['CounterStart'] ?? null,
"CounterEnd" => $input['CounterEnd'] ?? null,
"CounterDesc" => $input['CounterDesc'] ?? null,
"CounterReset" => $input['CounterReset'] ?? null,
];
if(!empty($input["CounterID"])) { $data["CounterID"] = $input["CounterID"]; }
return $data;
}
} }

View File

@ -2,16 +2,17 @@
namespace App\Controllers; namespace App\Controllers;
use CodeIgniter\API\ResponseTrait; use CodeIgniter\API\ResponseTrait;
use CodeIgniter\Controller; use App\Controllers\BaseController;
use App\Models\Location\LocationModel;
class Location extends Controller { class Location extends BaseController {
use ResponseTrait; use ResponseTrait;
protected $db; protected $model;
protected $rules; protected $rules;
public function __construct() { public function __construct() {
$this->db = \Config\Database::connect(); $this->model = new LocationModel();
$this->rules = [ $this->rules = [
'LocCode' => 'required|max_length[6]', 'LocCode' => 'required|max_length[6]',
'LocFull' => 'required', 'LocFull' => 'required',
@ -21,210 +22,54 @@ class Location extends Controller {
public function index() { public function index() {
$LocName = $this->request->getVar('LocName'); $LocName = $this->request->getVar('LocName');
$LocCode = $this->request->getVar('LocCode'); $LocCode = $this->request->getVar('LocCode');
$rows = $this->model->getLocations($LocCode,$LocName);
$sql = $this->db->table('location l')
->select("l.LocationID, LocCode, Parent, LocFull, LocType, v.VDesc ")
->join("locationaddress la", "l.LocationID=la.LocationID", 'left')
->join("valueset v", "v.VSetID=12 and v.VValue=l.loctype", 'left');
if($LocName != '') { $sql->like('LocFull', $LocName, 'both'); }
if($LocCode != '') { $sql->like('LocCode', $LocCode, 'both'); }
$rows = $sql->get()->getResultArray();
if (empty($rows)) { if (empty($rows)) {
return $this->respond([ return $this->respond([ 'status' => 'success', 'message' => "no Data.", 'data' => [] ], 200);
'status' => 'success',
'message' => "Location no Data.",
'data' => [],
], 200);
} }
return $this->respond([ return $this->respond([ 'status' => 'success', 'message'=> "fetch success", 'data' => $rows ], 200);
'status' => 'success',
'message'=> "Locations fetched successfully",
'data' => $rows,
], 200);
} }
public function show($LocationID = null) {
$rows = $this->db->table('location l')
->select("l.*, la.*, v.*")
->join("locationaddress la", "l.LocationID=la.LocationID", "left")
->join("valueset v", "v.VSetID=12 and v.VValue=l.loctype", "left")
->where('l.LocationID', (int) $LocationID)
->get()->getResultArray();
public function show($LocationID = null) {
$rows = $this->model->getLocation($LocationID);
if (empty($rows)) { if (empty($rows)) {
return $this->respond([ return $this->respond([ 'status' => 'success', 'message' => "no Data.", 'data' => [] ], 200);
'status' => 'success',
'message' => "Data not found.",
'data' => [],
], 200);
} }
return $this->respond([ return $this->respond([ 'status' => 'success', 'message'=> "fetch success", 'data' => $rows ], 200);
'status' => 'success',
'message'=> "Locations fetched successfully",
'data' => $rows,
], 200);
} }
public function create() { public function create() {
$input = $this->request->getJSON(true); $input = $this->request->getJSON(true);
$dataLocation = $this->prepareLocationData($input); if (!$this->validateData($input, $this->rules)) { return $this->failValidationErrors($this->validator->getErrors()); }
$dataLocationAddress = $this->prepareLocationAddressData($input);
if (!$this->validateData($dataLocation, $this->rules)) {
return $this->failValidationErrors($this->validator->getErrors());
}
try { try {
$this->db->transStart(); $data = $this->model->saveLocation($input);
$this->db->table('location')->insert($dataLocation); return $this->respondCreated([ 'status' => 'success', 'message' => 'data created successfully', 'data' => $data['LocationID'] ], 201);
$newLocationID = $this->db->insertID();
if (!empty($dataLocationAddress)) {
$dataLocationAddress['LocationID'] = $newLocationID;
$this->db->table('locationaddress')->insert($dataLocationAddress);
}
$this->db->transComplete();
if ($this->db->transStatus() === false) {
$dbError = $this->db->error();
return $this->failServerError(
'Failed to create location data (transaction rolled back): ' . ($dbError['message'] ?? 'Unknown database error')
);
}
return $this->respondCreated([
'status' => 'success',
'message' => 'Location created successfully',
'data' => $dataLocation,
], 201);
} catch (\Throwable $e) { } catch (\Throwable $e) {
// Ensure rollback if something goes wrong
if ($this->db->transStatus() !== false) {
$this->db->transRollback();
}
return $this->failServerError('Something went wrong: ' . $e->getMessage()); return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }
} }
public function update() { public function update() {
$input = $this->request->getJSON(true);
try { try {
$input = $this->request->getJSON(true); if (!$this->validateData($input, $this->rules)) { return $this->failValidationErrors( $this->validator->getErrors()); }
$this->model->saveLocation($input);
// Prepare data return $this->respondCreated([ 'status' => 'success', 'message' => 'data updated successfully', 'data' => $input['LocationID'] ], 201);
$dataLocation = $this->prepareLocationData($input);
$dataLocationAddress = $this->prepareLocationAddressData($input);
if (!$this->validateData($dataLocation, $this->rules)) {
return $this->failValidationErrors( $this->validator->getErrors());
}
// Start transaction
$this->db->transStart();
// Insert location
$this->db->table('location')->where('LocationID', $dataLocation["LocationID"])->update($dataLocation);
// Insert address if available
if (!empty($dataLocationAddress)) {
$dataLocationAddress['LocationID'] = $input["LocationID"];
$this->db->table('locationaddress')->upsert($dataLocationAddress);
}
// Complete transaction
$this->db->transComplete();
if ($this->db->transStatus() === false) {
$dbError = $this->db->error();
return $this->failServerError(
'Failed to update location data (transaction rolled back): ' . ($dbError['message'] ?? 'Unknown database error')
);
}
return $this->respondCreated([
'status' => 'success',
'message' => 'Location updated successfully',
'data' => $dataLocation,
], 201);
} catch (\Throwable $e) { } catch (\Throwable $e) {
// Ensure rollback if something goes wrong
if ($this->db->transStatus() !== false) {
$this->db->transRollback();
}
return $this->failServerError('Something went wrong: ' . $e->getMessage()); return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }
} }
public function delete() { public function delete() {
$input = $this->request->getJSON(true);
try { try {
$input = $this->request->getJSON(true);
$LocationID = $input["LocationID"]; $LocationID = $input["LocationID"];
if (!$LocationID) { $this->model->deleteLocation($LocationID);
return $this->failValidationErrors('LocationID is required.'); return $this->respondDeleted([ 'status' => 'success', 'message' => "Location with {$LocationID} deleted successfully." ]);
}
$location = $this->db->table('location')->where('LocationID', $LocationID)->get()->getRow();
if (!$location) {
return $this->failNotFound("LocationID with {$LocationID} not found.");
}
$this->db->table('location')->where('LocationID', $LocationID)->update(['DelDate' => NOW()]);
return $this->respondDeleted([
'status' => 'success',
'message' => "Location with {$LocationID} deleted successfully."
]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
// Ensure rollback if something goes wrong
if ($this->db->transStatus() !== false) {
$this->db->transRollback();
}
return $this->failServerError('Something went wrong: ' . $e->getMessage()); return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }
} }
private function prepareLocationData(array $input): array {
$LinkTo = null;
if (!empty($input['LinkTo'])) {
$ids = array_column($input['LinkTo'], 'InternalPID');
$LinkTo = implode(',', $ids);
}
$data = [
"LocCode" => $input['LocCode'] ?? null,
"Parent" => $input['Parent'] ?? null,
"LocFull" => $input['LocFull'] ?? null,
"LocType" => $input['LocType'] ?? null,
"Description" => $input['Description'] ?? null,
];
if(!empty($input["LocationID"])) { $data["LocationID"] = $input["LocationID"]; }
return $data;
}
private function prepareLocationAddressData(array $input): array {
$data = [
"LocationID" => $input['LocationID'] ?? null,
"Street1" => $input['Street1'] ?? null,
"Street2" => $input['Street2'] ?? null,
"City" => $input['City'] ?? null,
"Province" => $input['Province'] ?? null,
"PostCode" => $input['PostCode'] ?? null,
"GeoLocationSystem" => $input['GeoLocationSystem'] ?? null,
"GeoLocationData" => $input['GeoLocationData'] ?? null,
"Email" => $input['Email'] ?? null,
"Phone" => $input['Phone'] ?? null,
"Mobile" => $input['Mobile'] ?? null,
];
return $data;
}
} }

View File

@ -33,7 +33,7 @@ class ContainerDef extends BaseController {
public function show($ConDefID) { public function show($ConDefID) {
try { try {
$rows = $this->model->find($ConDefID); $rows = $this->model->getContainer($ConDefID);
return $this->respond([ 'status' => 'success', 'message'=> "data fetched successfully", 'data' => $rows ], 200); return $this->respond([ 'status' => 'success', 'message'=> "data fetched successfully", 'data' => $rows ], 200);
} catch (\Exception $e) { } catch (\Exception $e) {
return $this->failServerError('Exception : '.$e->getMessage()); return $this->failServerError('Exception : '.$e->getMessage());

View File

@ -13,9 +13,9 @@ class CreateSpecimenTable extends Migration {
'ConCode' => ['type' => 'VARCHAR', 'constraint' => 3, 'null' => false], 'ConCode' => ['type' => 'VARCHAR', 'constraint' => 3, 'null' => false],
'ConName' => ['type' => 'varchar', 'constraint' => 50, 'null' => true], 'ConName' => ['type' => 'varchar', 'constraint' => 50, 'null' => true],
'ConDesc' => ['type' => 'varchar', 'constraint' => 50, 'null' => true], 'ConDesc' => ['type' => 'varchar', 'constraint' => 50, 'null' => true],
'Additive' => ['type' => 'varchar', 'constraint' => 50, 'null' => true], 'Additive' => ['type' => 'int', 'null' => true],
'ConClass' => ['type' => 'int', 'null' => false], 'ConClass' => ['type' => 'int', 'null' => true],
'Color' => ['type' => 'int', 'null' => false], 'Color' => ['type' => 'int', 'null' => true],
'CreateDate' => ['type' => 'Datetime', 'null' => true], 'CreateDate' => ['type' => 'Datetime', 'null' => true],
'EndDate' => ['type' => 'DATETIME', 'null' => true] 'EndDate' => ['type' => 'DATETIME', 'null' => true]
]); ]);

View File

@ -6,10 +6,11 @@ use CodeIgniter\Database\Seeder;
class CounterSeeder extends Seeder { class CounterSeeder extends Seeder {
public function run() { public function run() {
$now = date('Y-m-d H:i:s');
// counter // counter
$data = [ $data = [
['CounterID'=>1, 'CounterValue'=>'1', 'CounterStart'=>'1', 'CounterEnd'=>'99999', 'CounterDesc'=>'Counter for Order#', 'CounterReset'=>'Y' ], ['CounterID'=>1, 'CounterValue'=>'1', 'CounterStart'=>'1', 'CounterEnd'=>'99999', 'CounterDesc'=>'Counter for Order#', 'CounterReset'=>'Y', 'CreateDate'=> "$now" ],
['CounterID'=>2, 'CounterValue'=>'1', 'CounterStart'=>'1', 'CounterEnd'=>'9999', 'CounterDesc'=>'Counter for Visit#', 'CounterReset'=>'M' ], ['CounterID'=>2, 'CounterValue'=>'1', 'CounterStart'=>'1', 'CounterEnd'=>'9999', 'CounterDesc'=>'Counter for Visit#', 'CounterReset'=>'M', 'CreateDate'=> "$now" ]
]; ];
$this->db->table('counter')->insertBatch($data); $this->db->table('counter')->insertBatch($data);
} }

View File

@ -7,15 +7,16 @@ use CodeIgniter\Database\Seeder;
class DummySeeder extends Seeder { class DummySeeder extends Seeder {
public function run() { public function run() {
$now = date('Y-m-d H:i:s');
// location // location
$data = [ $data = [
['LocationID'=>1, 'LocCode'=>'QLOC', 'LocFull'=>'Dummy Location', 'LocType'=>'ROOM', 'Description'=>'Location made for dummy testing' ], ['LocationID'=>1, 'LocCode'=>'QLOC', 'LocFull'=>'Dummy Location', 'LocType'=>'ROOM', 'Description'=>'Location made for dummy testing', 'CreateDate'=> "$now" ],
['LocationID'=>2, 'LocCode'=>'DEFLOC', 'LocFull'=>'Default Location', 'LocType'=>'ROOM', 'Description'=>'Default location' ] ['LocationID'=>2, 'LocCode'=>'DEFLOC', 'LocFull'=>'Default Location', 'LocType'=>'ROOM', 'Description'=>'Default location', 'CreateDate'=> "$now" ]
]; ];
$this->db->table('location')->insertBatch($data); $this->db->table('location')->insertBatch($data);
$data = [ $data = [
['LocationID'=>1, 'Street1'=>'Jalan Nginden', 'Street2'=>'Intan Raya', 'City'=>'Surabaya', 'Province'=>'East Java', 'PostCode'=>'60222'], ['LocationID'=>1, 'Street1'=>'Jalan Nginden', 'Street2'=>'Intan Raya', 'City'=>'Surabaya', 'Province'=>'East Java', 'PostCode'=>'60222', 'CreateDate'=> "$now"],
['LocationID'=>2, 'Street1'=>'Jalan ', 'Street2'=>'Jalan jalan', 'City'=>'Depok', 'Province'=>'DKI Jakarta', 'PostCode'=>'10123'] ['LocationID'=>2, 'Street1'=>'Jalan ', 'Street2'=>'Jalan jalan', 'City'=>'Depok', 'Province'=>'DKI Jakarta', 'PostCode'=>'10123', 'CreateDate'=> "$now"]
]; ];
$this->db->table('locationaddress')->insertBatch($data); $this->db->table('locationaddress')->insertBatch($data);
@ -29,9 +30,9 @@ class DummySeeder extends Seeder {
// contact // contact
$data = [ $data = [
['ContactID'=>1, 'NameFirst'=>'Default', 'NameLast'=>'Doctor', 'Title'=>'', 'Initial'=>'DEFDOC', ['ContactID'=>1, 'NameFirst'=>'Default', 'NameLast'=>'Doctor', 'Title'=>'', 'Initial'=>'DEFDOC',
'Birthdate'=>'', 'EmailAddress1'=>'', 'EmailAddress2'=>'', 'Phone'=>'', 'MobilePhone1'=>'', 'MobilePhone2'=>'', 'Specialty'=>'', 'SubSpecialty'=>'' ], 'Birthdate'=>'', 'EmailAddress1'=>'', 'EmailAddress2'=>'', 'Phone'=>'', 'MobilePhone1'=>'', 'MobilePhone2'=>'', 'Specialty'=>'', 'SubSpecialty'=>'', 'CreateDate'=> "$now" ],
['ContactID'=>2, 'NameFirst'=>'Dummy', 'NameLast'=>'Doctor', 'Title'=>'', 'Initial'=>'QDOC', ['ContactID'=>2, 'NameFirst'=>'Dummy', 'NameLast'=>'Doctor', 'Title'=>'', 'Initial'=>'QDOC',
'Birthdate'=>'', 'EmailAddress1'=>'', 'EmailAddress2'=>'', 'Phone'=>'', 'MobilePhone1'=>'', 'MobilePhone2'=>'', 'Specialty'=>'', 'SubSpecialty'=>'' ] 'Birthdate'=>'', 'EmailAddress1'=>'', 'EmailAddress2'=>'', 'Phone'=>'', 'MobilePhone1'=>'', 'MobilePhone2'=>'', 'Specialty'=>'', 'SubSpecialty'=>'', 'CreateDate'=> "$now" ]
]; ];
$this->db->table('contact')->insertBatch($data); $this->db->table('contact')->insertBatch($data);
$data = [ $data = [
@ -43,27 +44,46 @@ class DummySeeder extends Seeder {
]; ];
$this->db->table('contactdetail')->insertBatch($data); $this->db->table('contactdetail')->insertBatch($data);
$data = [ $data = [
['OccupationID'=>1, 'OccCode'=>'OC001', 'OccText'=>'Medical Doctor', 'Description'=>'Diagnoses and treats, injuries and illnesses' ], ['OccupationID'=>1, 'OccCode'=>'OC001', 'OccText'=>'Medical Doctor', 'Description'=>'Diagnoses and treats, injuries and illnesses', 'CreateDate'=> "$now" ],
['OccupationID'=>2, 'OccCode'=>'OC002', 'OccText'=>'Trainee Medical Technician', 'Description'=>'Performing basic laboratory task' ], ['OccupationID'=>2, 'OccCode'=>'OC002', 'OccText'=>'Trainee Medical Technician', 'Description'=>'Performing basic laboratory task', 'CreateDate'=> "$now" ],
['OccupationID'=>3, 'OccCode'=>'OC003', 'OccText'=>'Medical Laboratory Technician', 'Description'=>'Perform routine laboratory tests' ] ['OccupationID'=>3, 'OccCode'=>'OC003', 'OccText'=>'Medical Laboratory Technician', 'Description'=>'Perform routine laboratory tests', 'CreateDate'=> "$now" ]
]; ];
$this->db->table('occupation')->insertBatch($data); $this->db->table('occupation')->insertBatch($data);
// patient // patient
$data = [ $data = [
[ 'InternalPID'=>1, 'PatientID'=>'SMAJ1', 'NameFirst'=>'Dummy', 'NameLast' => 'Patient M', 'Gender'=>'6', 'BirthDate'=>'1991-09-09', 'Street_1'=>'Makati', 'EmailAddress1'=>'smaj1@5panda.id', [ 'InternalPID'=>1, 'PatientID'=>'SMAJ1', 'NameFirst'=>'Dummy', 'NameLast' => 'Patient M', 'Gender'=>'6', 'BirthDate'=>'1991-09-09', 'Street_1'=>'Makati', 'EmailAddress1'=>'smaj1@5panda.id',
'Country'=>'325', 'Race'=>'175', 'Religion'=>'207', 'Ethnic'=>'218', 'DeathIndicator' => '16'], 'Country'=>'325', 'Race'=>'175', 'Religion'=>'207', 'Ethnic'=>'218', 'DeathIndicator' => '16', 'CreateDate'=> "$now"],
[ 'InternalPID'=>2, 'PatientID'=>'SMAJ2', 'NameFirst'=>'Dummy', 'NameLast' => 'Patient F', 'Gender'=>'6', 'BirthDate'=>'1997-02-02', 'Street_1'=>'Manila', 'EmailAddress1'=>'smaj2@5panda.id', [ 'InternalPID'=>2, 'PatientID'=>'SMAJ2', 'NameFirst'=>'Dummy', 'NameLast' => 'Patient F', 'Gender'=>'6', 'BirthDate'=>'1997-02-02', 'Street_1'=>'Manila', 'EmailAddress1'=>'smaj2@5panda.id',
'Country'=>'325', 'Race'=>'176', 'Religion'=>'206', 'Ethnic'=>'219', 'DeathIndicator' => '16'], 'Country'=>'325', 'Race'=>'176', 'Religion'=>'206', 'Ethnic'=>'219', 'DeathIndicator' => '16', 'CreateDate'=> "$now"],
[ 'InternalPID'=>3, 'PatientID'=>'SMAJ3', 'NameFirst'=>'Dummy', 'NameLast' => 'Patient L', 'Gender'=>'6', 'BirthDate'=>'1997-02-02', 'Street_1'=>'Manila', 'EmailAddress1'=>'smaj3@5panda.id', [ 'InternalPID'=>3, 'PatientID'=>'SMAJ3', 'NameFirst'=>'Dummy', 'NameLast' => 'Patient L', 'Gender'=>'6', 'BirthDate'=>'1997-02-02', 'Street_1'=>'Manila', 'EmailAddress1'=>'smaj3@5panda.id',
'Country'=>'325', 'Race'=>'176', 'Religion'=>'206', 'Ethnic'=>'219', 'DeathIndicator' => '16'] 'Country'=>'325', 'Race'=>'176', 'Religion'=>'206', 'Ethnic'=>'219', 'DeathIndicator' => '16', 'CreateDate'=> "$now"]
]; ];
$this->db->table('patient')->insertBatch($data); $this->db->table('patient')->insertBatch($data);
$data = [ $data = [
[ 'InternalPID'=>1, 'IdentifierType'=>'KTP', 'Identifier'=>'9901' ], [ 'InternalPID'=>1, 'IdentifierType'=>'KTP', 'Identifier'=>'9901', 'CreateDate'=> "$now" ],
[ 'InternalPID'=>2, 'IdentifierType'=>'KTP', 'Identifier'=>'9902' ], [ 'InternalPID'=>2, 'IdentifierType'=>'KTP', 'Identifier'=>'9902', 'CreateDate'=> "$now" ],
[ 'InternalPID'=>3, 'IdentifierType'=>'KTP', 'Identifier'=>'9903' ] [ 'InternalPID'=>3, 'IdentifierType'=>'KTP', 'Identifier'=>'9903', 'CreateDate'=> "$now" ]
]; ];
$this->db->table('patidt')->insertBatch($data); $this->db->table('patidt')->insertBatch($data);
// containerdef
$data = [
['ConCode' => '1','ConName' => 'SST', 'ConDesc' =>'Evacuated blood collection tube, gel separator', 'Additive' => "66", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '11','ConName' => 'Plain', 'ConDesc' =>'Evacuated blood collection tube, no additive/metal-free', 'Additive' => "67", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '12','ConName' => '2Hr PP', 'ConDesc' =>'Evacuated blood collection tube, untuk Glukosa 2 Jam PP', 'Additive' => "68", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '13','ConName' => 'Glukosa Sewaktu', 'ConDesc' =>'Evacuated blood collection tube, untuk Glukosa Sewaktu', 'Additive' => "69", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '14','ConName' => 'GTT 30 menit', 'ConDesc' =>'Evacuated blood collection tube, untuk GTT 30 menit', 'Additive' => "71", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '15','ConName' => 'GTT 60 menit', 'ConDesc' =>'Evacuated blood collection tube, untuk GTT 60 menit', 'Additive' => "71", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '16','ConName' => 'GTT 120 menit', 'ConDesc' =>'Evacuated blood collection tube, untuk GTT 90 menit', 'Additive' => "71", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '20','ConName' => 'RST', 'ConDesc' =>'Evacuated blood collection tube, thrombin/clot activator/gel separator', 'Additive' => "71", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '101','ConName' => 'EDTA - Hematologi', 'ConDesc' =>'Evacuated blood collection tube, K2EDTA/aprotinin', 'Additive' => "71", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '150','ConName' => 'Citrate - Koagulasi', 'ConDesc' =>'Evacuated blood collection tube, untuk koagulasi', 'Additive' => "71", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '200','ConName' => 'Aliquot', 'ConDesc' =>'General specimen container, no additive, non-sterile. Untuk aliquot', 'Additive' => "71", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '290','ConName' => 'Pot Urin', 'ConDesc' =>'Non-sterile urine specimen container IVD', 'Additive' => "71", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '295','ConName' => 'Urine Container', 'ConDesc' =>'Urine specimen container', 'Additive' => "71", 'ConClass' => '80', 'CreateDate'=> "$now"],
['ConCode' => '900','ConName' => 'Packing Pengiriman', 'ConDesc' =>'Specimen Transport Packaging', 'Additive' => "71", 'ConClass' => '81', 'CreateDate'=> "$now"],
];
$this->db->table('containerdef')->insertBatch($data);
} }
} }

View File

@ -1,32 +0,0 @@
<?php
namespace App\Database\Seeds;
use CodeIgniter\Database\Seeder;
class SpecimenSeeder extends Seeder {
public function run() {
// containerdef
$data = [
['ConCode' => '1','ConName' => 'SST', 'ConDesc' =>'Evacuated blood collection tube, gel separator', 'Additive' => "Gel", 'ConClass' => '1'],
['ConCode' => '11','ConName' => 'Plain', 'ConDesc' =>'Evacuated blood collection tube, no additive/metal-free', 'Additive' => null, 'ConClass' => '1'],
['ConCode' => '12','ConName' => '2Hr PP', 'ConDesc' =>'Evacuated blood collection tube, untuk Glukosa 2 Jam PP', 'Additive' => "Sodium Fluoride", 'ConClass' => '1'],
['ConCode' => '13','ConName' => 'Glukosa Sewaktu', 'ConDesc' =>'Evacuated blood collection tube, untuk Glukosa Sewaktu', 'Additive' => "Sodium Fluoride", 'ConClass' => '1'],
['ConCode' => '14','ConName' => 'GTT 30 menit', 'ConDesc' =>'Evacuated blood collection tube, untuk GTT 30 menit', 'Additive' => "Sodium Fluoride", 'ConClass' => '1'],
['ConCode' => '15','ConName' => 'GTT 60 menit', 'ConDesc' =>'Evacuated blood collection tube, untuk GTT 60 menit', 'Additive' => "Sodium Fluoride", 'ConClass' => '1'],
['ConCode' => '16','ConName' => 'GTT 120 menit', 'ConDesc' =>'Evacuated blood collection tube, untuk GTT 90 menit', 'Additive' => "Sodium Fluoride", 'ConClass' => '1'],
['ConCode' => '20','ConName' => 'RST', 'ConDesc' =>'Evacuated blood collection tube, thrombin/clot activator/gel separator', 'Additive' => "Clot activator", 'ConClass' => '1'],
['ConCode' => '101','ConName' => 'EDTA - Hematologi', 'ConDesc' =>'Evacuated blood collection tube, K2EDTA/aprotinin', 'Additive' => "K2EDTA", 'ConClass' => '1'],
['ConCode' => '150','ConName' => 'Citrate - Koagulasi', 'ConDesc' =>'Evacuated blood collection tube, untuk koagulasi', 'Additive' => "Sodium citrate (substance)", 'ConClass' => '1'],
['ConCode' => '200','ConName' => 'Aliquot', 'ConDesc' =>'General specimen container, no additive, non-sterile. Untuk aliquot', 'Additive' => null, 'ConClass' => '1'],
['ConCode' => '290','ConName' => 'Pot Urin', 'ConDesc' =>'Non-sterile urine specimen container IVD', 'Additive' => null, 'ConClass' => '1'],
['ConCode' => '295','ConName' => 'Urine Container', 'ConDesc' =>'Urine specimen container', 'Additive' => null, 'ConClass' => '1'],
['ConCode' => '900','ConName' => 'Packing Pengiriman', 'ConDesc' =>'Specimen Transport Packaging', 'Additive' => null, 'ConClass' => '2']
];
$this->db->table('containerdef')->insertBatch($data);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ use CodeIgniter\Model;
class BaseModel extends Model { class BaseModel extends Model {
protected $beforeInsert = ['normalizeDatesToUTC']; protected $beforeInsert = ['normalizeDatesToUTC'];
protected $beforeUpdate = ['normalizeDatesToUTC']; protected $beforeUpdate = ['normalizeDatesToUTC'];
protected $afterFind = ['convertDatesToUTCISO']; protected $afterFind = ['convertDatesToUTCISO'];
protected $afterInsert = ['convertDatesToUTCISO']; protected $afterInsert = ['convertDatesToUTCISO'];
protected $afterUpdate = ['convertDatesToUTCISO']; protected $afterUpdate = ['convertDatesToUTCISO'];

View File

@ -12,12 +12,6 @@ class ContactDetailModel extends BaseModel {
protected $useTimestamps = true; protected $useTimestamps = true;
protected $createdField = 'ContactStartDate'; protected $createdField = 'ContactStartDate';
protected $updatedField = ''; protected $updatedField = '';
protected $beforeInsert = ['normalizeDatesToUTC'];
protected $beforeUpdate = ['normalizeDatesToUTC'];
protected $afterFind = ['convertDatesToUTCISO'];
protected $afterInsert = ['convertDatesToUTCISO'];
protected $afterUpdate = ['convertDatesToUTCISO'];
public function syncDetails(int $ContactID, array $contactDetails) { public function syncDetails(int $ContactID, array $contactDetails) {
try { try {

View File

@ -7,17 +7,14 @@ use App\Models\BaseModel;
class ContactModel extends BaseModel { class ContactModel extends BaseModel {
protected $table = 'contact'; protected $table = 'contact';
protected $primaryKey = 'ContactID'; protected $primaryKey = 'ContactID';
protected $allowedFields = ['NameFirst', 'NameLast', 'Title', 'Initial', 'Birthdate', 'EmailAddress1', 'EmailAddress2', 'Phone', 'MobilePhone1', 'MobilePhone2', 'Specialty', 'SubSpecialty', 'CreateDate', 'EndDate']; protected $allowedFields = ['NameFirst', 'NameLast', 'Title', 'Initial', 'Birthdate', 'EmailAddress1', 'EmailAddress2', 'Phone',
'MobilePhone1', 'MobilePhone2', 'Specialty', 'SubSpecialty', 'CreateDate', 'EndDate'];
protected $useTimestamps = true; protected $useTimestamps = true;
protected $createdField = 'CreateDate'; protected $createdField = 'CreateDate';
protected $updatedField = ''; protected $updatedField = '';
protected $useSoftDeletes = true;
protected $beforeInsert = ['normalizeDatesToUTC']; protected $deletedField = "EndDate";
protected $beforeUpdate = ['normalizeDatesToUTC'];
protected $afterFind = ['convertDatesToUTCISO'];
protected $afterInsert = ['convertDatesToUTCISO'];
protected $afterUpdate = ['convertDatesToUTCISO'];
public function getContactsWithDetail() { public function getContactsWithDetail() {
$rows = $this->select("contact.ContactID, cd.SiteID, cd.ContactCode, NameFirst, NameLast, Specialty") $rows = $this->select("contact.ContactID, cd.SiteID, cd.ContactCode, NameFirst, NameLast, Specialty")
@ -37,7 +34,7 @@ class ContactModel extends BaseModel {
} }
public function getContactWithDetail($ContactID) { public function getContactWithDetail($ContactID) {
$rows = $this->where('contact.ContactID', $ContactID)->join('contactdetail cd', 'contact.ContactID=cd.ContactID','left')->get()->getResultArray(); $rows = $this->join('contactdetail cd', 'contact.ContactID=cd.ContactID','left')->where('contact.ContactID', $ContactID)->findAll();
$contact = []; $contact = [];
foreach ($rows as $row) { foreach ($rows as $row) {
@ -77,7 +74,7 @@ class ContactModel extends BaseModel {
return $contact; return $contact;
} }
public function saveWithDetails(array $data): array { public function saveContact(array $data): array {
$db = \Config\Database::connect(); $db = \Config\Database::connect();
$db->transStart(); $db->transStart();
@ -94,8 +91,8 @@ class ContactModel extends BaseModel {
} }
if (!empty($data['Details'])) { if (!empty($data['Details'])) {
$detailModel = new \App\Models\ContactDetailModel(); $modelDetail = new \App\Models\Contact\ContactDetailModel();
$result = $detailModel->syncDetails($contactId, $data['Details']); $result = $modelDetail->syncDetails($contactId, $data['Details']);
if ($result['status'] !== 'success') { if ($result['status'] !== 'success') {
throw new \RuntimeException('SyncDetails failed: ' . $result['message']); throw new \RuntimeException('SyncDetails failed: ' . $result['message']);
@ -111,8 +108,6 @@ class ContactModel extends BaseModel {
} catch (\Throwable $e) { } catch (\Throwable $e) {
$db->transRollback(); $db->transRollback();
log_message('error', 'saveWithDetails error: ' . $e->getMessage());
return [ return [
'status' => 'error', 'status' => 'error',
'message' => $e->getMessage(), 'message' => $e->getMessage(),

View File

@ -6,5 +6,5 @@ use App\Models\BaseModel;
class OccupationModel extends BaseModel { class OccupationModel extends BaseModel {
protected $table = 'occupation'; protected $table = 'occupation';
protected $primaryKey = 'OccupationID'; protected $primaryKey = 'OccupationID';
protected $allowedFields = ['OccCode', 'OccText', 'Description']; protected $allowedFields = ['OccCode', 'OccText', 'Description', 'CreateDate'];
} }

View File

@ -5,7 +5,13 @@ namespace App\Models;
class CounterModel extends BaseModel { class CounterModel extends BaseModel {
protected $table = 'counter'; protected $table = 'counter';
protected $primaryKey = 'CounterID'; protected $primaryKey = 'CounterID';
protected $allowedFields = ['CounterValue', 'CounterStart', 'CounterEnd', 'CounterReset']; protected $allowedFields = ['CounterValue', 'CounterStart', 'CounterEnd', 'CounterReset', 'CreateDate', 'EndDate'];
protected $useTimestamps = true;
protected $createdField = "CreateDate";
protected $updatedField = "";
protected $useSoftDeletes = true;
protected $deletedField = "EndDate";
public function use($CounterID) { public function use($CounterID) {
$row = $this->where('CounterID',$CounterID)->get()->getResultArray(); $row = $this->where('CounterID',$CounterID)->get()->getResultArray();

View File

@ -0,0 +1,22 @@
<?php
namespace App\Models\Location;
use App\Models\BaseModel;
class LocationAddressModel extends BaseModel {
protected $table = 'locationaddress';
protected $primaryKey = 'LocationID';
protected $allowedFields = ['Street1', 'Street2', 'City', 'Province', 'PostCode', 'GeoLocationSystem', 'GeoLocationData', 'Phone', 'Mobile', 'Email', 'CreateDate', 'EndDate'];
protected $useTimestamps = true;
protected $createdField = 'CreateDate';
protected $updatedField = '';
protected $useSoftDeletes = true;
protected $deletedField = 'EndDate';
protected $beforeInsert = ['normalizeDatesToUTC'];
protected $beforeUpdate = ['normalizeDatesToUTC'];
protected $afterFind = ['convertDatesToUTCISO'];
protected $afterInsert = ['convertDatesToUTCISO'];
protected $afterUpdate = ['convertDatesToUTCISO'];
}

View File

@ -0,0 +1,79 @@
<?php
namespace App\Models\Location;
use App\Models\BaseModel;
class LocationModel extends BaseModel {
protected $table = 'location';
protected $primaryKey = 'LocationID';
protected $allowedFields = ['SiteID', 'LocCode', 'Parent', 'LocFull', 'Description', 'LocType', 'CreateDate', 'EndDate'];
protected $useTimestamps = true;
protected $createdField = 'CreateDate';
protected $updatedField = '';
protected $useSoftDeletes = true;
protected $deletedField = 'EndDate';
public function getLocations($LocCode, $LocName) {
$sql = $this->select("LocationID, LocCode, Parent, LocFull, LocType, v.VDesc ")
->join("valueset v", "v.VSetID=12 and v.VValue=location.loctype", 'left');
if($LocName != '') { $sql->like('LocFull', $LocName, 'both'); }
if($LocCode != '') { $sql->like('LocCode', $LocCode, 'both'); }
$rows = $sql->findAll();
return $rows;
}
public function getLocation($LocationID) {
$rows = $this->select("location.*, la.*, v.*")
->join("locationaddress la", "location.LocationID=la.LocationID", "left")
->join("valueset v", "v.VSetID=12 and v.VValue=location.loctype", "left")
->where('location.LocationID', (int) $LocationID)->findAll();
//->get()->getResultArray();
return $rows;
}
public function saveLocation(array $data): array {
$modelAddress = new \App\Models\Location\LocationAddressModel();
$db = \Config\Database::connect();
$db->transBegin();
try {
if (!empty($data['LocationID'])) {
$LocationID = $data['LocationID'];
$this->update($LocationID, $data);
$modelAddress->update($LocationID, $data);
} else {
$LocationID = $this->insert($data, true);
$data['LocationID'] = $LocationID;
$modelAddress->insert($data);
}
if ($db->transStatus() === false) {
$db->transRollback();
throw new \Exception('Transaction failed');
}
$db->transCommit();
return [ 'status' => 'success', 'LocationID' => $LocationID ];
} catch (\Throwable $e) {
$db->transRollback();
return [ 'status' => 'error', 'message' => $e->getMessage() ];
}
}
public function deleteLocation(array $data): array {
$modelAddress = new \App\Models\Location\LocationAddressModel();
$db = \Config\Database::connect();
$db->transBegin();
try {
$LocationID = $data['LocationID'];
$this->delete($LocationID);
$modelAddress->delete($LocationID);
if ($db->transStatus() === false) {
$db->transRollback();
throw new \Exception('Transaction failed');
}
$db->transCommit();
return [ 'status' => 'success', 'LocationID' => $LocationID ];
} catch (\Throwable $e) {
$db->transRollback();
return [ 'status' => 'error', 'message' => $e->getMessage() ];
}
}
}

View File

@ -14,22 +14,17 @@ class PatVisitModel extends BaseModel {
protected $useTimestamps = true; protected $useTimestamps = true;
protected $createdField = 'CreateDate'; protected $createdField = 'CreateDate';
protected $updatedField = ''; protected $updatedField = '';
protected $useSoftDeletes = true;
protected $beforeInsert = ['normalizeDatesToUTC']; protected $deletedField = 'EndDate';
protected $beforeUpdate = ['normalizeDatesToUTC'];
protected $afterFind = ['convertDatesToUTCISO'];
protected $afterInsert = ['convertDatesToUTCISO'];
protected $afterUpdate = ['convertDatesToUTCISO'];
public function __construct() { public function __construct() {
$this->db = \Config\Database::connect();
$this->visnum_prefix = "DV"; $this->visnum_prefix = "DV";
} }
public function show($PVID) { public function show($PVID) {
$rows = $this->join('patdiag pd', 'pd.InternalPVID=patvisit.InternalPVID', 'left') $rows = $this->join('patdiag pd', 'pd.InternalPVID=patvisit.InternalPVID', 'left')
->join('patvisitadt pva', 'pva.InternalPVID=patvisit.InternalPVID', 'left') ->join('patvisitadt pva', 'pva.InternalPVID=patvisit.InternalPVID', 'left')
->where('patvisit.PVID',$PVID)->get()->getResultArray(); ->where('patvisit.PVID',$PVID)->findAll();
return $rows; return $rows;
} }
@ -37,7 +32,7 @@ class PatVisitModel extends BaseModel {
$rows = $this->join('patdiag pd', 'pd.InternalPVID=patvisit.InternalPVID', 'left') $rows = $this->join('patdiag pd', 'pd.InternalPVID=patvisit.InternalPVID', 'left')
->join('patvisitadt pva', 'pd.InternalPVID=pva.InternalPVID', 'left') ->join('patvisitadt pva', 'pd.InternalPVID=pva.InternalPVID', 'left')
->join('location l', 'l.LocationID=pva.LocationID', 'left') ->join('location l', 'l.LocationID=pva.LocationID', 'left')
->where('patvisit.InternalPID',$InternalPID)->get()->getResultArray(); ->where('patvisit.InternalPID',$InternalPID)->findAll();
return $rows; return $rows;
} }

View File

@ -0,0 +1,405 @@
<?php
namespace App\Models\Patient;
use App\Models\BaseModel;
class PatientModel extends BaseModel {
protected $table = 'patient';
protected $primaryKey = 'InternalPID';
protected $allowedFields = ['PatientID', 'AlternatePID', 'Prefix', 'NameFirst', 'NameMiddle', 'NameMaiden', 'NameLast', 'Suffix', 'NameAlias', 'Gender', 'Birthdate', 'PlaceOfBirth', 'Street_1', 'Street_2', 'Street_3',
'City', 'Province', 'ZIP', 'EmailAddress1', 'EmailAddress2', 'Phone', 'MobilePhone', 'Custodian', 'AccountNumber', 'Country', 'Race', 'MaritalStatus', 'Religion', 'Ethnic', 'Citizenship',
'DeathIndicator', 'DeathDateTime', 'LinkTo', 'CreateDate', 'DelDate' ];
protected $useTimestamps = true;
protected $createdField = 'CreateDate';
protected $updatedField = '';
protected $useSoftDeletes = true;
protected $deletedField = 'DelDate';
public function getPatients($filters = []) {
$qname = "LOWER(CONCAT_WS(' ', IFNULL(Prefix,''), IFNULL(NameFirst,''), IFNULL(NameMiddle,''), IFNULL(NameLast,''), IFNULL(NameMaiden,''), IFNULL(Suffix,'')))";
$builder = $this->db->table($this->table);
$builder->select("InternalPID, PatientID, $qname as FullName, Gender, Birthdate, EmailAddress1 as Email, MobilePhone");
if (!empty($filters['Name'])) {
$builder->like($qname, $filters['Name'], 'both');
}
if (!empty($filters['InternalPID'])) {
$builder->where('InternalPID', $filters['InternalPID']);
}
if (!empty($filters['PatientID'])) {
$builder->like('PatientID', $filters['PatientID'], 'both');
}
if (!empty($filters['Birthdate'])) {
$builder->where('Birthdate', $filters['Birthdate']);
}
return $builder->get()->getResultArray();
}
public function getPatient($InternalPID) {
$rows = $this->db->table('patient p')
->select("
p.*,
country.VDesc as Country,
country.VID as CountryVID,
race.VDesc as Race,
race.VID as RaceVID,
religion.VDesc as Religion,
religion.VID as ReligionVID,
ethnic.VDesc as Ethnic,
ethnic.VID as EthnicVID,
gender.VDesc as Gender,
gender.VID as GenderVID,
deathindicator.VDesc as DeathIndicator,
deathindicator.VID as DeathIndicatorVID,
maritalstatus.VDesc as MaritalStatus,
maritalstatus.VID as MaritalStatusVID,
patcom.Comment as Comment,
patidt.IdentifierType,
patidt.Identifier,
patatt.Address
")
->join('valueset country', 'country.VID = p.Country', 'left')
->join('valueset race', 'race.VID = p.Race', 'left')
->join('valueset religion', 'religion.VID = p.Religion', 'left')
->join('valueset ethnic', 'ethnic.VID = p.Ethnic', 'left')
->join('valueset gender', 'gender.VID = p.Gender', 'left')
->join('valueset deathindicator', 'deathindicator.VID = p.DeathIndicator', 'left')
->join('valueset maritalstatus', 'maritalstatus.VID = p.MaritalStatus', 'left')
->join('patcom', 'patcom.InternalPID = p.InternalPID', 'left')
->join('patidt', 'patidt.InternalPID = p.InternalPID', 'left')
->join('patatt', 'patatt.InternalPID = p.InternalPID and patatt.DelDate is null', 'left')
->where('p.InternalPID', (int) $InternalPID)
->get()
->getResultArray();
if (empty($rows)) { return null; }
$patient = $rows[0];
if (method_exists($this, 'transformPatientData')) { $patient = $this->transformPatientData($patient); }
unset($patient['Address']);
unset($patient['IdentifierType']);
unset($patient['Identifier']);
unset($patient['Comment']);
// Default nested structures
$patient['PatIdt'] = null;
$patient['PatAtt'] = [];
foreach ($rows as $row) {
if ($row['IdentifierType'] && $row['Identifier'] && !$patient['PatIdt']) {
$patient['PatIdt'] = [
'IdentifierType' => $row['IdentifierType'],
'Identifier' => $row['Identifier'],
];
}
if ($row['Address']) {
$patient['PatAtt'][] = ['Address' => $row['Address']];
}
}
if (empty($patient['PatIdt'])) { $patient['PatIdt'] = null; }
if (empty($patient['PatAtt'])) { $patient['PatAtt'] = null; }
return $patient;
}
public function createPatient($input) {
$db = \Config\Database::connect();
$patidt = $input['PatIdt'] ?? [];
$patatt = $input['PatAtt'] ?? [];
$patcom['Comment'] = $input['PatCom'] ?? null;
$input['LinkTo'] = empty($input['LinkTo']) ? null : $input['LinkTo'];
$input['Birthdate'] = $this->isValidDateTime($input['Birthdate']);
$input['DeathDateTime'] = $this->isValidDateTime($input['DeathDateTime']);
$db->transBegin();
try {
$this->insert($input);
$newInternalPID = $this->getInsertID();
$this->checkDbError($db, 'Insert patient');
if (!empty($patidt)) {
$patidt['InternalPID'] = $newInternalPID;
$db->table('patidt')->insert($patidt);
$this->checkDbError($db, 'Insert patidt');
}
if (!empty($patcom)) {
$patcom['InternalPID'] = $newInternalPID;
$db->table('patcom')->insert($patcom);
$this->checkDbError($db, 'Insert patcom');
}
if (!empty($patatt)) {
foreach ($patatt as &$row) {
$row['InternalPID'] = $newInternalPID;
}
$db->table('patatt')->upsertBatch($patatt);
$this->checkDbError($db, 'Insert patatt');
}
$db->transCommit();
// $db->transComplete();
// if ($db->transStatus() === false) {
// throw new \Exception("Failed to sync patient relations");
// }
return $newInternalPID;
} catch (\Exception $e) {
$db->transRollback();
throw $e;
}
}
public function updatePatient($input) {
$db = \Config\Database::connect();
$patidt = $input['PatIdt'] ?? [];
$patatt = $input['PatAtt'] ?? [];
$patcom['Comment'] = $input['PatCom'] ?? null;
$input['LinkTo'] = empty($input['LinkTo']) ? null : $input['LinkTo'];
$input['Birthdate'] = $this->isValidDateTime($input['Birthdate']);
$input['DeathDateTime'] = $this->isValidDateTime($input['DeathDateTime']);
$db->transBegin();
try {
$InternalPID = $input['InternalPID'];
$this->where('InternalPID',$InternalPID)->set($input)->update();
$this->checkDbError($db, 'Update patient');
$now = date('Y-m-d H:i:s');
if (!empty($patidt)) {
$exists = $db->table('patidt')->where('InternalPID', $InternalPID)->get()->getRowArray();
if ($exists) {
$db->table('patidt')->where('InternalPID', $InternalPID)->update($patidt);
} else {
$patidt['InternalPID'] = $InternalPID;
$db->table('patidt')->insert($patidt);
$this->checkDbError($db, 'Update patidt');
}
} else {
$db->table('patidt')->where('InternalPID', $InternalPID)->delete();
$this->checkDbError($db, 'Update patidt');
}
if (!empty($patcom)) {
$exists = $db->table('patcom')->where('InternalPID', $InternalPID)->get()->getRowArray();
if ($exists) {
$db->table('patcom')->where('InternalPID', $InternalPID)->update($patcom);
$this->checkDbError($db, 'Update patcom');
} else {
$patcom['InternalPID'] = $InternalPID;
$db->table('patcom')->insert($patcom);
$this->checkDbError($db, 'Update patcom');
}
} else {
$db->table('patcom')->where('InternalPID', $InternalPID)->delete();
$this->checkDbError($db, 'Update patcom');
}
if (!empty($patatt)) {
// Ambil daftar address aktif (DelDate IS NULL) di DB
$oldActive = $db->table('patatt')
->select('Address')
->where('InternalPID', $InternalPID)
->where('DelDate', null)
->get()->getResultArray();
$oldActive = array_column($oldActive, 'Address');
// Normalisasi & dedup input baru (berdasarkan Address)
$mapNew = [];
foreach ($patatt as $row) {
if (!isset($row['Address'])) continue;
$mapNew[$row['Address']] = $row; // overwrite duplikat di input
}
$newData = array_keys($mapNew);
// Hitung yang perlu ditambah & dihapus
$added = array_diff($newData, $oldActive); // baru (belum aktif)
$removed = array_diff($oldActive, $newData); // dulu aktif tapi hilang di input
// 1) Soft delete yang dihapus
if (!empty($removed)) {
$db->table('patatt')
->where('InternalPID', $InternalPID)
->whereIn('Address', $removed)
->set('DelDate', $now)
->update();
$this->checkDbError($db, 'Update/Delete patatt');
}
// 2) Tambahkan yang baru
foreach ($added as $addr) {
$data = $mapNew[$addr];
$data['InternalPID'] = $InternalPID;
// Coba REACTIVATE satu baris yang pernah di-soft delete (kalau ada)
$builder = $db->table('patatt');
$builder->set('DelDate', null);
// Kalau ada kolom lain yang mau di-update saat re-activate, set di sini juga
// mis: $builder->set('Note', $data['Note'] ?? null);
$builder->where('InternalPID', $InternalPID)
->where('Address', $addr)
->where('DelDate IS NOT NULL', null, false)
->orderBy('PatAttID', 'DESC')
->limit(1)
->update();
$this->checkDbError($db, 'Update/Insert patatt');
if ($db->affectedRows() === 0) {
// Tidak ada baris soft-deleted untuk alamat ini → INSERT baru
$db->table('patatt')->insert($data);
$this->checkDbError($db, 'Update/Insert patatt');
}
}
} else {
// Input kosong → semua yang masih aktif di-soft delete
$db->table('patatt')->where('InternalPID', $InternalPID)->where('DelDate', null)->set('DelDate', $now)->update();
$this->checkDbError($db, 'Update/Delete patatt');
}
$db->transCommit();
// if ($db->transStatus() === false) {
// throw new \Exception('Failed to sync patient relations');
// }
return $InternalPID;
} catch (\Exception $e) {
$db->transRollback();
throw $e;
}
}
private function transformPatientData(array $patient): array {
$patient["Age"] = $this->calculateAgeFromBirthdate($patient["Birthdate"], $patient["DeathDateTime"]);
$patient["DeathDateTime"] = $this->formattedDate($patient["DeathDateTime"]);
$patient["CreateDate"] = $this->formattedDate($patient["CreateDate"]);
$patient["BirthdateConversion"] = $this->formatedDateForDisplay($patient["Birthdate"]);
$patient["LinkTo"] = $this->getLinkedPatients($patient['LinkTo']);
$patient["Custodian"] = $this->getCustodian($patient['Custodian']);
$patient['PatCom'] = $patient['Comment'];
return $patient;
}
private function getLinkedPatients(?string $linkTo): ?array {
if (empty($linkTo)) { return null; }
$ids = array_filter(explode(',', $linkTo));
return $this->db->table('patient')
->select('InternalPID, PatientID')
->whereIn('InternalPID', $ids)
->get()
->getResultArray() ?: null;
}
private function getCustodian($custodianId): ?array {
if (empty($custodianId)) {
return null;
}
return $this->db->table('patient')
->select('InternalPID, PatientID')
->where('InternalPID', (int) $custodianId)
->get()
->getRowArray() ?: null;
}
// Conversion to (Years Months Days) - For Age
private function calculateAgeFromBirthdate($birthdate, $deathdatetime) {
$dob = new \DateTime($birthdate);
// Cek DeathTime
if ($deathdatetime == null) {
$today = new \DateTime();
} else {
$deathdatetime = new \DateTime($deathdatetime);
$today = $deathdatetime;
}
$diff = $today->diff($dob);
$formattedAge = "";
if ($diff->y > 0){
$formattedAge .= "{$diff->y} Years ";
}
if ($diff->m > 0){
$formattedAge .= "{$diff->m} Months ";
}
if ($diff->d > 0){
$formattedAge .= "{$diff->d} Days";
}
return $formattedAge;
}
// Conversion Time to Format Y-m-d\TH:i:s\Z
private function formattedDate(?string $dateString): ?string {
try {
if (empty($dateString)) {return null;}
$dt = new \DateTime($dateString, new \DateTimeZone("UTC"));
return $dt->format('Y-m-d\TH:i:s\Z'); // ISO 8601 UTC
} catch (\Exception $e) {
return null;
}
}
// Conversion Time to Format j M Y - For BirthdateConversion
private function formatedDateForDisplay($dateString) {
$date = \DateTime::createFromFormat('Y-m-d H:i', $dateString);
if (!$date) {
$timestamp = strtotime($dateString);
if ($timestamp) {
return date('j M Y', $timestamp);
}
return null;
}
return $date->format('j M Y');
}
// Check Error and Send Spesific Messages
private function checkDbError($db, string $context) {
$error = $db->error();
if (!empty($error['code'])) {
throw new \Exception(
"{$context} failed: {$error['code']} - {$error['message']}"
);
}
}
// Preventif 0000-00-00
private function isValidDateTime($datetime) {
if (empty($datetime) || $datetime=="") {return null; }
try {
// Kalau input hanya Y-m-d (tanpa jam)
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $datetime)) {
$dt = \DateTime::createFromFormat('Y-m-d', $datetime);
return $dt ? $dt->format('Y-m-d') : null; // hanya tanggal
}
// Selain itu (ISO 8601 atau datetime lain), format ke Y-m-d H:i:s
$dt = new \DateTime($datetime);
return $dt->format('Y-m-d H:i:s');
} catch (\Exception $e) {
return null;
}
}
}

View File

@ -1,7 +1,7 @@
<?php <?php
namespace App\Models\Specimen; namespace App\Models\Specimen;
use App\Models\BaseUtcModel; use App\Models\BaseModel;
class ContainerDefModel extends BaseModel { class ContainerDefModel extends BaseModel {
protected $table = 'containerdef'; protected $table = 'containerdef';
@ -20,4 +20,12 @@ class ContainerDefModel extends BaseModel {
protected $afterInsert = ['convertDatesToUTCISO']; protected $afterInsert = ['convertDatesToUTCISO'];
protected $afterUpdate = ['convertDatesToUTCISO']; protected $afterUpdate = ['convertDatesToUTCISO'];
public function getContainer($ConDefID) {
$rows = $this->select('containerdef.*, vscol.VValue as ColorTxt, vscla.VValue as ConClassTxt, vsadd.VValue as AdditiveTxt')
->join('valueset vscol', 'vscol.VID=containerdef.Color', 'left')
->join('valueset vscla', 'vscla.VID=containerdef.ConClass', 'left')
->join('valueset vsadd', 'vsadd.VID=containerdef.Additive', 'left')
->where('ConDefID', $ConDefID)->findAll();
return $rows;
}
} }

View File

@ -2,7 +2,7 @@
namespace App\Models\ValueSet; namespace App\Models\ValueSet;
use App\Models\BaseUtcModel; use App\Models\BaseModel;
class ValueSetDefModel extends BaseModel { class ValueSetDefModel extends BaseModel {
protected $table = 'valuesetdef'; protected $table = 'valuesetdef';
@ -15,18 +15,11 @@ class ValueSetDefModel extends BaseModel {
protected $useSoftDeletes = true; protected $useSoftDeletes = true;
protected $deletedField = 'EndDate'; protected $deletedField = 'EndDate';
protected $beforeInsert = ['normalizeDatesToUTC'];
protected $beforeUpdate = ['normalizeDatesToUTC'];
protected $afterFind = ['convertDatesToUTCISO'];
protected $afterInsert = ['convertDatesToUTCISO'];
protected $afterUpdate = ['convertDatesToUTCISO'];
public function getValueSetDefs($param = null) { public function getValueSetDefs($param = null) {
if ($param !== null) { if ($param !== null) {
$builder = $this->builder(); $rows = $this->like('VSName', $param, 'both')
$builder->like('VSName', $param, 'both'); ->orlike('VSDesc', $param, 'both')
$builder->orlike('VSDesc', $param, 'both'); ->findAll();
$rows = $builder->get()->getResultArray();
} else { } else {
$rows = $this->findAll(); $rows = $this->findAll();
} }

View File

@ -15,21 +15,12 @@ class ValueSetModel extends BaseModel {
protected $useSoftDeletes = true; protected $useSoftDeletes = true;
protected $deletedField = 'EndDate'; protected $deletedField = 'EndDate';
protected $beforeInsert = ['normalizeDatesToUTC'];
protected $beforeUpdate = ['normalizeDatesToUTC'];
protected $afterFind = ['convertDatesToUTCISO'];
protected $afterInsert = ['convertDatesToUTCISO'];
protected $afterUpdate = ['convertDatesToUTCISO'];
public function getValueSets($param = null) { public function getValueSets($param = null) {
if ($param !== null) { if ($param !== null) {
$builder = $this->builder(); $rows = $this->groupStart()
$builder->groupStart()
->like('VValue', $param, 'both') ->like('VValue', $param, 'both')
->orlike('VDesc', $param, 'both') ->orlike('VDesc', $param, 'both')
->groupEnd(); ->groupEnd()->findAll();
$rows = $builder->get()->getResultArray();
return $rows; return $rows;
} else { } else {
return $this->findAll(); return $this->findAll();