Total sum of several columns in a table - php

I am currently having problem with my total. Well, I have 3 different tables. billing_payments, billing_entry, and services.
My problem is, I can't get the total of each SERVICES. I provided a screenshot so that you'll get what I mean.
Here is the code of the report. I have added some comments to indicate where the problem starts and ends.
<table class="table table-striped table-hover">
<thead>
<tr>
<th>#</th>
<th>PATIENT NAME</th>
<th>CASE</th>
<?php
$servicesquery = $this->db->get('services');
foreach ($servicesquery->result() as $service) {
echo '<th>'.$service->service_name.'</th>';
}
?>
<th>MEDICAL SUPPLIES</th>
<th>PHILHEALTH</th>
<th>DISCOUNT</th>
<th>GROSS</th>
<th>NET</th>
<tr>
</thead>
<tbody>
<?php
$x = 1;
$billquery = $this->db->query('SELECT * FROM `billing_payments` WHERE (`date` BETWEEN "'.$this->input->get('from').'" AND "'.$this->input->get('to').'")');
foreach ($billquery->result() as $data) {
echo '<tr>';
echo '<td>'.$x++.'</td>';
echo '<td>'.$data->patientname.'</td>';
echo '<td>'.$data->session_id.'</td>';
//SERVICES
$servicesquery = $this->db->get('services');
foreach ($servicesquery->result() as $service) {
$this->db->where('billing_serviceid', $service->service_id);
$this->db->where('billing_patientid', $data->patient_id);
$this->db->where('billing_id', $data->billing_id);
$this->db->select_sum('billing_amount');
$billing = $this->db->get('billing_entry');
foreach ($billing->result() as $bill) {
echo '<td>'.$bill->billing_amount.'</td>';
}
}
//MEDICAL SUPPLIES
$this->db->where('billing_id', $data->billing_id);
$this->db->where('billing_servicename', 'MEDICAL SUPPLIES');
$this->db->select_sum('billing_amount');
$medsup = $this->db->get('billing_entry');
foreach ($medsup->result() as $med) {
echo '<td>'.$med->billing_amount.'</td>';
}
//PHILHEALTH
$this->db->where('billing_id', $data->billing_id);
$this->db->select_sum('billing_philhealth');
$philhealth = $this->db->get('billing_entry');
foreach ($philhealth->result() as $phil) {
echo '<td class="bg-info">'.$phil->billing_philhealth.'</td>';
}
//DISCOUNT
$this->db->where('billing_id', $data->billing_id);
$this->db->select_sum('billing_discount');
$philhealth = $this->db->get('billing_entry');
foreach ($philhealth->result() as $phil) {
echo '<td class="bg-info">'.$phil->billing_discount.'</td>';
}
//GROSS
$this->db->where('billing_id', $data->billing_id);
$this->db->select_sum('billing_amount');
$gross = $this->db->get('billing_entry');
foreach ($gross->result() as $gr) {
echo '<td class="bg-warning">'.$gr->billing_amount.'</td>';
}
echo '<td class="bg-danger">'.$data->total_amount.'</td>';
echo '</tr>';
}
echo '<tr>';
echo '<td colspan="3" style="text-align:right"><strong>TOTAL:</strong></td>';
//PROBLEM STARTS HERE
//TOTAL PER SERVICES
$quer = $this->db->get('services');
foreach ($quer->result() as $service) {
$totserv = $this->db->query('SELECT * FROM `billing_payments` WHERE (`date` BETWEEN "'.$this->input->get('from').'" AND "'.$this->input->get('to').'")');
foreach ($totserv->result() as $servdata) {
$id = $servdata->id;
$this->db->where('billing_id', $servdata->billing_id);
$this->db->where('billing_serviceid', $service->service_id);
$this->db->select_sum('billing_amount');
$medsup = $this->db->get('billing_entry');
foreach ($medsup->result() as $med) {
echo '<td class="bg-success">'.$med->billing_amount.'</td>';
}
}
}
//PROBLEM ENDS HERE
//TOTAL NET
$totalamt = $this->db->query('SELECT SUM(total_amount) AS totalamount FROM `billing_payments` WHERE (`date` BETWEEN "'.$this->input->get('from').'" AND "'.$this->input->get('to').'")');
foreach ($totalamt->result() as $data) {
echo '<td>'.$data->totalamount.'</td>';
}
echo '</tr>';
?>

If you look at your image, it's clear to see you're outputting each value from the columns (in the green box) in your final row (350, zero, 350, 485, 485, 485, zero, 15, 300)
You can fix this by adding a placeholder variable to calculate the total for each service, e.g.:
foreach ($quer->result() as $service) { // you want to output one <td> per service, so the <td> should be printed at the end of this foreach
$serviceTotal = 0; // initialize the total for each service
$totserv = $this->db->query('SELECT * FROM `billing_payments` WHERE (`date` BETWEEN "'.$this->input->get('from').'" AND "'.$this->input->get('to').'")');
foreach ($totserv->result() as $servdata) {
$id = $servdata->id;
$this->db->where('billing_id', $servdata->billing_id);
$this->db->where('billing_serviceid', $service->service_id);
$this->db->select_sum('billing_amount');
$medsup = $this->db->get('billing_entry');
foreach ($medsup->result() as $med) {
$serviceTotal = $serviceTotal + $med->billing_amount
}
}
echo '<td class="bg-success">'. $serviceTotal .'</td>';
}
This way you will get one per service, and the $serviceTotal variable will contain the sum of each individual line item for that particular service.
You have more efficient options open to you as well - firstly, you could calculate the individual totals when you are getting them in the services code block, e.g.:
$serviceTotals = array(); // a holder for all the totals
foreach ($servicesquery->result() as $service) {
$this->db->where('billing_serviceid', $service->service_id);
$this->db->where('billing_patientid', $data->patient_id);
$this->db->where('billing_id', $data->billing_id);
$this->db->select_sum('billing_amount');
$billing = $this->db->get('billing_entry');
foreach ($billing->result() as $bill) {
$serviceTotals[$service->service_id] = $serviceTotals[$service->service_id] + $bill->billing_amount; //this updates the total for each service ID
echo '<td>'.$bill->billing_amount.'</td>';
}
}
You could then loop through this array to output each total.
Ideally, you should also consider calculating all these values in your controller, which would call the queries you need from your model(s), and then packaging that data in your $data variable. The controller can then pass all of that to your view. CodeIgniter has a lot of good resources for explaining the Model-View-Controller (MVC) pattern (it's a bit outside of the scope of this question to go into it here), and using CI without implementing the MVC pattern is going to make it harder to make use of most of the documentation and support for CI on the net.

Related

Getting all data after clicking a particular cell in a table

Dbfiddle: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=65b310b4b973a7577d4953e01c09a124
Currently I have a table that displays a total count of my data values for each source. I'm getting this value after comparing 2 tables 1 is crm_leads with all my product information and 1 is crm_sources with what sources are the products related to.
Now this is the output:
Now as you can see the total count is shown under each header next to its source. There are 8 cells for each source as seen in the picture. Now these count values are inside a tags which once clicked go to viewall page.
Now here basically I want to show the data of the item that I had clicked. So for example, if I clicked the 163 under Hot status, it takes me to the viewall page and shows me id, source, enquiry_date for all those under status Hot in a table.
So basically it should detect the data for which source and which status is clicked and then accordingly make a statement like this?
select * from crm_leads where lead_source = '.$source.' and lead_status = '.$status.';
Another thing I'm thinking I can do here is put my table inside a form and pass those values as post in my controller class leadstatus which will pass that value to viewall? Not really sure on how to proceed.
Model Class:
function get_statusreport($fdate='',$tdate='')
{
$this->db->select("l.lead_status,crm_sources.title,count(*) as leadnum,l.enquiry_date,l.sub_status");
$this->db->from($this->table_name." as l");
if($fdate !='')
$this->db->where("date(l.added_date) >=",date('Y-m-d',strtotime($fdate)));
if($tdate !='')
$this->db->where("date(l.added_date) <=",date('Y-m-d',strtotime($tdate)));
$this->db->where("lead_status <>",10);
$this->db->join("crm_sources ","crm_sources.id= l.lead_source","left");
$this->db->group_by("l.lead_status,crm_sources.title");
$this->db->order_by("leadnum DESC, crm_sources.title ASC,l.lead_status ASC");
$query = $this->db->get();
$results = $query->result_array();
return $results;
}
Controller Class(leadstatus holds the view for my current table):
public function leadstatus($slug='')
{
$content='';
$content['groupedleads'] = $this->leads_model->get_statusreport($fdate,$tdate);
$this->load->view('crm/main',$main);
$this->load->view('crm/reports/leadstatus',$content);
}
public function viewall($slug='')
{
$content='';
$this->load->view('crm/main',$main);
$this->load->view('crm/reports/viewall',$content);
}
View class:
<?php
$ls_arr = array(1=>'Open',8=>'Hot',2=>'Closed',3=>'Transacted',4=>'Dead');
foreach($groupedleads as $grplead){
$statuses[] = $status = $ls_arr[$grplead["lead_status"]];
if($grplead["title"] == NULL || $grplead["title"] == '')
$grplead["title"] = "Unknown";
if(isset($grplead["title"]))
$titles[] = $title = $grplead["title"];
$leaddata[$status][$title] = $grplead["leadnum"];
}
if(count($titles) > 0)
$titles = array_unique($titles);
if(count($statuses) > 0)
$statuses = array_unique($statuses);
?>
<table>
<tr">
<th id="status">Source</th>
<?php
if(count($statuses) > 0)
foreach($statuses as $status){
?><th id=<?php echo $status; ?>><?php echo $status; ?></th>
<?php
}
?>
<th>Total</th>
</tr>
<?php
if(is_array($titles))
foreach($titles as $title){
?>
<tr>
<?php
$total = 0;
echo "<td>".$title."</td>";
foreach ($statuses as $status) {
$num = $leaddata[$status][$title];
echo "<td><a target='_blank' href='".site_url('reports/viewall')."'>".$num."</a></td>";
$total += $num;
$sum[$status] += $num;
}
echo "<td>".$total."</td>";
$grandtotal += $total;
?>
</tr>
<?php } ?>
</table>
You can include the source and status in the URL like this:
foreach ($statuses as $status) {
$num = $leaddata[$status][$title];
echo "<td><a target='_blank' href='" . site_url('reports/viewall?source=' . $source . '&status=' . $status) . "'>" . $num . "</a></td>";
$total += $num;
$sum[$status] += $num;
}
Then in your controller:
public function viewall($slug = '')
{
$content = '';
$source = $this->input->get('source');
$status = $this->input->get('status');
// Do what you want with $source and $status
$this->load->view('crm/main', $main);
$this->load->view('crm/reports/viewall', $content);
}

Unable to get database results using whereMonth query inside a for loop php laravel

I want to query a database by making use of a whereMonth clause in laravel using a for loop but I am getting an empty array. If I replace $m in whereMonth clause with an integer like 7 it pulls the data.
<table class="table table-bordered table-hover expenses-report" id="expenses-report-table">
<thead>
<tr>
<th class="bold">Category</th>
<?php
for ($m=1; $m<=12; $m++) {
echo ' <th class="bold">' .date('F', mktime(0,0,0,$m,1)) . '</th>';}
?>
<th class="bold">year ({{\Carbon\Carbon::now()->format('Y')}})</th>
<?php
?>
</tr>
</thead>
<tbody>
#foreach ($categories as $category)
<tr>
<td>
{{$category->name}}
<?php
for ($m = 1; $m <= 12; $m++) {
if (!isset($netMonthlyTotal[$m])) {
$netMonthlyTotal[$m] = array();
}
$expense_results = $expenses->whereMonth('date',$m)
->whereYear('date', \Carbon\Carbon::now()->format('Y'))
->where('category', $category->id)
->get();
print_r($expense_results);
$total_expenses = array();
echo '<td>';
foreach ($expense_results as $expense) {
$expense = $expenses->where('id', $expense->id)->first();
$total = $expense->amount;
$totalTaxByExpense = 0;
// Check if tax is applied
if ($expense->tax != 0) {
$totalTaxByExpense+= ($total / 100 * $expense->tax);
}
$taxTotal[$m][] = $totalTaxByExpense;
$total_expenses[] = $total;
}
$total_expenses = array_sum($total_expenses);
// Add to total monthy expenses
array_push($netMonthlyTotal[$m], $total_expenses);
if (!isset($totalNetByExpenseCategory[$category->id])) {
$totalNetByExpenseCategory[$category->id] = array();
}
array_push($totalNetByExpenseCategory[$category->id], $total_expenses);
// Output the total for this category
if (count($categories) <= 8) {
echo $total_expenses;
} else {
// show tooltip for the month if more the 8 categories found. becuase when listing down you wont be able to see the month
echo '<span data-toggle="tooltip"
title="' . date('F', mktime(0, 0, 0, $m, 1)) . '">' . $total_expenses . '</span>';
}
echo '</td>';
}
?>
</td>
<td class="bg-odd">
{{array_sum($totalNetByExpenseCategory[$category->id])}}
</td>
</tr>
#endforeach
</tbody>
</table>
I basically want to return results matching the search query including the whereMonth
Can you replace this part
$query->whereMonth('date', $m);
with this
$query->whereMonth('date', (string) $m);
And then try again. I guess its not accepting integers.
I was able to get it to work by making use of Raw query
$rawQuery ="SELECT amount, id,tax FROM tblexpenses WHERE MONTH(date) = $m AND YEAR(CURRENT_DATE) AND category=$category->id GROUP BY id";
$expense_results = DB::select(DB::raw($rawQuery));
Though I would appreciate it if someone can help to translate this query to laravel

Unable to use an array as an array?

I am in the process of building a software download site for my company.
However, I have come across a problem that I am unsure how to get past.
I am retrieving all the information from a table about a particular software release and placing them in a multidimensional array. I am then trying to run a foreach (I have even tried a for loop) against that array and I get an error shown below:
When I run var dump against the original array, I get this:
So I am really confused as I don't know what I'm missing or where I am going wrong. The reason why I want to run this is so that I can filter the array into a one dimensional array.
Below is the code for the main web page
<?php
//Displays list of companies in 2 columns
$versionAccess = VersionAccess::findAccess($relId);//This gets set earlier in the webpage
$count = count($versionAccess);
var_dump($versionAccess);
foreach ($versionAccess as $va)
{
if ($va->company_access != '0')
{
$versionAcc[] = $va->comapny_id;
}
}
foreach ($company as $compAccess)
{
$compAccessId = $compAccess->company_id;
if (in_array($compAccessId, $versionAcc))
{
$access = 'checked disabled';
}
else { $access = 'disabled'; }
$accessName = 'access'.$compAccessId;
if ($ctr % 2 == 0)
{
echo '<td>'.$compAccess->company_name.':</td>';
echo '<td><label class="switch"><input type="checkbox" name="'.$accessName.'" value="1" '.$access.'><span class="slider round"></span></label></td>';
echo '</tr>';
}
else
{
if ($ctr < $compCount)
{
echo '<tr>';
echo '<td>'.$compAccess->company_name.':</td>';
echo '<td><label class="switch"><input type="checkbox" name="'.$accessName.'" value="1" '.$access.'><span class="slider round"></span></label></td>';
}
else
{
echo '<tr>';
echo '<td>'.$compAccess->company_name.':</td>';
echo '<td><label class="switch"><input type="checkbox" name="'.$accessName.'" value="1" '.$access.'><span class="slider round"></span></label></td>';
echo '</tr>';
}
}
$ctr++;
}
?>
The function that brings the data from the database is:
public static function findAccess($accessId)
//find the version access in database
{
return self::findQuery("SELECT * FROM version_access WHERE version_id = '$accessId'");
}
The findQuery method:
public static function findQuery($sql)
{
global $database;
$resultSet = $database->query($sql);
$objectArray = array();
while ($row = mysqli_fetch_array($resultSet))
{
$objectArray[] = self::instant($row);
}
return $objectArray;
}
I am still relatively new and any help is greatly appreciated.

Too many queries, php. Creating lite forum engine

I've started to writing my engine of forum, just to refresh php skills.
My problem is that, when I make a board and one theard, I have double queries.
I know why, I have "foreach in different foreach" but I cannot find a way to sort it out, can you guys help me how would you do it? To avoid this big number of queries?
An example, SMF forum main page has only 12 queries (NO MATTER OF NUMBERS BOARDS AND THEARDS).
My page have 12 already, but I have only 2 categories, 5 boards, 4 theards, 1 user.
If I add one board, and one theard I have +2 queries.
<?php
if(!defined('USED'))
exit;
# Name of page!
$page = 'Forum';
$db = new Database();
$array = $db -> select("SELECT `id`,`name` FROM `".PREFIX."category`");
if(count($array) > 0)
{
$container .= '';
foreach($array as $category)
{
$container .= '<div class="panel panel-primary" id="category-'.$category['id'].'">
<div class="panel-heading">
<h3 class="panel-title">
'.$category['name'].'
</h3>
</div>
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th class="col-md-9">Board Name</th>
<th class="col-md-3">Latest</th>
</tr>
</thead>';
$array2 = $db -> select("SELECT `id`,`id_category`,`name`,`info` FROM `".PREFIX."boards` WHERE `id_category`=".$category['id']."");
if(count($array2) > 0)
{
foreach($array2 as $board)
{
$container .='<tbody>
<tr>
<td>
<strong>'.$board['name'].'</strong><br/>
<small>'.$board['info'].'</small>
</td>';
$array3 = $db -> select("SELECT `id`,`id_board`,`title`,`created_by`,`created_date` FROM `".PREFIX."theards` WHERE `id_board`=".$board['id']." ORDER BY `created_date` DESC LIMIT 1");
if(count($array3) > 0)
{
foreach($array3 as $theards)
{
$array4 = $db -> select("SELECT `id`,`name` FROM `".PREFIX."users` WHERE `id`=".$theards['created_by']."");
foreach($array4 as $user)
{
$created_by = $user['name'];
}
$container .='<td>
'.$theards['title'].'<br/><small>'.$created_by.', <abbr class="timeago" title="'.$theards['created_date'].'">less than a month ago</abbr></small>
</td>';
}
}
else
{
$container .= '<td>
Nothing is here!
</td>';
}
$container .=' </tr>
</tbody>';
}
}
else
{
$container .='<tbody>
<tr>
<td>Nothing is here!</td>
<td>...</td>
</tr>
</tbody>';
}
$container .='</table>
</div>';
}
}
else
{
Site::Error("You need to add a category first!");
}
And my select:
public function select($query) {
$rows = array();
$result = $this -> query($query);
if($result === false) {
return false;
}
while ($row = $result -> fetch_assoc()) {
$rows[] = $row;
}
global $db_count;
$db_count = !isset($db_count) ? 1 : $db_count + 1;
return $rows;
}
Ive added $db_count at the end of the file to check numbers of queries.
Instead of running one query to get a list of IDs, then looping across those IDs to get another set of IDS, then looping across those IDs to get a set of data, how about writing one query, using a JOIN to line up the three tables?

applying stylesheet class for dynamic rows

I am trying to apply css class for dynamic rows in php. But its not happening. Here is my code
please someone suggest me where i am going wrong. I have declared a counter for rows but not getting where to increment its count.
<table width='100%' border='0' cellspacing='0' cellpadding='2'>
<tr>
<td class='tddash'>10 latest unpaid customer invoices</td>
</tr>
<tr>
<td valign='top'>";
$SQL = "SELECT salesorders.orderno,
debtorsmaster.name,
custbranch.brname,
salesorders.customerref,
salesorders.orddate,
salesorders.deliverydate,
salesorders.deliverto,
salesorders.printedpackingslip,
salesorders.poplaced,
SUM(salesorderdetails.unitprice*salesorderdetails.quantity*(1-salesorderdetails.discountpercent)/currencies.rate) AS ordervalue
FROM salesorders INNER JOIN salesorderdetails
ON salesorders.orderno = salesorderdetails.orderno
INNER JOIN debtorsmaster
ON salesorders.debtorno = debtorsmaster.debtorno
INNER JOIN custbranch
ON debtorsmaster.debtorno = custbranch.debtorno
AND salesorders.branchcode = custbranch.branchcode
INNER JOIN currencies
ON debtorsmaster.currcode = currencies.currabrev
WHERE salesorderdetails.completed=0
GROUP BY salesorders.orderno,
debtorsmaster.name,
custbranch.brname,
salesorders.customerref,
salesorders.orddate,
salesorders.deliverydate,
salesorders.deliverto,
salesorders.printedpackingslip,
salesorders.poplaced
ORDER BY salesorders.orderno";
$SalesOrdersResult1 = DB_query($SQL,$db);
echo "<table width='100%' celpadding='2' class='selection'><tbody>";
$TableHeader = "<tr><th> Customer </th><th>Order Date</th><th>Delivery Date</th><th>Delivery To</th><th>Order Total</th></tr> ";
$k = 0;
while ($row = DB_fetch_array($SalesOrdersResult1))
{
if ($k == 1){
echo '<tr class="EvenTableRows">';
$k = 0;
} else {
echo '<tr class="OddTableRows">';
$k = 1;
}
$FormatedOrderValue1 = locale_number_format($row['ordervalue'],$row['currdecimalplaces']);
//$TotalOrderValue = $array_sum($FormatedOrderValue1);
//$FormatedOrderValue1 = locale_number_format($myrow['ordervalue'],$_SESSION['CompanyRecord']['decimalplaces']);
$FormatedOrderDate = ConvertSQLDate($row['orddate']);
$FormatedDelDate = ConvertSQLDate($row['deliverydate']);
echo " <td> " . $row['name'] . " </td>";
echo " <td>$FormatedOrderDate</td><td>$FormatedDelDate</td><td> " . $row['deliverto'] . " </td><td>$FormatedOrderValue1</td> ";
}
//echo "<tr><td colspan='3'>Total</td><td colspan='2'>$TotalOrderValue</td></tr></tbody>";
//echo $array_sum($FormatedOrderValue1);
echo "</table>";
echo"</td>
</tr>
</table>
Try to put this inside your while loop.
if ($k == 1){
echo '<tr class="EvenTableRows">';
$k = 0;
} else {
echo '<tr class="OddTableRows">';
$k = 1;
}
If you want decorate your table, and you can use css use it. Don't use server side language
tr:nth-child(even) {background: #CCC}
tr:nth-child(odd) {background: #FFF}
Three issues with your code (four if you count the fact that you have a massive amount of HTML that should be moved outside of being echo'ed within php)
1) You have no $k++; to increment your $k value
2) You have a "tr" within the $row['name'] line that needs to be removed.
3) You need to move the entire if($k) block INSIDE of your while() loop.

Categories