Link to home
Start Free TrialLog in
Avatar of Stef Merlijn
Stef MerlijnFlag for Netherlands

asked on

How to create a order form with calculations

Hi,

On my site I want to add an orderform. Basically I have the following setup for products in a MySQL DB:
- productname
- price
- quantity ordered
- maximum order quantity (if set to 0 (zero) then unlimited)

Each product has a price. Dependend on the quantity ordered the customer will get a discount.
1-4 no discount
5-9 20%
10-14 25%
15+ 30%

There is one main product. If the quantity of any other product exceeds the quantity of the main product, a message need to be given: "Quantity of the main product must be at equal to or greater than any ordered quantity for any other product".

I'm looking for a way to get the list of products from the database and let the customer enter the quantity for one or more products.
When a quantity for a product is changed, the total amount for the order is calculated (taking any discount into account).
Pressing a Order button will send an E-mail to me and the customer.

What I like to get is the beasics on how to set this up. If I know how to do it with two products, I can do it myself for the rest.

Below is the code I use in my delphi application.
procedure TFWIZZcrmKopen.IModRelBPropertiesChange(Sender: TObject);
var ResterendeMaandenInJaar : Integer;
begin
  ResterendeMaandenInJaar := (12 - MonthOfTheYear(Now));
  vModRelT := IModRelL.Value + IModRelB.Value;
  vModFacT := IModFacL.Value + IModFacB.Value;
  vModAgeT := IModAgeL.Value + IModAgeB.Value;
  vModCorT := IModCorL.Value + IModCorB.Value;
  vModKmrT := IModKmrL.Value + IModKmrB.Value;
  vModOpdT := IModOpdL.Value + IModOpdB.Value;
  vModVbhT := IModVbhL.Value + IModVbhB.Value;
  vMLTCMPT := IMLTCMPL.Value + IMLTCMPB.Value;
  vORTRAPT := IORTRAPL.Value + IORTRAPB.Value;
  vCLIEOPT := ICLIEOPL.Value + ICLIEOPB.Value;

  TotaalBesteldeModulesOpties := (IModRelB.Value + IModFacB.Value + IModAgeB.Value + IModCorB.Value + IModKmrB.Value + IModOpdB.Value
                          + IModVbhB.Value + IMLTCMPB.Value + IORTRAPB.Value + ICLIEOPB.Value);

  // Korting als vast bedrag instellen.
  if (TotaalBesteldeModulesOpties < 5) then
    vKorting := 0   // Geen korting
  else
  if (TotaalBesteldeModulesOpties < 10) then
    vKorting := 20  // 20% korting
  else
  if (TotaalBesteldeModulesOpties < 20) then
    vKorting := 25  // 25% korting
  else
    vKorting := 30; // 30% korting
  lbKorting.Caption := IntToStr(vKorting) + ' %';

  // Bedragen op scherm zetten
  IBedragRel.Value    := IModRelB.Value * (vModRelP - ((vModRelP / 100) * vKorting));
  IBedragFac.Value    := IModFacB.Value * (vModFacP - ((vModFacP / 100) * vKorting));
  IBedragAge.Value    := IModAgeB.Value * (vModAgeP - ((vModAgeP / 100) * vKorting));
  IBedragCor.Value    := IModCorB.Value * (vModCorP - ((vModCorP / 100) * vKorting));
  IBedragKmr.Value    := IModKmrB.Value * (vModKmrP - ((vModKmrP / 100) * vKorting));
  IBedragOpd.Value    := IModOpdB.Value * (vModOpdP - ((vModOpdP / 100) * vKorting));
  IBedragVbh.Value    := IModVbhB.Value * (vModVbhP - ((vModVbhP / 100) * vKorting));
  IBedragMLTCMP.Value := IMLTCMPB.Value * (vMLTCMPP - ((vMLTCMPP / 100) * vKorting));
  IBedragORTRAP.Value := IORTRAPB.Value * (vORTRAPP - ((vORTRAPP / 100) * vKorting));
  IBedragCLIEOP.Value := ICLIEOPB.Value * (vCLIEOPP - ((vCLIEOPP / 100) * vKorting));

  // Totaalbedragen berekenen
  IBedragSubtotaal.Value          := IBedragRel.Value + IBedragFac.Value + IBedragAge.Value + IBedragCor.Value + IBedragKmr.Value + IBedragOpd.Value
                                   + IBedragVbh.Value + IBedragMLTCMP.Value + IBedragORTRAP.Value + IBedragCLIEOP.Value;

  If TotaalBesteldeModulesOpties > 5 then
    IBedragOnderhoudscontract.Value := {Eerste 5 licenties tegen normale prijs}
                                       (5) * ((vModUpdP / 12) * ResterendeMaandenInJaar)
                                       {Overige > 5 licenties tegen vervolgprijs}
                                     + (TotaalBesteldeModulesOpties - 5) * ((vModUpdV / 12) * ResterendeMaandenInJaar)
  else
    IBedragOnderhoudscontract.Value := {Alle licenties tegen vervolgprijs}
                                       TotaalBesteldeModulesOpties * ((vModUpdP / 12) * ResterendeMaandenInJaar);
  IBedragTotaal.Value             := (IBedragSubtotaal.Value + IBedragOnderhoudscontract.Value);
end;

Open in new window

Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

I am thinking that you might want to take a class in PHP.  The programming concepts are the same, but the syntax is (obviously) very different.  If you have some depth of experience in Delphi and other programming languages you can pick up PHP very quickly from this excellent book:
http://www.sitepoint.com/books/phpmysql4/


you can use the Form1 on Show Event to do your calculations, everytime you show your form the calculation is executed

see screen dump , how to get the on show event for a form
ee-onshow.png
Avatar of Stef Merlijn

ASKER

The code for Delphi is clear to me, but I need it to be translated to PHP.
No I didn't till now.
It might be a possible solution, but I need only one form, so it's a big investment for such small usage.
what about a free troial version , might be the fasted way to program PHP

http://www.embarcadero.com/products/radphp/downloads 
greetings Delphiwizard, I looked at your pascal code, and I can not even begin to reconstruct it into a PHP for MySQL code script, you have so many "Unknown" variable types, I can not get any idea (clue) about how or why these variables are in your code or how and maybe if they can be used in a PHP set up.

For instance you have a line as -
    vModRelT := IModRelL.Value + IModRelB.Value;

which I do NOT know what the "vModRelT" may be for or it's type (integer maybe?), and especially the IModRelL.Value, what is the "IModRelL" object and what info does it hold?

a simple minded php translation would be =
$vModRelT = $IModRelL->Value + $IModRelB->Value;

but this would not work, because there is nowhere in you code that the IModRelB object has been created or the IModRelB.Value has been given a value, although these may be a database object, PHP code will have to have code to access by connect to database, and do a query (SELECT, I guess), which I do not see in your code. Delphi can sometimes do much database access (connect to a database) without you writing any code to do it, however PHP does not have this default stuff, and may or may not be a problem here.

I think that your request of this question, may be much more than an easy translation from your procedure above, although there is one section that could be translated -

if ($TotaalBesteldeModulesOpties < 5) $vKorting = 0; // Geen korting
    elseif ($TotaalBesteldeModulesOpties < 10) $vKorting = 20;  // 20% korting
    elseif ($TotaalBesteldeModulesOpties < 20) $vKorting = 25;  // 25% korting
    else $vKorting = 30; // 30% korting
Hi Slick812:

You can forget all the variables.
Is was meant as a clearification (but missed it's purpose :-)

Basically if the functionality that I described above is met, than I would be very happy.


Product     Price     Quantity   Total
ProdA         100            2     200
ProdB         125            1     125
ProdC         150            2     300
ProdD         100            0       0
OptionA       200          [v]     200  <- checkbox
OptionB       100          [v]     100  <- checkbox
                        SUBTOTAL:  925
                        DISCOUNT:  185 (=20%)  <- 7 products
                           TOTAL:  740

Open in new window

In addition:
ProdA is the main product. Because ProdC is ordered with quantity 2, ProdA's quantity must be at least 2 too.
I have done some php code work on this, and as I tested I could not see what goal I was trying to get to. So, , I need to ask you about the way you want this to be set up, or the way I might be able to help you with this by setting up the php code. It occurred to me while I was testing and doing this, that you may not know enough PHP code usage to understand, or use any code I post here. Since your question is =
  "How to create a order form with calculations"

I guess you need the HTML <form> set up from reading a products database SELECT query?

or maybe that's already done for you and you just need the math of the discount calculation from your post ID:35736228 above?

any way, look at the code below and see if you can make any use of that kind of PHP code setup for a HTML form from a DB SELECT
<?php
// Incompleate Partial Code below 

if ($result = $mysqli->query('SELECT name, price, description, maxAllowed  FROM products1 WHERE onSale= 1')) 
    {
    echo '<form name="oform" action="discont1.php" method="post">
    <table cellpadding="8"><tr><td>product Name</td><td>Discription</td><td>maxAllowed</td>
    <td>Price</td><td>Order Number</td></tr>';
		while ($product = $result->fetch_object()) {
		echo '<tr><td>'.$product->name.'</td><td>'.$product->description.'</td><td>'.$product->maxAllowed.'</td><td>$'.
		$product->price.'</td><td><input type="text" name="'.$product->name.'" size="5" maxlength="5" value="0" /></td></tr>';
    }
echo '</table><input type="checkbox" name="option1" value="1"> option1<br />'.
    '<input type="checkbox" name="option2" value="1"> option2<br /><input type="submit" name="submit1" value=" Place Order "></form>';
mysqli_free_result($result);
    } else echo $mysqli->error;
$mysqli->close();
?>

Open in new window

Slick812:
You are correct. I'm not familiar with PHP, though I can understand it when it is provided to me. Then I probably can make the neccessary adjustments.
Currently I have nothing setup yet, so the whole form must be created from scratch. I can setup the MySQL-database myself.

In your code you seem to get the data from the database and put it in a table within a form.
On the form the customer then has to select the quantities required for each product and calculations can take place.
you say "In your code you seem to get the data from the database and put it in a table within a form".
That is correct.

I have done a PHP test page for your discount order FORM, and I already had a database Table for "Products" that I used for another product order page I worked on, so I took some of the methods and code form that and tried to apply it to what you might need.

I did not place alot of comments for explanation of the code I was using, I hope you get the idea of what is going on.

This seems to do what I expect for an order FORM to calculate a discount, and it also tests for amount ordered above MAIN product and maxAllowed.

You said that you can can setup the MySQL-database yourself,

for the Table I used here it's like -

`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY
`name` VARCHAR( 32 ) NOT NULL UNIQUE
`price` INT NOT NULL
`ordered` INT NOT NULL DEFAULT '0'
`maxAllowed` INT NOT NULL
`isMain` BOOLEAN NOT NULL DEFAULT '0'
`description` VARCHAR( 128 ) NOT NULL DEFAULT 'no d'
`onSale` INT NOT NULL DEFAULT '0'


<html><head><title>Discount Test</title></head><body bgcolor="#e3f7ff"><h2>Test for Discount</h2>
<p>
<?php

// Since I will always use a database SELECT, I do it first
$mysqli = new mysqli('localhost', 'user', 'password', 'sales');
$ProdNum = 0;
if (mysqli_connect_errno()) {
	echo '<b>BIG mysqli ERROR - did NOT connect database to mysqli Object '.mysqli_connect_error().'</b></body></html>';
	// you should not display any MYSQL errors in your production page, just in the development page
	exit;
	}

if ($prodList = $mysqli->query('SELECT id, name, price, description, maxAllowed FROM products1 WHERE onSale= 1')) 
	{
	$ProdNum = $prodList->num_rows;
	//If there are no results from SELECT $ProdNum is zero and will be tested later for a value
	}

if (isset($_POST['submit1']) && $ProdNum){// test to see if submit
	$mainID = array(-1, 'no');
// $mainID holds info for the MAIN Product, and used for testing if order is above MAIN Product
	if ($result = $mysqli->query('SELECT id, name FROM products1 WHERE isMain= 1 AND onSale= 1')) {
	$product = $result->fetch_object();
	$mainID[0] = $product->id; 
	$mainID[1] = $product->name;
	mysqli_free_result($result);
	}
	$error = 0;
	$maxOrder = 0;
	$aryOrder = array();
	while ($product = $prodList->fetch_object()) {// get a row of database result one at a time
		if (is_numeric($_POST[$product->name]) && (((int) $_POST[$product->name]) > 0))
// you MUST test the POST values for allowed input
			$aryOrder[$product->id] = array((int) $_POST[$product->name], $product->name, $product->price, $product->maxAllowed);
		// add to $aryOrder if order is above zero
		$product = null; // release memory
		}
// at this point $aryOrder holds all of the orders posted or nothing if there are all zero for numbers
// I do not test to see if $aryOrder is empty because next I test to see if they ordered MAIN product
	if (($mainID[0] > -1) && isset($aryOrder[$mainID[0]]))
		$maxOrder = $aryOrder[$mainID[0]][0]; else 
		$error = 'ERROR - You did not Order any of the Main Product '.$mainID[1].'<br />';

	echo $maxOrder.' debug Main ID- '.$mainID[0].' prod Num- '.$ProdNum .'<br />';
	if ($error) echo $error;
		else {
	$option1 = (isset($_POST['option1'])) ? 1 : 0;// get the options
	$option2 = (isset($_POST['option2'])) ? 1 : 0;
	$debug = '<b>De bug output to check values</b><br />opt1- '.$option1.' opt2- '.$option2.'<br />';
	$outStr = '<p><table border="1" cellpadding="4"><tr><td>Product</td><td>Price</td><td>Quanity</td><td>Cost for Line</td></tr>';
	$TotalQuantity = 0;// holds the Quantity to test for discount
	$addTotal = 0;// holds the added values of the product cost

	foreach ($aryOrder as $key=>$value) { // run through the Orders array
		$debug .= ' key- '.$key.' order- '.$value[0].' name- '.$value[1].' price- '.$value[2].
                ' maxAllowed- '.$value[3].'<br />';
		if ($value[0] > $value[3]) // test for MaxAllowed
			{
			$error = 'ERROR - you ordered '.$value[0].' of '.$value[1].
                        ' which is more than the Maximum Allowed of '.$value[3].'<br />';
			break;
			}
		if (($key != $mainID[0]) && ($maxOrder < $value[0]))//test for over MAIN product
			{
			$error = 'ERROR - you ordered '.$value[0].' of '.$value[1].' which is more than the Main Product '.$mainID[1].' of '.$maxOrder.'<br />';
			break;
			}
		$lineTotal = $value[0] * $value[2];
		$outStr .= '<tr><td>'.$value[1].'</td><td>'.$value[2].'</td><td>'.$value[0].'</td><td>'.$lineTotal.'</td></tr>';
		$addTotal += $lineTotal;
		$TotalQuantity += $value[0];
		} // foreach ($aryOrder
	if ($error) echo $error;// stop on error
		else {
		echo $debug;
		if ($option1) {// add options
			$addTotal += 200;
			$outStr .= '<tr><td>option1</td><td>200</td><td>1</td><td>200</td></tr>';
			}
		if ($option2) {
			$addTotal += 100;
			$outStr .= '<tr><td>option2</td><td>100</td><td>1</td><td>100</td></tr>';
			}
		$outStr .= '<tr><td>-</td><td>-</td><td>Sub Total</td><td>'.$addTotal.'</td></tr>';
      // add sub total
		if ($TotalQuantity < 5) $discount = 0; // find the discount
		elseif ($TotalQuantity < 10) $discount = 0.2;  // 20% dis
		elseif ($TotalQuantity < 20) $discount = 0.25;  // 25% dis
		else $discount = 0.3; // 30% dis
		echo 'sub total- '.$addTotal.' quantity- '.$TotalQuantity.' discont- '.$discount.' total dis- ';
		$disOff = floor($addTotal * $discount);
		$addTotal -= $disOff;
		echo $disOff.' final total- '.$addTotal.'<br /><b>END DEBUG</b>';
		if ($discount > 0) $outStr .= '<tr><td>-</td><td>'.($discount * 100).
                '%</td><td>Discount</td><td>'.$disOff.'</td></tr>';
		$outStr .= '</table>Total order amount for '.count($aryOrder).' products is $'.$addTotal.'</p>';
		
		}
	if (!$error) 
	{
	$query = 'UPDATE products1 SET ordered = ? WHERE name = ?';
	$stmt = $mysqli->prepare($query);
	$stmt->bind_param("is", $value[0], $value[1]);
	// UPDATE database for all $aryOrder values
	foreach ($aryOrder as $value) {
		if(!$stmt->execute()) {
			echo 'execute has failed on '.$value[1].'<br>';
			break;
			}
		}
	$stmt->close();
	echo $outStr;
	}
	} // else if ($error)
	}// if (isset($_POST['submit1'])

// // // Below is the code for the order FORM
	if ($ProdNum) {
		echo '<hr><form name="oform" action="discont1.php" method="post">
	<table border="1" cellpadding="8"><tr><td>product Name</td><td>Discription</td><td>maxAllowed</td>
	<td>Price</td><td>Order Number</td></tr>';
		$prodList->data_seek(0);
		while ($product = $prodList->fetch_object()) {
		echo '<tr><td>'.$product->name.'</td><td>'.$product->description.'</td><td>'.$product->maxAllowed.'</td><td>$'.
		$product->price.'</td><td><input type="text" name="'.$product->name.'" size="5" maxlength="5" value="0" /></td></tr>'; 
		$product = null;
		}
		echo '</table><input type="checkbox" name="option1" value="1"> option1<br />'.
		'<input type="checkbox" name="option2" value="1"> option2<br />'.
                '<input type="submit" name="submit1" value=" Place Order "></form>';
		mysqli_free_result($prodList);
		} else echo '<b>No Products On Sale are Currently Availible</b>';
$mysqli->close();


?>
</body></html>

Open in new window

Whoooh, you got into it... thank you.
I will do some testing an try to figure out what the code does exactly.
-> `isMain` BOOLEAN NOT NULL DEFAULT '0'
There seems to be no BOOLEAN value available, so I set it to INT default 0

`ordered` INT NOT NULL DEFAULT '0'
It seems to make no sense to put the ordered quantity in this table and override i's valuet for each and every customer that places an order.
Can you explain what is the purpose of this field?
the `ordered` field holds the amount that the individual ordered for that product and is only for testing and development here. I included a database table and accessed it, to show you one way to do this using PHP and get some display that you asked for in the product amounts and subtotals, and final total after discount. However this is not meant to be a working "product ordering" set of methods, , , as you ask about the `ordered`, you would have a different Table or session storage for recording of the products, discount, and number ordered for a customer, I did not have time to do other table or session recording for this test, so I just updated the `ordered` in a table that already existed. In my actual table, I do not have the `ordered' or the `isMain`, but used the field names (of same type) in my table, and exchanged them here for clarity. There are many other side effects, error checking and data storage stuff, which you did not ask about and I did not try to do or comment about.

any way, , In my code above, I should have changed it, some versions of php mysqli do not support array members as binds in prepare statements, see code changes below, for something that has a better chance to work in more versions
$query = 'UPDATE products1 SET ordered = ? WHERE name = ?';
	$stmt = $mysqli->prepare($query);
	$stmt->bind_param("is", $v0, $v1);
	// UPDATE database for all $aryOrder values
	foreach ($aryOrder as $value) {$v0=$value[0];
               $v1=$value[1];
		if(!$stmt->execute()) {
			echo 'execute has failed on '.$value[1].'<br />';
			break;
		}
		}
	$stmt->close();

Open in new window

I also noticed that I used the wrong method for clearing memory use in php (I've been doing code in javascript recently)
the line -

$product = null; // release memory

     should be -

unset($product); // release memory

sorry about that, but I try and release memory, even though for this small data set, memory usage is not a problem. You can even leave out the unset($product); line, unless you have large while loops or data walk throughs or other memory issues.
Thank you. I've not yet made time to test it all. I'll get back a.s.a.p.
Hi,

The code below works fien except for hthe following:
There are three product types. But the only producttype that is presented in the order (after pressing submit) is of type "Module".
So somewhere down the line I loose order-content.

Any suggestions and maybe some optimizations for the code?
<?php
		        // Connectie met de database opzetten
		        $mysqli = new mysqli('localhost', 'user', 'password', 'sales');
		        $ProdNumP = 0;
		        $ProdNumM = 0;
		        $ProdNumO = 0;
	        
		        // Verschillende producttypes laden
		        if ($prodListp = $mysqli->query('SELECT ID, Naam, Prijs, MaxBestel, Omschrijving, Inhoud FROM Producten WHERE Actief= 1 AND Type= "Pakket" ORDER BY Sortering')) 
		        {
		        $ProdNumP = $prodListp->num_rows;
		        //If there are no results from SELECT $ProdNump is zero and will be tested later for a value
		        }
		        if ($prodListm = $mysqli->query('SELECT ID, Naam, Prijs, MaxBestel, Omschrijving, Inhoud FROM Producten WHERE Actief= 1 AND Type= "Module" ORDER BY Sortering')) 
		        {
		        $ProdNumM = $prodListm->num_rows;
		        //If there are no results from SELECT $ProdNumm is zero and will be tested later for a value
		        }
		        if ($prodListo = $mysqli->query('SELECT ID, Naam, Prijs, MaxBestel, Omschrijving, Inhoud FROM Producten WHERE Actief= 1 AND Type= "Optie" ORDER BY Sortering')) 
		        {
		        $ProdNumO = $prodListo->num_rows;
		        //If there are no results from SELECT $ProdNumo is zero and will be tested later for a value
		        }

		        // test to see if submit 
		        if (isset($_POST['submitbestel']) && $ProdNumP){
		
			        // $mainID holds info for the MAIN Product, and used for testing if order is above MAIN Product
			        $mainID = array(-1, 'no');
			        if ($result = $mysqli->query('SELECT ID, Naam FROM Producten WHERE BasisProduct= 1 AND Actief= 1')) {
			        $product = $result->fetch_object();
			        $mainID[0] = $product->ID; 
			        $mainID[1] = $product->Naam;
			        mysqli_free_result($result);
			        }
			
			        $error = 0;
			        $maxOrder = 0;
			        $aryOrder = array();
		
			        // De bestelde producten worden nu in $aryOrder geplaatsts
			        while ($product = $prodListp->fetch_object()) {// get a row of database result one at a time
						if (is_numeric($_POST[$product->Naam]) && (((int) $_POST[$product->Naam]) > 0))
				        // you MUST test the POST values for allowed input
			                $aryOrder[$product->ID] = array((int) $_POST[$product->Naam], $product->Naam, $product->Prijs, $product->MaxBestel);
		                // add to $aryOrder if order is above zero
						unset($product); // release memory
		            }
			        while ($product = $prodListm->fetch_object()) {// get a row of database result one at a time
		                if (is_numeric($_POST[$product->Naam]) && (((int) $_POST[$product->Naam]) > 0))
				        // you MUST test the POST values for allowed input
			                   $aryOrder[$product->ID] = array((int) $_POST[$product->Naam], $product->Naam, $product->Prijs, $product->MaxBestel);
		                // add to $aryOrder if order is above zero
						unset($product); // release memory
		            }
			        while ($product = $prodListo->fetch_object()) {// get a row of database result one at a time
		                if (is_numeric($_POST[$product->Naam]) && (((int) $_POST[$product->Naam]) > 0))
				        // you MUST test the POST values for allowed input
							$aryOrder[$product->ID] = array((int) $_POST[$product->Naam], $product->Naam, $product->Prijs, $product->MaxBestel);
		                // add to $aryOrder if order is above zero
						unset($product); // release memory
		            }
		
			        // Het bestelde aantal van de basismodule Relatiebeheer wordt nu in variabele $maxOrder geplaatst
			        $maxOrder = $aryOrder[$mainID[0]][0];
			
			        if (!$error) 
				    {
				        $outStr = '<p><table class="prijzen"><tr><th class="top">Bestelde producten</th><th class="prijs">Prijs</th><th class="prijs">Aantal</th><th class="prijs">Totaal</th></tr>';
				        $TotalQuantity = 0;  // Aantal bestelde modules / opties
				        $subTotal      = 0;  // Subtotaal voor de gehele order
				        $addTotal      = 0;  // Totaalbedrag voor de gehele order
				
						// Ga door de bestelde producten $aryOrder
						foreach ($aryOrder as $key=>$value) { 
			                $debug .= ' key- '.$key.' order- '.$value[0].' Naam- '.$value[1].' Prijs- '.$value[2].' MaxBestel- '.$value[3].'<br />';
			                if ($value[0] > $value[3]) // test for MaxBestel
	                        {
		                        $error = 'FOUT - je hebt '.$value[0].' besteld van '.$value[1].', dit is meer dan de maximale bestelhoeveelheid voor dit product (max='.$value[3].')<br />';
		                        break;
	                        }
			                // Controleer of er meer van andere producten wordt besteld dan van het BasisProduct
			                if (($key != $mainID[0]) && ($maxOrder < $value[0]))     
	                        {
		                        $error = 'FOUT - je hebt '.$value[0].' besteld van '.$value[1].' dit is meer dan het aantal dat wordt besteld van de basismodule '.$mainID[1].' van '.$maxOrder.'<br />';
		                        break;
	                        }
			                $lineTotal = $value[0] * $value[2];
			                $outStr .= '<tr><td>'.$value[1].'</td><td class="prijs">'.$value[2].'</td><td class="prijs">'.$value[0].'</td><td class="prijs">'.$lineTotal.'</td></tr>';
			                $addTotal += $lineTotal;
			                $TotalQuantity += $value[0];
		                } // foreach ($aryOrder

		                // Bepaal de korting (discount)
		                if ($TotalQuantity < 5)      $discount = 0;     //  0% korting 
		                elseif ($TotalQuantity < 10) $discount = 0.2;   // 20% korting
		                elseif ($TotalQuantity < 20) $discount = 0.25;  // 25% korting
		                else                         $discount = 0.3;   // 30% korting

		                $disOff = floor($addTotal * $discount);
						$subTotal  = $addTotal;
		                $addTotal -= $disOff;
		                if ($discount > 0) 
		                {
			                // Subtotaal vermelden
			                $outStr .= '<tr><td>&nbsp;</td><td>&nbsp;</td><td>Subtotaal</td><td class="prijs">'.$subTotal.'</td></tr>';
							// Korting vermelden
							$outStr .= '<tr><td>&nbsp;</td><td>&nbsp;</td><td>Korting '.($discount * 100).'%</td><td class="prijs">'.$disOff.'</td></tr>';
						}
						// Eindtotaal vermelden
		                $outStr .= '<tr><td>&nbsp;</td><td>&nbsp;</td><td>Totaal</td><td class="prijs">'.$addTotal.'</td></tr>';
		                $outStr .= '</table></p>';

						// Bestelling opslaan in de database
				        if (!$error) 
				        {
					        $query = 'UPDATE Producten SET Besteld = ? WHERE Naam = ?';
					        $stmt = $mysqli->prepare($query);
					        $stmt->bind_param("is", $value[0], $value[1]);
					        // UPDATE database for all $aryOrder values
					        foreach ($aryOrder as $value) 
					        {
				                if(!$stmt->execute()) 
				                {
				                 	echo 'execute has failed on '.$value[1].'<br>';
				                 	break;
				                }
				            }
					        $stmt->close();
					        echo $outStr;
				        } // if (!$error)
			        } // if (!$error)
		        } // if (isset($_POST['submit1'])
	
		        // Toon het bestelformulier
		        if ($ProdNumP) 
		        {
					echo '<hr>
<!-- 
	           		<form name="bestelform" action="mailbestelling.php" method="post">
-->
	                <form name="bestelform" method="post">
				        <table class="prijzen"><tr><th class="top">Pakketten</th><th class="prijs">Prijs</th><th class="prijs">Aantal</th></tr>';
			                $prodListp->data_seek(0);
			                while ($product = $prodListp->fetch_object()) {
			                echo '<tr><th class="lossemodules">'.$product->Naam.'</th><td class="prijs">€ '.$product->Prijs.'</td><td class="aantal" rowspan="3"><input type="text" name="'.$product->Naam.'" size="5" maxlength="5" value="0" /></td></tr>'; 
			                echo '<tr><td colspan="2">'.$product->Omschrijving.'</td></tr>'; 
			                echo '<tr><td colspan="2">'.$product->Inhoud.'</td></tr>'; 
							unset($product); // release memory
			                }
			                echo '</table><br>';
				        echo '<table class="prijzen"><tr><th class="top">Losse modules</th><th class="prijs">Prijs</th><th class="prijs">Aantal</th></tr>';
			                $prodListm->data_seek(0);
			                while ($product = $prodListm->fetch_object()) {
			                echo '<tr><td class="vet">'.$product->Naam.'</td><td class="prijs">€ '.$product->Prijs.'</td><td class="aantal"><input type="text" name="'.$product->Naam.'" size="5" maxlength="5" value="0" /></td></tr>'; 
							unset($product); // release memory
			                }
			                echo '</table><br>';
				        echo '<table class="prijzen"><tr><th class="top">Programmaopties</th><th class="prijs">Prijs</th><th class="prijs">Aantal</th></tr>';
			                $prodListo->data_seek(0);
			                while ($product = $prodListo->fetch_object()) {
			                echo '<tr><td class="vet">'.$product->Naam.'</td><td class="prijs">€ '.$product->Prijs.'</td><td class="aantal"><input type="text" name="'.$product->Naam.'" size="5" maxlength="5" value="0" /></td></tr>'; 
							unset($product); // release memory
			                }
			                echo '</table>'.
	                '<p><input type="submit" name="submitbestel" value=" Bestellen "></p>
	                </form>';
	                mysqli_free_result($prodListp);
	                mysqli_free_result($prodListm);
	                mysqli_free_result($prodListo);
	            } else echo '<b>Er worden op dit moment geen producten online verkocht</b>';

			 $mysqli->close();
		   ?>

Open in new window

I'm very glad you got it to run and have a PHP you can work on and debug.

You say "So somewhere down the line I loose order-content."

not sure about the reason for that problem but I had only one while loop to set the $aryOrder  array values


you set the $aryOrder array values in three while loops like -
$aryOrder[$product->ID] = array((int) $_POST[$product->Naam], $product->Naam, $product->Prijs, $product->MaxBestel);

I would think that your $product->ID   and   $product->Naam  are UNIQUE values in your Producten table? If not they need to be UNIQUE, if the ID or Naam duplicates anywhere then there is no way to differentiate the posted Naam, unless you add something to do that.

In my example I used the  $debug output string to help see what was going wrong, , as -
$debug .= ' key- '.$key.' order- '.$value[0].' Naam- '.$value[1].' Prijs- '.$value[2].' MaxBestel- '.$value[3].'<br />';

I would think that this would give you information about what is missing, or incorrect in the $aryOrder, which should contain the values that were posted and the MaxBestel from the Producten table.

if your values for $product->ID   and   $product->Naam  are UNIQUE, then what I might try is to do a single SELECT query, maybe

if ($prodList = $mysqli->query('SELECT ID, Naam, Prijs, MaxBestel, Omschrijving, Inhoud FROM Producten WHERE Actief= 1 AND Type= "Pakket"  AND Type= "Optie"  AND Type= "Module" ORDER BY Sortering'))

and then do a single while loop and set the TYPE value into the $aryOrder array


while ($product = $prodList->fetch_object()) {// get a row of database result one at a time
    if (is_numeric($_POST[$product->Naam]) && (((int) $_POST[$product->Naam]) > 0))
    $aryOrder[$product->ID] = array((int) $_POST[$product->Naam], $product->Naam, $product->Prijs, $product->MaxBestel, $product->Type);
    // add to $aryOrder if order is above zero
    unset($product); // release memory
    }

and then Later in the code, when you need to separate the products by type, you test for it

if ($aryOrder[5] == 'Optie')
or
if ($value[5] == 'Optie')

and in your HTML form production, you would need to add three if tests and I guess three different Table output strings
$outPakket = '<table class="prijzen"><tr><th class="top">Pakketten</th><th class="prijs">Prijs</th><th class="prijs">Aantal</th></tr>'';

if ($product->Type == "Pakket') and fill the three different HTML table strings in one while loop
if ($product->Type == "Pakket') $outPakket .= '<tr><th class="lossemodules">'.$product->Naam.'</th><td class="prijs">€ '.$product->Prijs.'</td><td class="aantal" rowspan="3"><input type="text" name="'.$product->Naam.'" size="5" maxlength="5" value="0" /></td></tr>';

but without some debug info, I can not see a clear cut reason for your failures

maybe if you placed a debug output after the -
if (isset($_POST['submitbestel']) && $ProdNumP){
echo 'ProdNumP- '.$ProdNumP.' ProdNumM- '.$ProdNumM.' ProdNumO- '.$ProdNumO.'<br />';


it would at least tell you if your SELECT queries are getting anything?


I am puzzled because the Module while loop (the one that you say is working) is in the middle, I would think that the first or last would be the working one.

you may or may not like to add a debug echo output in the loop for -

while ($product = $prodListp->fetch_object()) {

to see if it is the loop not running or it is placing values that can not be accessed or other errors?


sorry , I just noticed, I was copy and pasting, and not giving you the correct logic for the select statement , maybe this is better -
'SELECT ID, Naam, Prijs, MaxBestel, Omschrijving, Inhoud FROM Producten WHERE Type= "Pakket"  OR Type= "Optie"  OR Type= "Module" AND Actief= 1 ORDER BY Sortering'

this is untested but you want all of the Types, so OR might do for it, instead of AND, but it may require a grouping or something else to give the wanted return? ?
What I want is to split the different types into separate tables.
In my current setup I accomplished that by creating separate queries and load them into the form one by one.
In your query you basically select all the type so you might as well do:
'SELECT ID, Naam, Prijs, MaxBestel, Omschrijving, Inhoud FROM Producten WHERE Actief= 1 ORDER BY Sortering'

Open in new window

OK, I am just finding what you need or want to do, and I see some of that now, but dealing with data retrieval from a MySQL data set by queries is a subject I can not hope to shed much useful information about, since it is a very large subject, but you do not seem like a beginner in SQL language, so I will add my views to try and help you with this.

I am unaware of what your problems may be except what you tell me, and you say - "But the only producttype that is presented in the order is of type 'Module' "

I am guessing that after the 3 while ($product = $prodListm->fetch_object())  loops the array $aryOrder has only the  - Type= "Module" - amount ordered numbers in it ? ?

so from your last post, your query code might look like this where FROM has a different Table name for each query -
if ($prodListm = $mysqli->query('SELECT ID, Naam, Prijs, MaxBestel, Omschrijving, Inhoud FROM newProducten WHERE Actief= 1 AND Type= "Module" ORDER BY Sortering'))
    {
    $ProdNumM = $prodListm->num_rows;
    }

I can not be concerned with what info or table entries you write in your SELECT query, only that the query is mostly formatted correctly and returns some data you can use for this learning experiment.

If you are using 3 different queries and fetch_object() loops, and you do not get the results you expect in the $aryOrder array, then you can place debug echo statements in locations of this code that will tell you where your data gets lost or not retrieved from the database. I looked and did not see anything that seemed to cause this, but it's easy to over look a misplaced {  or other arrangement error to cause a problem with the time I have to deal with this.

What you might try is using 3 separate $aryOrder arrays, instead of one, particularly if you use more than one table to query, as the ID will not be unique in different tables.

$aryOrderPak = array();
$aryOrderMod = array();
$aryOrderOpt = array();

while ($product = $prodListm->fetch_object()) {// get a row of database result one at a time
    if (is_numeric($_POST[$product->Naam]) && (((int) $_POST[$product->Naam]) > 0))
     // you MUST test the POST values for allowed input
    $aryOrderMod[$product->ID] = array((int) $_POST[$product->Naam], $product->Naam, $product->Prijs, $product->MaxBestel);
    // add to $aryOrderMod if order is above zero
    unset($product); // release memory
    }

and test the 3 arrays for correct data in a debug echo output, maybe after the three fetch_object() loops -
echo 'fetch_object results, Pak- '.count($aryOrderPak).' Mod- '.count($aryOrderMod).' Opt- '.count($aryOrderOpt).'<br />;

Of course maybe you could change the array identifier to some other unique entry for multiple tables-
$aryOrder[$product->Naam] = array((int) $_POST[$product->Naam], $product->ID, $product->Prijs, $product->MaxBestel);
and maybe use a single array ? ?

There are many different code possiblities, so my suggestions are limited to what I know about, I am mostly trying to show you ways to DEBUG and locate errors as you progress in your development of this.

> I am guessing that after the 3 while ($product = $prodListm->fetch_object())  loops the array
> $aryOrder has only the  - Type= "Module" - amount ordered numbers in it ? ?
Yes, that is correct.

so from your last post, your query code might look like this where FROM has a different Table name for each query -
if ($prodListm = $mysqli->query('SELECT ID, Naam, Prijs, MaxBestel, Omschrijving, Inhoud FROM newProducten WHERE Actief= 1 AND Type= "Module" ORDER BY Sortering'))
    {
    $ProdNumM = $prodListm->num_rows;
    }
No, the different producttypes are all placed in the same table "Producten".

Using three arays seems to be a solution. I'll try that.
Using three arays didn't solve anything.
Somehow the $aryOrder never contains any products except for the selection of type "Module".
Also when I don't order at least quantity one of the main product, no products are presented in the order.

Once again.

There are multiple productstypes. These products need to be presented in a separate <table>. This works fine now.
Ordering these products works currently only for products of the type where the main-products is part of.
Currently only order of type (same as main-product) can be ordered, but only when also main-product is ordered.

How to solve this?
OK, I will try and redo the whole code to get it to work as you have stated, but I am not sure of the way you want to use the "Main Product" as something that MUST be ordered,  You say in the question here -

There is one main product. If the quantity of any other product exceeds the quantity of the main product, a message need to be given: "Quantity of the main product must be at equal to or greater than any ordered quantity for any other product"

So In my thinking, the main product MUST have at least ONE ordered, and then in your last post you say -
Also when I don't order at least quantity one of the main product, no products are presented in the order.

Maybe you are not explaining it for the "Main Product" as it relates to the multiple productstypes, but I fail to see what you need for restrictions where you say for "other products can NOT exceed the quantity of the main product,", is this ALL productstypes? I guess not since you are complaining about the separate arrays not getting the orders.
Is the main product always in the type of "Module", ? I will set up my code and only look for the main product in the Module, since looking for main product and assigning a test for three different arrays according to Type would add to the complexity.

Please forget adjusting the code. I have adjusted some code I found of the internet.which works perfectly after I adjusted it to my needs (most of all lay-out / presentation).
Source I used as base: http://v3.thewatchmakerproject.com/journal/276/building-a-simple-php-shopping-cart
I can order and show the content of the order basket.
Also I added calculation of the discount (based on your code).

What is still missing?
1. Checking the minimum and maximum orderquantities for certain products
2. The main thing that is missing though, is the actual processing of the order.

For now sending the order by E-mail to the customer and myself would be fine. Later I want to add some way of direct payment possibility. I'm still looking how the get from the orderbasket to an E-mail.
ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you very much.