Viewing File: /home/assersoft/public_html/nationallab/app/Controllers/InvoicesController.php
<?php
namespace App\Controllers;
use CodeIgniter\RESTful\ResourceController;
use CodeIgniter\HTTP\ResponseInterface;
class InvoicesController extends ResourceController
{
protected $modelName = 'App\Models\InvoiceModel';
protected $invoiceTestModel;
protected $patientModel;
protected $testModel;
protected $testItemModel;
protected $reportDetailModel;
/**
* Constructor.
*/
public function __construct()
{
$this->invoiceTestModel = model('App\Models\InvoiceTestModel');
$this->patientModel = model('App\Models\PatientModel');
$this->testModel = model('App\Models\TestModel');
$this->testItemModel = model('App\Models\TestItemModel');
$this->reportDetailModel = model('App\Models\ReportDetailModel');
}
/**
* Count the total number of invoices.
*
* @return ResponseInterface
*/
public function count()
{
$total = $this->model->countAll();
return $this->respond(['total' => $total]);
}
/**
* Count the total number of invoice tests.
*
* @return ResponseInterface
*/
public function countTests()
{
$totalTests = $this->invoiceTestModel->countAll();
return $this->respond(['total_tests' => $totalTests]);
}
/**
* Return an array of resource objects, themselves in array format.
*
* @return ResponseInterface
*/
public function index()
{
$perPage = $this->request->getVar('limit') ?? 10;
$offset = $this->request->getVar('offset') ?? 1;
$search = $this->request->getVar('search') ?? '';
$search = trim($search);
$invoices = [];
if($search !== '') {
$invoices = $this->model
// search by lab number or patient name
->groupStart()
->like('invoices.lab_number', $search)
->orLike('patients.name', $search)
->groupEnd()
->select('invoices.*, patients.id as patient_id, patients.name as patient_name, patients.age as patient_age, patients.sex as patient_sex, patients.phone as patient_phone')
->join('patients', 'patients.id = invoices.patient_id')
->orderBy('invoices.id', 'DESC')
->paginate($perPage, 'default', $offset);
} else {
$invoices = $this->model
->select('invoices.*, patients.id as patient_id, patients.name as patient_name, patients.age as patient_age, patients.sex as patient_sex, patients.phone as patient_phone')
->join('patients', 'patients.id = invoices.patient_id')
->orderBy('invoices.id', 'DESC')
->paginate($perPage, 'default', $offset);
}
$response = [
'data' => $invoices,
'pager' => $this->model->pager->getDetails()
];
return $this->respond($response);
}
/**
* Return the properties of a resource object.
*
* @param int|string|null $id
*
* @return ResponseInterface
*/
public function show($id = null)
{
if($id == null) {
return $this->failNotFound('Invoice ID is required.');
}
$invoice = $this->model
->select('invoices.*, patients.id as patient_id, patients.name as patient_name, patients.age as patient_age, patients.sex as patient_sex, patients.phone as patient_phone')
->join('patients', 'patients.id = invoices.patient_id')
->where('invoices.id', $id)
->first();
if ($invoice === null) {
return $this->failNotFound('Invoice not found.');
}
$invoice['tests'] = $this->invoiceTestModel
->select('tests.id as test_id, tests.code, tests.name, invoice_tests.price')
->join('tests', 'tests.id = invoice_tests.test_id')
->where('invoice_tests.invoice_id', $id)
->findAll();
return $this->respond($invoice);
}
/**
* Return a new resource object, with default properties.
*
* @return ResponseInterface
*/
public function new()
{
$patients = $this->patientModel
->select('id, name')
->orderBy('name')
->findAll();
$tests = $this->testModel
->select('id, name, code, price')
->orderBy('name')
->findAll();
return $this->respond([
'patients' => $patients,
'tests' => $tests,
]);
}
/**
* Create a new resource object, from "posted" parameters.
*
* @return ResponseInterface
*/
public function create()
{
$data = $this->request->getJSON(true);
if (empty($data['patient_id']) || empty($data['tests'])) {
return $this->fail('Patient ID and tests are required.');
}
$invoiceData = [
'lab_number' => $data['lab_number'] ?? null,
'patient_id' => $data['patient_id'] ?? null,
'referred_by' => $data['referred_by'] ?? null,
'invoice_date' => $data['invoice_date'] ?? null,
'total_amount' => $data['total_amount'] ?? null,
'discount' => $data['discount'] ?? null,
'discounted_amount' => $data['discounted_amount'] ?? $data['total_amount'] ?? null,
'paid_amount' => $data['paid_amount'] ?? null,
'balance' => $data['balance'] ?? null,
'collecting_date' => $data['collecting_date'] ?? null,
];
if (!isset($data['tests']) || !is_array($data['tests']) || empty($data['tests'])) {
return $this->failValidationErrors(['tests' => 'At least one test is required.']);
}
if(!$this->model->insert($invoiceData)) {
return $this->failValidationErrors($this->model->errors());
}
$invoiceId = $this->model->insertID();
$testRows = [];
foreach ($data['tests'] as $test) {
if (!isset($test['test_id'], $test['price'])) {
return $this->failValidationErrors(['tests' => 'Each test must have test_id and price.']);
}
$testRows[] = [
'invoice_id' => $invoiceId,
'test_id' => $test['test_id'],
'price' => $test['price'],
'status' => 'Pending'
];
}
if (!$this->invoiceTestModel->insertBatch($testRows)) {
return $this->failServerError('Failed to save invoice tests.');
}
return $this->respondCreated(['id' => $invoiceId], 'Invoice created successfully.');
}
/**
* Return the editable properties of a resource object.
*
* @param int|string|null $id
*
* @return ResponseInterface
*/
public function edit($id = null)
{
if ($id == null) {
return $this->failNotFound('Invoice ID is required.');
}
$invoice = $this->model
->select('invoices.*, patients.id as patient_id, patients.name as patient_name, patients.age as patient_age, patients.sex as patient_sex, patients.phone as patient_phone')
->join('patients', 'patients.id = invoices.patient_id')
->where('invoices.id', $id)
->first();
if ($invoice === null) {
return $this->failNotFound('Invoice not found.');
}
$invoice['tests'] = $this->invoiceTestModel
->select('tests.code, tests.name, invoice_tests.price')
->join('tests', 'tests.id = invoice_tests.test_id')
->where('invoice_tests.invoice_id', $id)
->findAll();
return $this->respond($invoice);
}
/**
* Add or update a model resource, from "posted" properties.
*
* @param int|string|null $id
*
* @return ResponseInterface
*/
public function update($id = null)
{
if ($id === null) {
return $this->failNotFound('Invoice ID is required.');
}
$invoice = $this->model->find($id);
if (!$invoice) {
return $this->failNotFound('Invoice not found.');
}
$data = $this->request->getJSON(true);
$invoiceData = [
'lab_number' => $data['lab_number'] ?? $invoice['lab_number'],
'patient_id' => $data['patient_id'] ?? $invoice['patient_id'],
'referred_by' => $data['referred_by'] ?? $invoice['referred_by'],
'invoice_date' => $data['invoice_date'] ?? $invoice['invoice_date'],
'total_amount' => $data['total_amount'] ?? $invoice['total_amount'],
'discount' => $data['discount'] ?? $invoice['discount'],
'discounted_amount' => $data['discounted_amount'] ?? $invoice['discounted_amount'],
'paid_amount' => $data['paid_amount'] ?? $invoice['paid_amount'],
'balance' => $data['balance'] ?? $invoice['balance'],
'collecting_date' => $data['collecting_date'] ?? $invoice['collecting_date'],
];
if (!$this->model->update($id, $invoiceData)) {
return $this->failValidationErrors($this->model->errors());
}
if(!isset($data['tests']) || !is_array($data['tests']) || empty($data['tests'])) {
return $this->respond(
['id' => $id],
'Invoice updated successfully.'
);
}
$this->invoiceTestModel->where('invoice_id', $id)->delete();
$tests = $data['tests'] ?? [];
$testRows = [];
foreach ($tests as $test) {
if (!isset($test['test_id']) || !isset($test['price'])) {
return $this->failValidationErrors('Each test must include test_id and price.');
}
$testRows[] = [
'invoice_id' => $id,
'test_id' => $test['test_id'],
'price' => $test['price'],
'status' => 'Pending'
];
}
if (!empty($testRows) && !$this->invoiceTestModel->insertBatch($testRows)) {
return $this->failServerError('Failed to save updated invoice tests.');
}
return $this->respondUpdated(['id' => $id], 'Invoice updated successfully.');
}
/**
* Delete the designated resource object from the model.
*
* @param int|string|null $id
*
* @return ResponseInterface
*/
public function delete($id = null)
{
if ($id == null) {
return $this->failNotFound('Invoice ID is required.');
}
$invoice = $this->model->find($id);
if (!$invoice) {
return $this->failNotFound('Invoice not found.');
}
if (!$this->model->delete($id)) {
return $this->failServerError('Failed to delete invoice.');
}
return $this->respondDeleted(['id' => $id], 'Invoice deleted successfully.');
}
public function getInvoiceByPatientId($patientId = null)
{
if ($patientId === null) {
return $this->failNotFound('Patient ID is required.');
}
$patient = $this->patientModel->find($patientId);
if (!$patient) {
return $this->failNotFound('Patient not found.');
}
$invoices = $this->model
->select('invoices.*, patients.id as patient_id, patients.name as patient_name, patients.age as patient_age, patients.sex as patient_sex, patients.phone as patient_phone')
->join('patients', 'patients.id = invoices.patient_id')
->where('patients.id', $patientId)
->findAll();
if (empty($invoices)) {
return $this->failNotFound('No invoices found for this patient.');
}
foreach ($invoices as &$invoice) {
$invoice['tests'] = $this->invoiceTestModel
->select('tests.code, tests.name, invoice_tests.price')
->join('tests', 'tests.id = invoice_tests.test_id')
->where('invoice_tests.invoice_id', $invoice['id'])
->findAll();
}
return $this->respond($invoices);
}
public function getInvoiceByLabNumber($labNumber = null)
{
if ($labNumber === null) {
return $this->failNotFound('Lab number is required.');
}
$invoice = $this->model
->select('invoices.*, patients.id as patient_id, patients.name as patient_name, patients.age as patient_age, patients.sex as patient_sex, patients.phone as patient_phone')
->join('patients', 'patients.id = invoices.patient_id')
->where('invoices.lab_number', $labNumber)
->first();
if (!$invoice) {
return $this->failNotFound('Invoice not found.');
}
$invoice['tests'] = $this->invoiceTestModel
->select('tests.code, tests.name, invoice_tests.price')
->join('tests', 'tests.id = invoice_tests.test_id')
->where('invoice_tests.invoice_id', $invoice['id'])
->findAll();
return $this->respond($invoice);
}
public function getInvoiceTestById($id = null)
{
if ($id === null) {
return $this->failNotFound('Invoice Test ID is required.');
}
$invoiceTest = $this->invoiceTestModel
->select('invoice_tests.*, invoices.id as invoice_id, invoices.lab_number as lab_number, invoices.referred_by as referred_by, patients.id as patient_id, patients.name as patient_name, patients.age as patient_age, patients.sex as patient_sex, patients.phone as patient_phone, tests.id as test_id, tests.code as test_code, tests.name as test_name')
->join('invoices', 'invoices.id = invoice_tests.invoice_id')
->join('tests', 'tests.id = invoice_tests.test_id')
->join('patients', 'patients.id = invoices.patient_id')
->first();
if (!$invoiceTest) {
return $this->failNotFound('Invoice Test not found.');
}
$testItems = $this->testItemModel
->select('test_items.*')
->where('test_items.test_id', $invoiceTest['test_id'])
->findAll();
$reportDetails = $this->reportDetailModel
->select('report_details.*')
->join('reports', 'reports.id = report_details.report_id')
->join('invoice_tests', 'invoice_tests.id = reports.invoice_test_id')
->where('invoice_tests.id', $id)
->findAll();
$detailsByTestItemId = [];
foreach ($reportDetails as $detail) {
$detailsByTestItemId[$detail['test_item_id']] = $detail;
}
foreach ($testItems as &$item) {
if (isset($detailsByTestItemId[$item['id']])) {
$item['result'] = $detailsByTestItemId[$item['id']]['result'];
$item['remarks'] = $detailsByTestItemId[$item['id']]['remarks'];
} else {
$item['result'] = null;
$item['remarks'] = null;
}
}
unset($item);
$invoiceTest['test_items'] = $testItems;
return $this->respond($invoiceTest);
}
public function getInvoicesTestsByStatus()
{
$status = $this->request->getGet('status');
if($status !== 'Pending' && $status != 'Completed' && $status != 'Cancelled') {
return $this->fail('Invalid status. Only "Pending", "Cancelled" and "Completed" are allowed.');
}
$invoices = $this->invoiceTestModel
->select('invoice_tests.*, invoices.lab_number as lab_number, invoices.referred_by as referred_by, patients.id as patient_id, patients.name as patient_name, patients.age as patient_age, patients.sex as patient_sex, patients.phone as patient_phone, tests.id as test_id, tests.code as test_code, tests.name as test_name')
->join('invoices', 'invoices.id = invoice_tests.invoice_id')
->join('tests', 'tests.id = invoice_tests.test_id')
->join('patients', 'patients.id = invoices.patient_id')
->where('invoice_tests.status', $status)
->orderBy('invoices.lab_number', 'DESC')
->findAll();
$testIds = array_unique(array_column($invoices, 'test_id'));
if (empty($testIds)) {
return $this->respond([]);
}
$testItems = $this->testItemModel
->select('test_items.*')
->whereIn('test_items.test_id', $testIds)
->findAll();
$testItemsByTestId = [];
foreach ($testItems as $item) {
$testItemsByTestId[$item['test_id']][] = $item;
}
foreach ($invoices as &$invoiceTest) {
$tid = $invoiceTest['test_id'];
$invoiceTest['test_items'] = $testItemsByTestId[$tid] ?? [];
}
unset($invoiceTest);
return $this->respond($invoices);
}
}
Back to Directory
File Manager