I am writing products stock script. I have a MySQL table "products_stock":
id zid pid amount
1 123 321 1
2 124 321 5
4 124 566 7
3 125 321 10
So, total amount of product id = 321 in stock is 16. Somebody makes order with pid=321 and qty = 7. I need some php-function, which will minus 7 from column amount starting from the first zid, and update records in table products_stock so that it lookes after like this:
id zid pid amount
1 123 321 0
2 124 321 0
4 124 566 7
3 125 321 9
I am stucked from this point.
Thank you for answers!
I don't use codeigniter but going through the documentation on how to perform a select operation and batch update. The main issue is getting your logic right... You select all the product entry for that particular item and you iterate through and subtract the amount of each from the ordered product.
<?php
//your order
$orders = [
['id' => 321, 'qty' => 7],
['id' => 501, 'qty' => 20],
];
$data = [];
foreach($orders as $order) {
$items = $this->db->where('pid', $order['id']);
$order_qty = $order['qty'];
foreach($items as $item){
$item_qty = $item->amount - $order_qty;
if ($item_qty <= 0) {
// set amount to 0 because it is less than order quantity
$data[] = ['id' => $item->id, 'amount' => 0];
// Subtract amount from order quantity to get the remaining order
$order_qty = $order_qty - $item->amount;
} else {
//If amount is more than order quantity set to calculated amount
$data[] = ['id' => $item->id, 'amount' => $item_qty];
// update order to 0
$order_qty = 0;
}
//exit if order quantity is 0
if ($order_qty === 0 ){
break;
}
}
}
$this->db->update_batch('product_stock', $data, pid');
You can do so by selecting all the relevent rows from the products_stock table and subtract/update the values one by one in loop until your required quantity gets over.
Example code
// These are the inputs you will be getting.
$pid = 321;
$qty = 7;
// Fetch all the relevent rows using the below query statement.
$select_sql = "select * from products_stock where pid = {$pid} and amount > 0";
// This will return the below array.
$data = [
[
'id' => 1,
'zid' => 123,
'pid' => 321,
'amount' => 1,
],
[
'id' => 1,
'zid' => 124,
'pid' => 321,
'amount' => 5,
],
[
'id' => 1,
'zid' => 125,
'pid' => 321,
'amount' => 10,
],
];
$update_data = [];
// You can then loop through your rows to perform your logic
foreach ($data as $row) {
// Exit loop if qty is 0
if ($qty == 0) {
break;
}
$id = $row['id'];
$amount = $row['amount'];
// Subtract the required amount from qty.
$qty -= $amount;
$amount = 0;
// If extra qty was consumed, add back to the amount.
if ($qty < 0) {
$amount =+ ($qty * -1);
$qty = 0;
}
// Update you data here or the best practice would be to avoid sql in a loop and do a bulk update.
// You can do this based on your requirement.
// $update_sql = "update products_stock set amount = {$amount} where id = {$id}";
// Prepare date for bulk update
$update_data []= [
'id' => $id,
'amount' => $amount,
];
echo "Qty {$qty} | Amt {$amount} \n";
echo "--------\n";
}
// Bulk update all your rows
if (count($update_data) > 0) {
$this->db->update_batch('products_stock', $update_data, 'id');
}
echo "\n";
echo "Balance Qty ". $qty . "\n";
Output
Qty 6 | Amt 0
--------
Qty 1 | Amt 0
--------
Qty 0 | Amt 9
--------
Balance Qty 0
Refer https://eval.in/920847 for output.
You can try running the same code with different qty.
This is the rough logic for your use case which will work as expected. Still there may be better ways to do this in an optimal way.
Glad if it helps you.
Related
I have an order like this
product quantity inventory
1 5 50
1 6 50
7 2 150
1 6 50
I am trying to loop in each product and decrease the inventory
Total inventory for product 1 is 50
in loop
product 1 the inventory become 45
product 1 the inventory becomes 39
product 7 the inventory becomes 148
product 1 the inventory becomes 44
Hers is the issue in the last loop the inventory has been rest to 50 again.
here is my code
foreach($order->productId->inventory as $currentRequestedCount){
$currentRequested = $order->quantity * $order->relatedPackage ->unit_count;
if($currentRequestedCount->type == "existing"){
$currentRequested -= $currentRequestedCount->amount;
}
}
how to prevent the $currentRequestedCount from being reset?
I use arrays to illustrate this. You have your inventory:
$inventory = [
//product => inventory
1 => 50,
7 => 150,
];
You get a few orders:
$order = [
['product' => 1, 'quantity' => 5],
['product' => 1, 'quantity' => 6],
['product' => 7, 'quantity' => 2],
['product' => 1, 'quantity' => 6],
];
The orders are processed (without handling errors!).
foreach($order as $row){
$inventory[$row['product']] -= $row['quantity'];
}
The current inventory:
var_dump($inventory);
Output:
array(2) {
[1]=>
int(33)
[7]=>
int(148)
}
I have two arrays which I can get after form submit:
$product_id = $request->get('product_id');
// [1, 3, 4]
$quantity = $request->get('quantity');
// [5, 1, 2]
Now I want to submit this arrays into database where I want to pick the purchase_price from product database. I'm not sure how to assign product_id to product_quantity (index 0 to 0, 1 to 1, 2 to 2) and store into database.
Sample data to store into carts:
[1 5 120 ],
[3 1 230 ],
[4 2 340 ],
foreach ($product_id as $product)
{
}
DB::table('carts')->insert(
['product_id' => '',
'quantity' => 0,
'purchase_price' =>
]
);
Just for clarification:
product_id and quantity come from dynamic input box means number of product_id and quantity are same but it could be n times as user wanted. So I store it as arrays.
Now from this array I wanted to store it in database where I want to store with product_id with quantity.
Lets give you some suggetions:
If you have below array - if not then make it array like below:
$dataset = [
0 => [
'product_id' => 1,
'quantity' => 5,
'purchase_price' => 120,
],
1 => [
'product_id' => 3,
'quantity' => 1,
'purchase_price' => 230,
],
2 => [
'product_id' => 4,
'quantity' => 2,
'purchase_price' => 340,
]
];
Now you have to write INSERT query for this:
$result = Cart::insert($dataSet);
if ($result)
return true;
else
return false;
You will get an idea how to do it after seeing above code...good luck
Please check out this sample.
you can parse 2d array and convert it to json to store in the database then decode back:
$product_id = [1,2,3];
// [1, 3, 4]
$quantity = [5,1,2];
// [5, 1, 2]
$output=[120,230,340];
$out=[];
for ($i=0; $i < count($product_id); $i++) {
$out[$i]=[$product_id[$i],$quantity[$i],$output[$i]];
}
dd(json_encode($out));
output:
"[[1,5,120],[2,1,230],[3,2,340]]"
You can use
foreach ($product_id as $key=>$product)
{
//select purchase price from table by using the $product value
$purchase_price = *your select code here*
DB::table('carts')->insert([
'product_id' => $product,
'quantity' => $quantity[$key],
'purchase_price' => $purchase_price
]);
}
Let me know if not works
I'm working on an Online Store project using PHP and MySQLi. Most of this project is done and now I'm struggling with total price that a user must pay. This total price is showing in the cart.php page (where users can see all the product items that they have added earlier). So it must be set to the total price of all current items.
So here is the code of cart.php:
if(isset($_GET['cart_id']))
{
$cart_id = $_GET['cart_id'];
$get_add = "SELECT * FROM cart WHERE cart_id = '$cart_id'";
$run_add = mysqli_query($con,$get_add);
$cart_items = [];
while ($row_results = mysqli_fetch_array($run_add)){
$item = array(
'table_id' => $row_results['table_id'],
'cart_id' => $row_results['cart_id'],
'pro_id' => $row_results['product_id'],
'pro_title' => $row_results['product_title'],
'pro_price' => $row_results['product_price'],
'pro_img' => $row_results['product_image'],
'pro_supplier' => $row_results['product_supplier'],
'qty' => $row_results['qty'],
'cart_ip' => $row_results['cart_ip'],
);
$cart_items[] = $item;
}
foreach ($cart_items as $cart) {
echo $cart['pro_price']
}
}
The table cart structure goes like this:
see image here
So now I want to print the sum of all products as total_price, till now I tried several different ways but I could not get the result.
So if you know how to solve this question, please let me know.. I really really appreciate that...
Thanks in advance!
Assuming you need the sum of qty*product_price you could sum this way
$tot = 0;
while ($row_results = mysqli_fetch_array($run_add)){
$cart_items[] = array(
'table_id' => $row_results['table_id'],
'cart_id' => $row_results['cart_id'],
'pro_id' => $row_results['product_id'],
'pro_title' => $row_results['product_title'],
'pro_price' => $row_results['product_price'],
'pro_img' => $row_results['product_image'],
'pro_supplier' => $row_results['product_supplier'],
'qty' => $row_results['qty'],
'cart_ip' => $row_results['cart_ip'],
);
$tot += $row_results['qty']*$row_results['product_price'];
}
foreach ($cart_items as $cart) {
echo $cart['pro_price'];
}
echo $tot;
I have a scoring system for a online game, that is based on people creating teams out of a list of a players.
once the player score fields are entered, the below script should calculate the points based on predefined points multiplier and update the data across 3 tables
players table (where i update the player score1 and score2 and his points)
score table (where i add the new scores for each player "same fields")
update all teams score1, score2 and points where this player id exists
to have an idea about my db structure here it is briefly
players table
id
score1
score2
total
score table
id
playerid
score1
score2
total
time
teams table
id
userid
p1
p2
b3
b4
score1 (this is the sum of all score1 scored by all 4 players)
score2 (this is the sum of all score2 scored by all 4 players)
total (this is the sum of all calculates scores by all 4 players)
time
the problem
surprisingly step 1 and step 2 works perfectly, scores are added and players are added correctly but when i get to step3 some of the teams gets updated correctly some of them don't update with the correct scores
my code
//predefined points multiplier
define("points1", 7);
define("points2", 8);
if (isset($_POST['submit'])) {
$id = $_POST['id'];
$score1= $_POST['score1'];
$score2 = $_POST['score2'];
foreach($id as $key=>$player){
//calculate the total points based on their predefined multipliers
$totalpoints = 0;
$totalpoints += $score1[$key] * points1;
$totalpoints += $score2[$key] * points2;
//update player table
#send a request to api to update this player data
//add scores
#send a request to api to add the new scores to the score table
//update teams (updates the teams for users)
$raw = [
'id' => $id,
'score1' => $score1[$key],
'score2' => $score2[$key],
'total' => $totalpoints
];
$data = http_build_query ($raw);
$result = file_get_contents(
BASE_URL . 'update',
false,
stream_context_create(array(
PROTOCOL => array(
'method' => 'PUT',
'header' => array(
'Content-Length: ' . strlen($data),
'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'
),
'content' => $data
)
))
);
$response = json_decode($result, false);
}//end foreach
echo $response->notice->message;
}
The way you're doing it now $totalpoints will always be 0.
the players get updated correctly because the value for the scores is being set inside the foreach loop
$totalpoints = 0;
$totalpoints += $score1[$key] * points1; // <- $key does not exist result will be 0
$totalpoints += $score2[$key] * points2; // <- $key does not exist result will be 0
foreach($id as $key=>$player){
$raw = [
'id' => $id,
'score1' => $score1[$key], // <- $key has a value
'score2' => $score2[$key], // <- $key has a value
'total' => $totalpoints // <- result is always 0
];
}
try changing it into
foreach($id as $key=>$player){
$totalpoints = 0;
$totalpoints += $score1[$key] * points1; // <- $key has a value
$totalpoints += $score2[$key] * points2; // <- $key has a value
$raw = [
'id' => $id,
'score1' => $score1[$key], // <- $key has a value
'score2' => $score2[$key], // <- $key has a value
'total' => $totalpoints // now does have a chance to be other then just 0
];
}
I'm using jsTree to view hierarchical data that is stored in a mySQL database as a nested set (left, right, level, etc.). This is working fine, but I need to allow users to import data by uploading a CSV file. When they do so, any existing data in the table will be removed so I don't have to worry about updating the left/right fields.
The data they will be uploading will be in this format:
"Code","Title"
"100","Unit 100"
"200","Unit 200"
"101","Task 101: This is a task"
"102","Task 102: Another task"
"201","Task 201: Yet another"
"300","Unit 300"
"301","Task 301: Another one"
Everything will be a child of a main "Group" that is a level 1 node. All of the "codes" divisible by 100 (ie. 100, 200, 300) will be level 2 (parent nodes.. children of "Group"). All others will be level 3 (child) nodes of their respective parent nodes (ie. 101 and 102 are children of 100, 201 is a child of 200, etc.)
The resulting table in mySQL should look like this:
id parent_id position left right level title
1 0 0 1 18 0 ROOT
2 1 0 2 17 1 Group
3 2 0 3 8 2 Unit 100
4 2 1 9 12 2 Unit 200
5 3 0 4 5 3 Task 101: This is a task
6 3 1 6 7 3 Task 102: Another task
7 4 0 10 11 3 Task 201: Yet another
8 2 2 13 16 2 Unit 300
9 8 0 14 15 3 Task 301: Another one
The tree would then look like this:
My question is: using PHP, what is the best method to accomplish this? I already have code in place that pulls the data contained in the uploaded CSV file and stores it in an array, but I'm not sure what the logic to convert this to a nested set should look like.
Right now, the data is stored in a 2-dimensional array called $data (in the format $data[$col][$row]):
$data[0][0] = "Code";
$data[0][1] = "100";
$data[0][2] = "200";
$data[0][3] = "101";
$data[0][4] = "102";
$data[0][5] = "201";
$data[0][6] = "300";
$data[0][7] = "301";
$data[1][0] = "Title";
$data[1][1] = "Unit 100";
$data[1][2] = "Unit 200";
$data[1][3] = "Task 101: This is a task";
$data[1][4] = "Task 102: Another task";
$data[1][5] = "Task 201: Yet another";
$data[1][6] = "Unit 300";
$data[1][7] = "Task 301: Another one";
Array ( [0] => Array ( [0] => Code [1] => 100 [2] => 200 [3] => 101 [4] => 102 [5] => 201 [6] => 300 [7] => 301 ) [1] => Array ( [0] => Title [1] => Unit 100 [2] => Unit 200 [3] => Task 101: This is a task [4] => Task 102: Another task [5] => Task 201: Yet another [6] => Unit 300 [7] => Task 301: Another one ) )
Any help would be very much appreciated. I now have the parent_id, position, and level being calculated correctly... I just need to figure out the left/right part. Here is the code I'm currently using (thanks for getting me started Matteo):
$rows = array();
// insert ROOT row
$rows[] = array(
'id' => 1,
'parent_id' => 0,
'position' => 0,
'left' => 1,
'right' => 10000, // just a guess, will need updated later
'level' => 0,
'title' => 'ROOT',
);
echo "<br>";
print_r($rows[0]);
// insert group row
$rows[] = array(
'id' => 2,
'parent_id' => 1,
'position' => 0,
'left' => 2,
'right' => 9999, // just a guess, will need updated later
'level' => 1,
'title' => 'Group',
);
echo "<br>";
print_r($rows[1]);
// next ID to be used
$id = 3;
// keep track of code => ID correspondence
$map = array();
// parse data
for ($i = 1, $c = count($data[0]); $i < $c; ++$i) {
// save ID in the map
$map[$data[0][$i]] = $id;
// initialize the current row
$row = array(
'id' => $id,
'parent_id' => 1,
'position' => 0,
'left' => 0,
'right' => 0,
'level' => 1,
'title' => $data[1][$i],
);
// if the code is multiple of 100
if ($data[0][$i] % 100 == 0) {
$row['parent_id'] = 2;
$row['level'] = 2;
$row['position'] = (floor($data[0][$i] / 100)) - 1;
} else {
// get parent id from map
$row['parent_id'] = $map[floor($data[0][$i] / 100) * 100];
$row['level'] = 3;
$row['position'] = $data[0][$i] % 100;
}
// add the row
$rows[] = $row;
++$id;
echo "<br>";
print_r($row);
}
Given your $data array, you could parse it like this:
// this will contain all the rows to be inserted in your DB
$rows = array();
// insert ROOT row
$rows[0] = array(
'id' => 1,
'parent_id' => 0,
'position' => 0,
'level' => 0,
'left' => 1,
'right' => 10000,
'title' => 'ROOT',
);
// insert group row
$rows[1] = array(
'id' => 2,
'parent_id' => 1,
'position' => 0,
'level' => 1,
'left' => 2,
'right' => 9999,
'title' => 'Group',
);
// keep trace of code => ID correspondence
$map = array();
// next ID to be used
$id = 3;
// keep father => sons relationship
$tree = array();
// keep trace of code => row index correspondence
$indexes = array();
// next row index
$index = 2;
// parse your data
for ($i = 1, $c = count($data[0]); $i < $c; ++$i) {
// current code
$code = $data[0][$i];
// save ID in the map
$map[$code] = $id;
// update the indexes map
$indexes[$code] = $index;
// prepare the current row
$row = array(
'id' => $id,
'title' => $data[1][$i],
)
// get the value of code mod 100
$mod = $code % 100;
// if the code is multiple of 100
if ($mod == 0) {
// the parent_id is 2
$row['parent_id'] = 2;
// it is level two
$row['level'] = 2;
// compute position
$row['position'] = floor($code / 100) - 1;
}
else {
// get the parent code
$parent = floor($code / 100) * 100;
// get parent id from map using parent code
$row['parent_id'] = $map[$parent];
// it is level three
$row['level'] = 3;
// save position
$row['position'] = $mod;
// save in relationship tree
$tree[$parent][] = $code;
}
// add the row
$rows[$index] = $row;
// prepare next id
++$id;
// update row index
++$index;
}
// sort the relationship tree base on the parent code (key)
ksort($tree, SORT_NUMERIC);
// next left value
$left = 3;
// now, using the relationship tree, assign left and right
foreach ($tree as $parent => $sons) {
// calculate parent left value
$parentLeft = $left;
// prepare next left value
++$left;
// to be sure that the sons are in order
sort($sons, SORT_NUMERIC);
// assign values to sons
foreach ($sons as $son) {
// index in the rows array
$index = $indexes[$son];
// set left value
$rows[$index]['left'] = $left;
// set right value
$rows[$index]['right'] = $left + 1;
// increment left value
$left += 2;
}
// calculate parent right value
$parentRight = $left;
// prepare next left value
++$left;
// index of parent in the rows array
$index = $indexes[$parent];
// set the values
$rows[$index]['left'] = $parentLeft;
$rows[$index]['right'] = $parentRight;
}
// update group row right value
$rows[1]['right'] = $left;
// prepare next left value
++$left;
// update root row right value
$rows[0]['right'] = $left;
At this point, you can insert all the rows one at a time.
EDIT: now the script should handle all the required values correctly.
I would use Doctrine2 with a Nested Set Extension. You could use a nice and convenient API and don't have to worry about the nested set implementation:
See
http://www.gediminasm.org/article/tree-nestedset-behavior-extension-for-doctrine-2
or http://wildlyinaccurate.com/simple-nested-sets-in-doctrine-2
There are several extensions on github. Actually, i don't know which one is best.
https://github.com/l3pp4rd/DoctrineExtensions
https://github.com/guilhermeblanco/Doctrine2-Hierarchical-Structural-Behavior
https://github.com/blt04/doctrine2-nestedset
List item
If your data is flat, you could parse for keywords like 'Unit' or 'Task' to arrange your elements to the needed hierarchical order.