Foreach in foreach wrong calculation - php

I have two tables. One of them is called "customer" and the other is "current account".
I want to do; To collect the debit and credit columns in the current account table of data recorded in the customer table and draw the result. But somehow I cannot do the correct calculation. I leave my sample codes below.
Thank you in advance for your support.
Table Name : Customer Table name : Current Account
| tax | company_name |tax_no| debt | take
______________________ _________________________
| 1234| Company One |1234 | 9 |
| 5678| Company Second |1234 | | 3
|1234 | 15 |
|5678 | 4 |
|5678 | | 1
According to the table above, what I want to do is combine the data in the current account table according to the data in the customer table, take the debt from the receivable and get the result.
// Data list
$sql = $db->query("SELECT*FROM customer ORDER BY company_name ASC");
$sum_debt = 0;
$sum_take = 0;
foreach($sql->results() as item){
$tax = $item->tax;
$current = $db->query("SELECT*FROM current_account WHERE tax_no = '$tax' ");
foreach($current->results() as $row){
$sum_debt += $row->debt;
$sum_take += $row->take;
$res = $sum_take - $sum_debt;
}
}
The result is always wrong. It makes the conclusion by making the correct operation of the first data. It collects the first result over the next data.
The results that should be obtained according to the table; company one is: -24, company second is -3, but the second data is -27.

If you want to calculate the total per company, you should reset the debt and take for every new company and move the $res = $sum_take - $sum_debt; line from the inner foreach to the outer foreach and save the result for every company it is calculated.
// Data list
$sql = $db->query("SELECT*FROM customer ORDER BY company_name ASC");
$sum_debt = 0;
$sum_take = 0;
foreach($sql->results() as item)
{
$sum_debt = 0;
$sum_take = 0;
$tax = $item->tax;
current = $db->query("SELECT*FROM current_account WHERE tax_no = '$tax' ");
foreach($current->results() as $row){
$sum_debt += $row->debt;
$sum_take += $row->take;
}
$res = $sum_take - $sum_debt;
//Save or print res
echo $tax . " has debt: " . $res;
}
I would also highly recommend to retrieve all the nescessary calculated data within the first SQL query. Doing a query per company can be expensive and result in poor performance. The SQL would be something like:
SELECT c.tax,
c.company_name,
(SELECT SUM(take) FROM [Current Amount] WHERE tax_no = tax) -
(SELECT SUM(debt) FROM [Current Amount] WHERE tax_no = tax) AS [res]
FROM Company

If $res should contain the current account balance of a customer you need to move the calculation of $res outside of the inner for-loop and reset the sum_debt and sum_take for each customer:
$sql = $db->query("SELECT*FROM customer ORDER BY company_name ASC");
//for loop for each customer
foreach($sql->results() as item){
$sum_debt = 0; //debt of this customer
$sum_take = 0; //credit of this customer
$tax = $item->tax;
$current = $db->query("SELECT*FROM current_account WHERE tax_no = '$tax' ");
foreach($current->results() as $row){
$sum_debt += $row->debt;
$sum_take += $row->take;
}
$res = $sum_take - $sum_debt; //account balance of this customer
}
Also you could simplify your code by directly calculating the account balance:
$sql = $db->query("SELECT*FROM customer ORDER BY company_name ASC");
//for loop for each customer
foreach($sql->results() as item){
$balance_of_this_customer = 0;
$tax = $item->tax;
$current = $db->query("SELECT*FROM current_account WHERE tax_no = '$tax' ");
foreach($current->results() as $row){
$balance_of_this_customer -= $row->debt;
$balance_of_this_customer += $row->take;
}
}

I think you could do this in one SQL query and no query in a loop.
SELECT customer.company_name, customer.tax, SUM(current_account.debt) AS total_debt, SUM(current_account.take) AS total_take FROM customer LEFT JOIN current_account ON current_account.tax_no = customer.tax GROUP BY customer.tax

try this. i've fixed your problem and edited your code with better syntax, ofcourse in myself opinion
$data = array();
$customers = $db->query("SELECT * FROM `customer` ORDER BY `company_name` ASC");
$customers = $customers->results();
$result = 0;
foreach($customers as $customer){
if(!isset($data[$customer['id']])){
$data[$customer['id']] = array(
'balance' => 0,
'debt' => 0,
'take' => 0
);
}
$accounts = $db->query("SELECT * FROM `current_account` WHERE `tax_no` = '" . $customer->tax . "'");
$accounts = $accounts->results();
foreach($accounts as $account){
$data[$customer['id']]['take'] += $row->take;
$data[$customer['id']]['debt'] += $row->debt;
$data[$customer['id']]['balance'] = $data[$customer['id']]['take'] - $data[$customer['id']]['debt'];
}
}
print_r($data);

Related

Php Mysqli how to sum two different condition result

Below query works but it shows two different sum of different orders perfectly as i made GROUP BY ORDER_ID as (1000, 2000).
But i want this (1000, 2000) as (3000). If there are 2 orders in a week 1 has percentage based discount and one is without discount and each order has different delivery charge.
Each order has different discount percentage, and different delivery charge.
That's why i did group by order_id in my query and if i removes group by order_id it gives me a different total amount. But With the group by order_id it shows the correct amount of as much orders are in the current week or month or year.
Please help in this regard.
Below is my query what im trying to do.
$totalX = "select sum(price) as price, coupon, city, delivery_type, order_id
from orders where date between '2018-09-12' and '2018-09-13' group by order_id";
$totalXx = $dba2->query($totalX);
while ($total = $totalXx->fetch_assoc()) {
$couponX = "select coupon, price, percent from couponsAll where id = '".$total['coupon']."'";
$couponXx = $dba->query($couponX);
$coupon = $couponXx->fetch_assoc();
$areaBX = "select * from countries_citiesALL where id = '".$total['city']."' ";
$areaBXx = $dba->query($areaBX);
$areaBXxx = $areaBXx->fetch_assoc();
$area6X = "select * from delivery_typeALL where area = '".$total['city']."' and id = '".$total['delivery_type']."'";
$area6Xx = $dba->query($area6X);
$area6xXx = $area6Xx->fetch_assoc();
$dchargezQ = $area6xXx['price'];
if ($coupon['price'] >= 1 && $coupon['percent'] < 1) {
/// this condition is if price based discount
$priceAcoup = $total['price'] - $coupon['price'];
$gtotalx = $priceAcoup + $areaBXxx['price'] + $dchargezQ;
$gtotal = number_format($gtotalx, 3);
echo '<font color="black" style=""><b>'.$gtotal.'</b></font>';
} else {
if ($coupon['price'] < 1 && $coupon['percent'] >= 1) {
/// this condition is if percentage based discount
$priceAcoup = $total['price'] - (($total['price'] * $coupon['percent']) / 100);
$gtotalx = $priceAcoup + $areaBXxx['price'] + $dchargezQ;
$gtotal = number_format($gtotalx, 3);
echo '<font color="black" style=""><b>'.$gtotal.'</b></font>';
} else {
/// this condition is if there is no percentage or price based discount
$gtotalx = $total['price'] + $areaBXxx['price'] + $dchargezQ;
$gtotal = number_format($gtotalx, 3);
echo '<font color="black" style=""><b>'.$gtotal.'</b></font>';
}
}
}
Well issue is resolved as mentioned below.
I changed $weekTotal[] under every condition with $weekTotal1[], $weekTotal2[], $weekTotal3[] and put this $weekTotal1=array();, $weekTotal2=array();, $weekTotal3=array(); above the 2nd query loop and got it working.
Thanks for your kind assistance.
$__xz_rTorders1 = $dba2->query("SELECT count(distinct(order_id)) as count, order_id, date FROM orders_confirmed
group by WEEK(date), MONTH(date)
order by WEEK(date), MONTH(date)
");
while($__xz_rTordersa4 = $__xz_rTorders1->fetch_assoc()) {
$__xz_signupweek = $__xz_rTordersa4['date'];
/*start day*/
for($__xz_i = 0; $__xz_i <7 ; $__xz_i++) {
$__xz_date = date('Y-m-d', strtotime("-".$__xz_i."days", strtotime($__xz_signupweek)));
$__xz_dayName = date('D', strtotime($__xz_date));
if($__xz_dayName == "Sun") {
//echo "<b>From:</b> ". date( "d/m/Y", strtotime($__xz_date))." / ";
$mstart_date=date( "Y-m-d", strtotime($__xz_date));
}
}
/*end day*/
for($__xz_i = 0; $__xz_i <7 ; $__xz_i++) {
$__xz_date = date('Y-m-d', strtotime("+".$__xz_i."days", strtotime($__xz_signupweek)));
$__xz_dayName = date('D', strtotime($__xz_date));
if($__xz_dayName == "Sat") {
//echo "<b>To:</b> ". date( "d/m/Y", strtotime($__xz_date));
$mend_date=date( "Y-m-d", strtotime($__xz_date));
}
}
///////////////////***********///////////////////
$weekTotal1=array();
$weekTotal2=array();
$weekTotal3=array();
///////////////////***********///////////////////
$totalX= "select sum(price) as price, coupon, city, delivery_type, order_id
from orders_confirmed where date between '".$mstart_date."' and '".$mend_date."'
group by order_id
";
$totalXx= $dba2->query($totalX);
while ($total = $totalXx->fetch_assoc()){
$couponX= "select coupon, price, percent
from coupons
where id = '".$total['coupon']."'
";
$couponXx= $dba->query($couponX);
$coupon = $couponXx->fetch_assoc();
$areaBX= "select * from countries_cities
where id = '".$total['city']."' ";
$areaBXx= $dba->query($areaBX);
$areaBXxx= $areaBXx->fetch_assoc();
$area6X= "select * from delivery_type
where area = '".$total['city']."'
and id = '".$total['delivery_type']."'
";
$area6Xx= $dba->query($area6X);
$area6xXx= $area6Xx->fetch_assoc();
$dchargezQ= $area6xXx['price'];
if ($coupon['price'] >= 1 && $coupon['percent'] < 1) {
$priceAcoup1=$total['price']-$coupon['price'];
///////////////////***********///////////////////
$weekTotal1[] = $priceAcoup1+$areaBXxx['price']+$dchargezQ;
///////////////////***********///////////////////
}else if ($coupon['price'] < 1 && $coupon['percent'] >= 1) {
$priceAcoup2=$total['price']-(($total['price']*$coupon['percent'])/100);
///////////////////***********///////////////////
$weekTotal2[] = $priceAcoup2+$areaBXxx['price']+$dchargezQ;
///////////////////***********///////////////////
}else{
///////////////////***********///////////////////
$weekTotal3[] = $total['price']+$areaBXxx['price']+$dchargezQ;
///////////////////***********///////////////////
}
} // End Of While Loop (2nd)
$weekTotal_val3 = array_sum($weekTotal1);
$weekTotal_val4 = array_sum($weekTotal2);
$weekTotal_val5 = array_sum($weekTotal3);
$finalTOTAL=number_format($weekTotal_val3+$weekTotal_val4+$weekTotal_val5,3);
echo '<font color="red" style=""><b>'.$finalTOTAL.'</b></font>';
} // End Of While Loop (1st)

php inventory and order management system

for($i=0; $i<count($_POST['order_item']); $i++)
{
$order_date=$_POST['order_date'];
$customer_name=$_POST['customer_name'];
$salesman_name=$_POST['salesman_name'];
$area_code=$_POST['area_code'];
$product_name=$_POST['product_name'][$i];
$item_qty=$_POST['item_qty'][$i];//product actual quality
$order_item=$_POST['order_item'][$i]; //order item number
$billed_qty=$_POST['itqty'][$i]; // product billed quantity editable
$prod_mrps=$_POST['mrps'][$i];
$prices=$_POST['price'][$i];
$discount=$_POST['qty'][$i];
$amount=$_POST['total'][$i];
$prod_qty = $_POST['prod_qty'][$i];//available quantity
$batch_no = $_POST['batch_no'][$i];//batch number
$qtyout = 0;
$result = $dbo->query("SELECT `batch_no`, `prod_id`, `prod_name`, `total_qty` FROM `sm_product_batch` where `prod_name` = '$product_name' and `batch_status` = 'Active_batch' order by batch_no asc");
while ($row = $result->fetch(PDO::FETCH_ASSOC))
{
if($billed_qty > 0)
{
$batchout = 0;
$rem = max($row['total_qty']-$billed_qty,0);
if($rem == 0)
$batchout = $row['total_qty']; //This means there are no items of this cost remaining
else
$batchout = $billed_qty; //This means there are items remaining and therefore our next loop (within the while) will check for the next expensive item
$billed_qty -= $batchout;
$qtyout += $batchout;
$sql = "Update sm_product_batch set total_qty = (total_qty - $batchout) where prod_name='".$product_name."' AND batch_no = ".$row["batch_no"];
$dbo->query($sql);
$sql1 = "Update sm_product_batch SET batch_status=CASE WHEN total_qty='0' THEN 'Inactive_batch' ELSE 'Active_batch' END where prod_name='".$product_name."'";
$dbo->query($sql1);
}
}
$sql = "INSERT INTO sm_invoice (order_id,invoice_id,product_name,customer_name,salesman_name,order_item,area_code,order_date,invoice_date,item_qty,billed_qty,batch_no,prod_mrp,price,spl_dis,total) VALUES ('".$order_id."','".$order_id."','".$product_name."','".$customer_name."','".$salesman_name."','".$order_item."','".$area_code."','".$order_date."','".$invoice_date."','".$item_qty."','".$_POST['itqty'][$i]."','".$batch_no."','".$prod_mrps."','".$prices."','".$discount."','".$amount."')";
$dbo->query($sql);
}
This is my code to update inventory with batch and invoice table. This code is only working for my first product. Need this to be done for all products of an order. Any help is appreciated.
for($i=0; $i<count($_POST['order_item']); $i++)
{
$order_date=$_POST['order_date'];
$customer_name=$_POST['customer_name'];
$salesman_name=$_POST['salesman_name'];
$area_code=$_POST['area_code'];
$product_name=$_POST['product_name'][$i];
$item_qty=$_POST['item_qty'][$i];//product actual quality
$order_item=$_POST['order_item'][$i]; //order item number
$billed_qty=$_POST['itqty'][$i]; // product billed quantity editable
$prod_mrps=$_POST['mrps'][$i];
$prices=$_POST['price'][$i];
$discount=$_POST['qty'][$i];
$amount=$_POST['total'][$i];
$prod_qty = $_POST['prod_qty'][$i];//available quantity
$batch_no = $_POST['batch_no'][$i];//batch number
$qtyout = 0;
$result = $dbo->query("SELECT `batch_no`, `prod_id`, `prod_name`, `total_qty` FROM `sm_product_batch` where `prod_name` = '$product_name' and `batch_status` = 'Active_batch' order by batch_no asc");
while ($row = $result->fetch(PDO::FETCH_ASSOC))
{
if($billed_qty > 0)
{
$batchout = 0;
$rem = max($row['total_qty']-$billed_qty,0);
if($rem == 0)
$batchout = $row['total_qty']; //This means there are no items of this cost remaining
else
$batchout = $billed_qty; //This means there are items remaining and therefore our next loop (within the while) will check for the next expensive item
$billed_qty -= $batchout;
$qtyout += $batchout;
$sql = "Update sm_product_batch set total_qty = (total_qty - $batchout) where prod_name='".$product_name."' AND batch_no = ".$row["batch_no"];
$dbo->query($sql);
$sql1 = "Update sm_product_batch SET batch_status=CASE WHEN total_qty='0' THEN 'Inactive_batch' ELSE 'Active_batch' END where prod_name='".$product_name."'";
$dbo->query($sql1);
$sql = "INSERT INTO sm_invoice (order_id,invoice_id,product_name,customer_name,salesman_name,order_item,area_code,order_date,invoice_date,item_qty,billed_qty,batch_no,prod_mrp,price,spl_dis,total) VALUES ('".$order_id."','".$order_id."','".$_POST['product_name'][$i]."','".$customer_name."','".$salesman_name."','".$_POST['order_item'][$i]."','".$area_code."','".$order_date."','".$invoice_date."','".$item_qty."','".$batchout."','".$row["batch_no"]."','".$_POST['mrps'][$i]."','".$_POST['price'][$i]."','".$_POST['qty'][$i]."','".$_POST['total'][$i]."')";
$dbo->query($sql);
}
}
}
Found the answer after lot of debugging.
Thanks for all your response.

How to pull the requests to the database?

Good day! Please tell me how to pull data to obtain information with 3-different tables?
I now have:
$result = $this->db->query("SELECT * FROM oc_order_product WHERE order_id = (SELECT order_id FROM oc_order_product ORDER BY order_product_id DESC LIMIT 1)");
and
EOD;
for($i = 0; $i<count($result->rows); $i++) {
$points = $result->rows[$i]['points'];
$price = $result->rows[$i]['price'];
$counts = $result->rows[$i]['quantity'];
$str .= <<<EOD
And these have come from another table, not with oc_order_product, and oc_product_option_value:
$price = $result->rows[$i]['price'];
$counts = $result->rows[$i]['quantity'];
How do I add correctly**$result** oc_product_option_value and price, quantity? As has just never tried something goes wrong)

PHP - Order a list of database elements

I am displaying a list of items based on a database. The order of the items is by ProductID.
When I add an item to the database, it is automatically assigned a ProductID.
However, I would like to be able to either
a) sort the list alphabetically by name, without changing the ProductID in the database or
b) add another column to the database called, for example: Rank, and have this list display the list by Rank, rather than by ProductID.
Here is my code. Any help in re-writing this section of the code to accomplish either a) or b) would be very helpful!
PS: I'm a little familiar with PHP and databases, but I am by no means an experienced coder.
$category = array_search(strtolower('upright'), $CFG["Category"]);
$product2 = new ProductData();
$where2 = sprintf(" WHERE CategoryID=%d ORDER BY ProductID DESC", $category);
$rows2 = $product2->GetRows($where2);
$count2 = count($rows2);
$line_count2 = 4;
$total_lines2 = ceil($count2/$line_count2);
// Photo
$photo5 = new PhotoData();
$thumb_array5 = array();
$count3 = count($rows2);
for ( $i = 0; $i < $count3; $i++ )
{
$ret = $photo5->Query($rows2[$i]["ProductID"]);
if ( $ret != 0 )
{
continue;
}
$thumb_array5[$photo5->Get("ProductID")] = $photo5->Get("Photo1");
}
Your SELECT query is not shown which I assume is coming from your ProductData() class. If you could change the source of your ProductData() that includes ranking, you could use a variable for ranking, like:
SELECT
#Ranking := #Ranking + 1 AS Rank,
productID,
product_name
FROM yourTable t, (SELECT #Ranking := 0) r
ORDER BY product_name;
Otherwise you could do it in your Php instead:
First change the ORRDER BY to your product name instead of product id:
$category = array_search(strtolower('upright'), $CFG["Category"]);
$product2 = new ProductData();
$where2 = sprintf(" WHERE CategoryID=%d ORDER BY Product_Name", $category);
Then in your php use a variable to do the ranking:
$count3 = count($rows2);
echo "<table><tr><th>Ranking</th><th>Product Name</th><th>Product Name</th></tr>";
for ( $rank = 0; $rank < $count3; $rank++ )
{
echo "<tr>";
echo "<td>$rank+1</td><td>".$rows2[$rank]["Product_name"]."</td><td><img src='".$photo5->Get("Photo1")."'></td>"
echo "</tr>";
}
echo "</table>";

PHP Sum a value in while loop, but with conditions

I have two tables to be joined, 1 is user and 1 is attendance.
TABLE : attendance
id userId totalHours
1 1 0745
2 3 0845
3 1 0945
TABLE : user
id name departmentId
1 John 2
2 Sean 2
3 Allan 2
Not every user have attendance record (their totalHours)
But I need to query by userId WHERE departmentId = XXXX and SUM each of their totalHours that exist, without neglecting the userId without any record in attendance.
So far I made this:
$result = mysqli_query($con,"SELECT * FROM user WHERE departmentId = 2");
while($row = mysqli_fetch_array($result))
{
$id = $row['userId'];
$result2 = mysqli_query($con,"SELECT * FROM attendance WHERE userId = $id");
while($row2 = mysqli_fetch_array($result2))
$totalHours = 0;
{
$totalHours = $row2['totalHours'];
$grandTotal += $totalHours;
$totalHoursInHHmm = substr_replace($totalHours,":",2,0);
$parsed = date_parse($totalHoursInHHmm);
$toSeconds = $parsed['hour'] * 3600 + $parsed['minute'] * 60;
$total += $toSeconds;
$init = $total;
$hours = floor($init / 3600);
$minutes = floor(($init / 60) % 60);
}
echo "$hours:$minutes";
}
The result shows all the user in the department, and did SUM all the totalHours for each userId , but what was wrong is, there are userId without any attendance still have the SUM value shown, inheriting previous total Sum
Any help is appreciated :)
I need to query by userId WHERE departmentId = XXXX and SUM each of
their totalHours that exist, without neglecting the userId without any
record in attendance.
To show the hours for all users in a given department, even users w/o rows in the attendance table, use a LEFT JOIN
Use (CAST(totalHours AS UNSIGNED) % 100)/60 + FLOOR(CAST(totalHours AS UNSIGNED)/100) to convert your varchar hours+minutes to a single number of hours.
$query = "SELECT u.id,
SUM((CAST(totalHours AS UNSIGNED) % 100)/60 + FLOOR(CAST(totalHours AS UNSIGNED)/100)) grandTotal
FROM user u
LEFT JOIN attendance a
ON u.id = a.userId
WHERE u.departmentId = 2
GROUP BY u.id";
$result = mysqli_query($con,$query);
while($row = mysqli_fetch_array($result)) {
print $row['id'] . ' ' . $row['grandTotal'];
}
try this, just in the first while you wont need both.
SELECT TIME_FORMAT(sum(STR_TO_DATE(a.totalHours, '%i')),'%H:%i') as sum, u.id, u.name FROM user AS u LEFT JOIN attendance AS a ON a.userId = u.id WHERE u.departmentId = 2 AND u.id = $user_id GROUP by u.id;
Update, try that not sure if it will work I cant test it right now but refer to this question.
how to convert weird varchar "time" to real time in mysql?
Once you get the right query working it will be really easy in php to do the rest. The DB should do this work, although the schema is not ideal here..
OK! It's happening because, the users that doesn't have any attendance isn't passing through the second while, then the values aren't being restarted. You can correct this simply setting $grandTotal after you echo it. Like this:
$result = mysqli_query($con,"SELECT * FROM user WHERE departmentId = 2");
while($row = mysqli_fetch_array($result))
{
$id = $row['userId'];
$result2 = mysqli_query($con,"SELECT * FROM attendance WHERE userId = $id");
while($row2 = mysqli_fetch_array($result2))
{
$totalHours = 0;
$totalHours = $row2['totalHours'];
$grandTotal += $totalHours
}
echo $grandTotal;
$grandTotal = 0;
}
What I understood from the question is NOT to neglect those userid even if they do not have their attandance record. In this scenario I have 2 Options to be chosen ...
1.
$result = mysqli_query($con,"SELECT * FROM user WHERE departmentId = 2");
while($row = mysqli_fetch_array($result))
{
$id = $row['userId'];
$result2 = mysqli_query($con,"SELECT * FROM attendance WHERE userId = $id");
$grandTotal=0;
while($row2 = mysqli_fetch_array($result2))
$totalHours = 0;
{
$totalHours = $row2['totalHours'];
$grandTotal += $totalHours
}
echo $grandTotal;
}
2.
$result = mysqli_query($con,"SELECT * FROM user WHERE departmentId = 2");
while($row = mysqli_fetch_array($result))
{
$id = $row['userId'];
$result2 = mysqli_query($con,"SELECT * FROM attendance WHERE userId = $id");
while($row2 = mysqli_fetch_array($result2))
$totalHours = 0;
{
$totalHours = $row2['totalHours'];
if($totalHours<=0)
$grandTotal=0;
$grandTotal += $totalHours
}
echo $grandTotal;
}
Move $totalhours = 0 within the curly braces {}.
Set $hours = $minutes = 0 at the top of the second while loop (where you set $totalhours = 0)
**If you don't reset $hours and $minutes, users who don't have attendance will get the old values.

Categories