Commit a281a4a4 authored by Malcolm Blaney's avatar Malcolm Blaney

Biggest change in this update is rewriting the stock import system.

It now imports the whole file without user interaction, this
required adding a new concept of supplier availability to the
stock table. Other changes include: allowing existing users to be
selected from the sell page, their payment can also be delayed by
selecting the "account" option during the sale. Purchasing
variable priced items now calculates a base price depending on the
purchaser's buyer group. This is the amount the supplier is credited
for. The purchase page can now remain open for multiple purchasing
days by using a comma separated list for "co-op-day".
parent a9a587d9
......@@ -377,9 +377,16 @@ class Banking extends Base {
}
public function SaveNextWeek($us_next_week) {
$co_op_day = $this->Substitute("co-op-day");
// If co-op-day contains commas, assume this is multiple weekdays in which
// case the save next week option is not used.
if (strpos($co_op_day, ",") !== false) {
return;
}
// Use the configured day of the week for the co-op to find the next time
// the co-op will be held.
$timestamp = strtotime("next ".$this->Substitute("co-op-day"));
$timestamp = strtotime("next ".$co_op_day);
$mysqli = connect_db();
$user_query = "";
......@@ -400,6 +407,12 @@ class Banking extends Base {
public function CountNextWeek() {
$co_op_day = $this->Substitute("co-op-day");
// If co-op-day contains commas, assume this is multiple weekdays in which
// case the count next week option is not used.
if (strpos($co_op_day, ",") !== false) {
return array(0, time());
}
$timestamp = strtotime("this ".$co_op_day);
// Want to make sure today is not set as the value if today is co-op day.
if ($timestamp < strtotime("24 hours")) {
......
......@@ -904,7 +904,8 @@ class Cart extends Base {
$payment_method .= '<label for="'.$id.'">Payment:</label>'.
'<select id="'.$id.'">'.
'<option value="cash">Cash</option>'.
'<option value="eftpos">Eftpos</option>';
'<option value="eftpos">Eftpos</option>'.
'<option value="account">Account</option>';
}
$min = $display_cash ? 0 : 1;
$query = 'SELECT name FROM cart_method WHERE user = "'.$this->owner.'" '.
......
......@@ -689,7 +689,7 @@ class Groupwizard extends Base {
'<div class="form-spacing">'.
'<label for="groupwizard-stock-retail-percent">The markup for '.
'retail:</label>'.
'<input id="groupwizard-stock-retail-precent" size="5" '.
'<input id="groupwizard-stock-retail-percent" size="5" '.
'maxlength="5" value="'.$this->Value("stock-wholesale-percent").'">'.
'</div>'.
'<div class="form-spacing">'.
......
......@@ -42,6 +42,12 @@ class Manager extends Base {
$stock = new Stock($this->user, $this->owner);
$object["products"] = $stock->AllProducts();
// Need wholesale and retail percent to calculate base price for variably
// priced products.
$object["wholesalePercent"] =
(float)$this->Substitute("stock-wholesale-percent");
$object["retailPercent"] =
(float)$this->Substitute("stock-retail-percent");
}
else if ($action == "search") {
// Purchase->Search won't return any data if the system_group doesn't
......
......@@ -524,6 +524,7 @@ class Payment extends Base {
public function Save($user, $time, $total, $method = "cash") {
$mysqli = connect_db();
$total = number_format($total, 2, ".", "");
$query = 'INSERT INTO payments VALUES ("'.$user.'", '.$time.', "", '.
$total.', "'.$method.'", "'.$this->user->name.'") '.
'ON DUPLICATE KEY UPDATE amount = '.$total.', comment = "'.$method.'"';
......
......@@ -116,7 +116,18 @@ class Purchase extends Base {
$set_order_mode = true;
}
else {
$co_op_day = strtotime($co_op_day_text);
$co_op_day = 0;
// If $co_op_day_text contains commas, assume this is multiple weekdays
// and split it into an array and check if date("l") is in it.
if (strpos($co_op_day_text, ",") !== false) {
$today = date("l");
if (in_array($today, explode(",", $co_op_day_text))) {
$co_op_day = strtotime($today);
}
}
else {
$co_op_day = strtotime($co_op_day_text);
}
// Check if today is co-op-day, order mode will be used if not.
if ((time() > $co_op_day) && (time() < $co_op_day + 86400)) {
// Check if this group should force into order mode on co-op-day.
......@@ -817,6 +828,13 @@ class Purchase extends Base {
}
public function PreOrder($user, $timestamp) {
$co_op_day = $this->Substitute("co-op-day");
// If co-op-day contains commas, assume this is multiple weekdays in which
// case the pre order option is not used.
if (strpos($co_op_day, ",") !== false) {
return;
}
$pre_order_done = false;
$mysqli = connect_db();
// Don't update purchases if PreOrder has already been called for this
......@@ -840,7 +858,6 @@ class Purchase extends Base {
// Need to find the most recent co-op date to copy from. This will either
// be today if it's co-op-day, as providing a day name to strtotime returns
// the start of the day (midnight), otherwise find last week's date.
$co_op_day = $this->Substitute("co-op-day");
$start = strtotime($co_op_day);
if ($start > time()) {
$start = strtotime("last ".$co_op_day);
......@@ -1271,9 +1288,15 @@ class Purchase extends Base {
}
public function RemoveAllPurchases() {
$co_op_day = $this->Substitute("co-op-day");
// If co-op-day contains commas, assume this is multiple weekdays in which
// case the remove purchases option is not used.
if (strpos($co_op_day, ",") !== false) {
return;
}
// Only remove purchases around the time of the next co-op-day (ie this
// weeks orders).
$co_op_day = $this->Substitute("co-op-day");
$next_co_op = strtotime($co_op_day);
if ($next_co_op < time()) {
$next_co_op = strtotime("next ".$co_op_day);
......@@ -1657,9 +1680,13 @@ class Purchase extends Base {
$user = "";
$values = "";
$total = 0;
$count = 0;
$existing_user = false;
$products = array();
$us_data = json_decode($_POST["data"], true);
$us_user_index = json_decode($_POST["userIndex"], true);
$payment = new Payment($this->user, $this->owner);
$organiser = new Organiser($this->user, $this->owner);
// Get available usernames for this sales data.
do {
......@@ -1675,19 +1702,38 @@ class Purchase extends Base {
} while ($exists);
foreach ($us_data as $us_user => $us_values) {
// Need to know when at the last entry in the array.
$count++;
if ($us_user === "") continue;
if (!is_array($us_values)) continue;
$total = 0;
$purchase_count = count($us_values);
if ($purchase_count > 0) {
$user = "buyer_".$time."_";
// The given value for user is just an index.
$user .= $mysqli->escape_string($us_user);
$query = 'INSERT INTO users VALUES ("'.$user.'", "", "", "'.
$this->user->group.'", 0, "", '.$time.', "")';
if (!$mysqli->query($query)) {
$this->Log("Purchase->SaveSales 1: ".$mysqli->error);
$user = "";
$existing_user = false;
// Check if a username was given, otherwise create one from the index.
if (isset($us_user_index[$us_user])) {
$user = $mysqli->escape_string($us_user_index[$us_user]);
error_log("Saving purchase for user: ".$user);
if ($user !== "" && !$organiser->MatchUser($user)) {
$this->Log("Purchase->SaveSales 1: User ".$user." not found.");
continue;
}
$existing_user = true;
}
if ($user === "") {
$user = "buyer_".$time."_".$mysqli->escape_string($us_user);
error_log("Saving purchase for user: ".$user);
$query = 'INSERT INTO users VALUES ("'.$user.'", "", "", '.
'"'.$this->user->group.'", 0, "", '.$time.', "")';
if (!$mysqli->query($query)) {
$this->Log("Purchase->SaveSales 2: ".$mysqli->error);
}
$this->NewUser($user);
$payment->NewUser($user, false);
$existing_user = false;
}
for ($i = 0; $i < $purchase_count; $i++) {
......@@ -1714,21 +1760,28 @@ class Purchase extends Base {
$products[$supplier][$name] = $quantity;
}
}
$this->NewUser($user);
$payment->NewUser($user, false);
$total = number_format($total, 2, ".", "");
$payment->Save($user, $time, $total);
// The last payment is saved separately below to check the payment
// method, which only applies to the last user (the rest are cash).
if ($count < count($us_data) && $total != 0) {
$payment->Save($user, $time, $total);
}
}
}
// If a payment method is given, it only applies to the last user.
// Make sure that the last user has purchases (ie total != 0).
if (isset($payment_method) && $total != 0) {
$payment->Save($user, $time, $total, $payment_method);
if ($total != 0) {
// An existing user can delay payment by leaving the purchase as a
// balance against their account, which they will be invoiced for.
if (!$existing_user && $payment_method == "account") {
$payment_method = "Error: Payment method 'account' selected, ".
"only existing users can be invoiced.";
}
if ($payment_method != "account") {
$payment->Save($user, $time, $total, $payment_method);
}
}
if ($values !== "") {
$query = 'INSERT INTO purchase VALUES '.$values;
if (!$mysqli->query($query)) {
$this->Log("Purchase->SaveSales 2: ".$mysqli->error);
$this->Log("Purchase->SaveSales 3: ".$mysqli->error);
}
}
$mysqli->close();
......@@ -1824,11 +1877,18 @@ class Purchase extends Base {
// mode to set the current date, and purchase mode to set the date for
// next week so purchases can be added with that date.
$co_op_day = $this->Substitute("co-op-day");
if (!$next_co_op = strtotime($co_op_day)) {
return array("error" => "Purchase day not set.");
// If co-op-day contains commas, assume this is multiple weekdays in which
// case ordering is not used. (So just set $next_co_op to now.)
if (strpos($co_op_day, ",") !== false) {
$next_co_op = time();
}
if ($next_co_op < time()) {
$next_co_op = strtotime("next ".$co_op_day);
else {
if (!$next_co_op = strtotime($co_op_day)) {
return array("error" => "Purchase day not set.");
}
if ($next_co_op < time()) {
$next_co_op = strtotime("next ".$co_op_day);
}
}
$object = array();
......@@ -1973,6 +2033,11 @@ class Purchase extends Base {
}
$object["nextWeek"] = array();
$object["processed"] = array();
// Need wholesale and retail percent to calculate base price for variably
// priced products.
$object["wholesalePercent"] =
(float)$this->Substitute("stock-wholesale-percent");
$object["retailPercent"] = (float)$this->Substitute("stock-retail-percent");
return $object;
}
......
......@@ -588,8 +588,10 @@ class Reader extends Base {
private function RemoveFeed($error) {
// Find the feed url in the error message.
$pattern = "/A feed could not be found at (.*?)\. /";
if (preg_match($pattern, $error, $matches)) {
$pattern1 = "/A feed could not be found at (.*?)\. /";
$pattern2 = "/^(.*) is invalid XML/";
if (preg_match($pattern1, $error, $matches) ||
preg_match($pattern2, $error, $matches)) {
$feed = $matches[1];
$mysqli = connect_db();
// Notify users who subscribe to this feed that it's been removed.
......
......@@ -31,10 +31,19 @@ class Sell extends Base {
if ($us_action == "list") {
$stock = new Stock($this->user, $this->owner);
$banking = new Banking($this->user, $this->owner);
list($users, $buyerGroup) = $banking->AllBuyers();
// Cast data to object required for json.
return array("data" => (object)array(),
"processed" => array(),
"products" => $stock->AvailableProducts());
"userIndex" => array(),
"users" => $users,
"buyerGroup" => $buyerGroup,
"products" => $stock->AvailableProducts(),
"wholesalePercent" =>
(float)$this->Substitute("stock-wholesale-percent"),
"retailPercent" =>
(float)$this->Substitute("stock-retail-percent"));
}
if ($us_action == "save") {
$purchase = new Purchase($this->user, $this->owner);
......@@ -170,6 +179,10 @@ class Sell extends Base {
'<div class="form-spacing">'.
$payment_methods.
'</div>'.
'<div class="form-spacing">'.
'<label for="purchase-name-input">Username:</label>'.
'<input id="purchase-name-input" size="15" maxlength="50">'.
'</div>'.
'<div class="form-spacing">'.
'<label for="purchase-product-input">Product:</label>'.
'<input id="purchase-product-input" size="15" maxlength="100">'.
......
......@@ -214,18 +214,6 @@ class Spark extends Base {
public function Update() {
// This is called when the version of the module is updated,
// to provide a way to update or modify tables etc..
$mysqli = connect_db();
$query = 'CREATE TABLE IF NOT EXISTS spark_share ('.
'user VARCHAR(50) NOT NULL,'.
'box_id INT UNSIGNED NOT NULL,'.
'spark_id VARCHAR(32) NOT NULL,'.
'system_group VARCHAR(50),'.
'PRIMARY KEY(user, box_id, spark_id, system_group)'.
') ENGINE=MyISAM';
if (!$mysqli->query($query)) {
$this->Log("Spark->Update: ".$mysqli->error);
}
$mysqli->close();
}
public function UpdateScript($path) {
......@@ -488,8 +476,6 @@ class Spark extends Base {
return;
}
// Notify other modules that weight has been updated.
$this->Notify($id, "spark", "spark", "", 0, true);
// If "updated" flag is set need to echo current wifi credentials.
$updated = false;
$query = 'SELECT updated FROM spark WHERE user = "'.$this->owner.'" '.
......@@ -527,6 +513,8 @@ class Spark extends Base {
// Output the string that is read by the spark.
// An ampersand is added to denote the end of the data.
echo $credentials."&";
// Notify other modules that credentials were sent.
$this->Notify($id, "spark", "spark", "", 0, true);
}
$mysqli->close();
}
......
This diff is collapsed.
......@@ -127,29 +127,35 @@ class Summary extends Base {
$purchase_page .= "order=true";
$pre_order_text = $this->Substitute("summary-pre-order", "/!final/",
$this->Substitute("pre-order-final"));
// If today is co-op-day, don't show items ordered message.
$co_op_day = strtotime($this->Substitute("co-op-day"));
if ((time() < $co_op_day) || (time() > $co_op_day + 86400)) {
$items = $purchase->Data(time(), strtotime("7 days"));
if (empty($items)) {
if ($pre_order_available) {
$ordered_text = "You haven't placed an order yet.".
'<br><b>You can <a class="purchase-page-link" '.
'href="'.$purchase_page.'">order here</a> '.$pre_order_text.'.</b>';
$co_op_day = $this->Substitute("co-op-day");
// If co-op-day contains commas, assume this is multiple weekdays in which
// case the ordering message is not shown.
if (strpos($co_op_day, ",") === false) {
// If today is co-op-day, also don't show items ordered message.
$co_op_day = strtotime($this->Substitute("co-op-day"));
if ((time() < $co_op_day) || (time() > $co_op_day + 86400)) {
$items = $purchase->Data(time(), strtotime("7 days"));
if (empty($items)) {
if ($pre_order_available) {
$ordered_text = "You haven't placed an order yet.".
'<br><b>You can <a class="purchase-page-link" '.
'href="'.$purchase_page.'">order here</a> '.
$pre_order_text.'.</b>';
}
}
}
else {
$ordered_text = 'You have items ordered.';
if ($pre_order_available) {
$ordered_text .= '<br><b>You can <a class="purchase-page-link" '.
'href="'.$purchase_page.'">change them here</a> '.$pre_order_text.
'.</b>';
else {
$ordered_text = 'You have items ordered.';
if ($pre_order_available) {
$ordered_text .= '<br><b>You can <a class="purchase-page-link" '.
'href="'.$purchase_page.'">change them here</a> '.$pre_order_text.
'.</b>';
}
}
}
}
else if ($pre_order_available) {
$ordered_text = '<b>You can <a class="purchase-page-link" '.
'href="'.$purchase_page.'">order here</a> '.$pre_order_text.'.</b>';
else if ($pre_order_available) {
$ordered_text = '<b>You can <a class="purchase-page-link" '.
'href="'.$purchase_page.'">order here</a> '.$pre_order_text.'.</b>';
}
}
return '<p>Hello '.$name.',<br>'.
......
......@@ -89,12 +89,14 @@ var user=$("#manager-username-input").val();if(user===""||!currentProduct){retur
var product=currentProduct.name;if(product!==$("#manager-product-input").val()){alert("Product not found.");resetForm();return false;}
var supplier=currentProduct.user;if(supplier!==$("#manager-supplier-input").val()){alert("Supplier not found.");resetForm();return false;}
var priceLevel=manager.buyerGroup[user];if(!priceLevel){priceLevel="retail";}
var price=currentProduct[priceLevel].toFixed(2);if(currentProduct.unit==="variable"){price=$("#manager-price-input").val();}
var price=currentProduct[priceLevel];var basePrice=currentProduct.price;if(currentProduct.unit==="variable"){price=parseFloat($("#manager-price-input").val());if(!price){$("#manager-price-input").val("");return false;}
basePrice=price;if(priceLevel==="wholesale"&&manager.wholesalePercent){basePrice-=basePrice*manager.wholesalePercent/100;}
else if(priceLevel==="retail"&&manager.retailPercent){basePrice-=basePrice*manager.retailPercent/100;}}
var quantity=parseFloat($("#manager-quantity-input").val());if(!quantity||quantity<0){alert("Quantity required.");return false;}
var total=(quantity*price).toFixed(2);var timestamp=parseInt($.datepicker.formatDate("@",$("#manager-date-input").datepicker("getDate")),10);if(!timestamp){alert("Date required.");return false;}
if(currentDate&&timestamp>currentDate-oneDay&&timestamp<currentDate+oneDay){timestamp=currentDate;}
else{currentDate=null;}
saving=true;$("#manager-form .submit").button("option","disabled",true);dobrado.log("Saving purchase...","info");$.post("/php/request.php",{request:"manager",username:user,timestamp:timestamp,product:product,supplier:supplier,quantity:quantity,price:price,basePrice:currentProduct.price.toFixed(2),action:"submit",url:location.href,token:dobrado.token},function(response){if(dobrado.checkResponseError(response,"manager submit")){saving=false;$("#manager-form .submit").button("option","disabled",false);return;}
saving=true;$("#manager-form .submit").button("option","disabled",true);dobrado.log("Saving purchase...","info");$.post("/php/request.php",{request:"manager",username:user,timestamp:timestamp,product:product,supplier:supplier,quantity:quantity,price:price.toFixed(2),basePrice:basePrice.toFixed(2),action:"submit",url:location.href,token:dobrado.token},function(response){if(dobrado.checkResponseError(response,"manager submit")){saving=false;$("#manager-form .submit").button("option","disabled",false);return;}
var data=JSON.parse(response);var selectedRow=0;var newItem=true;if(currentDate){$.each(purchase,function(i,item){if(item.name===product&&item.date===currentDate&&item.user===user){purchase[i].supplier=supplier;purchase[i].quantity=quantity;purchase[i].price=price;purchase[i].total=total;if(managerGrid){selectedRow=i;}
newItem=false;}
else if(!data.done&&item.user===user&&item.name==="surcharge"&&item.date===data.date){purchase[i]=data;}});}
......
......@@ -610,9 +610,22 @@ if (!this.dobrado.manager) {
if (!priceLevel) {
priceLevel = "retail";
}
var price = currentProduct[priceLevel].toFixed(2);
var price = currentProduct[priceLevel];
var basePrice = currentProduct.price;
if (currentProduct.unit === "variable") {
price = $("#manager-price-input").val();
price = parseFloat($("#manager-price-input").val());
// When price is variable need to check for valid input.
if (!price) {
$("#manager-price-input").val("");
return false;
}
basePrice = price;
if (priceLevel === "wholesale" && manager.wholesalePercent) {
basePrice -= basePrice * manager.wholesalePercent / 100;
}
else if (priceLevel === "retail" && manager.retailPercent) {
basePrice -= basePrice * manager.retailPercent / 100;
}
}
var quantity = parseFloat($("#manager-quantity-input").val());
if (!quantity || quantity < 0) {
......@@ -648,8 +661,8 @@ if (!this.dobrado.manager) {
product: product,
supplier: supplier,
quantity: quantity,
price: price,
basePrice: currentProduct.price.toFixed(2),
price: price.toFixed(2),
basePrice: basePrice.toFixed(2),
action: "submit",
url: location.href,
token: dobrado.token },
......@@ -842,6 +855,7 @@ if (!this.dobrado.manager) {
resetForm();
return false;
}
// showPurchase sets currentProduct and input values.
showPurchase(selected[currentRemove++]);
}
......
......@@ -131,11 +131,14 @@ return false;}
function addFromEnter(event){if(event.which===13){event.preventDefault();add();}}
function add(){var user=$("#purchase-name-input").val();if(user===""||!currentProduct){return false;}
var product=currentProduct.name;if(product!==$("#purchase-product-input").val()){alert("Product not found.");resetForm();return false;}
var accumulative=true;var supplier=currentProduct.user;var price=currentProduct[purchase.buyerGroup[user]];if(currentProduct.unit==="variable"){price=parseFloat($("#purchase-price-input").val());if(!price){$("#purchase-price-input").val("");return false;}
var accumulative=true;var supplier=currentProduct.user;var priceLevel=purchase.buyerGroup[user];if(!priceLevel){priceLevel="retail";}
var price=currentProduct[priceLevel];var basePrice=currentProduct.price;if(currentProduct.unit==="variable"){price=parseFloat($("#purchase-price-input").val());if(!price){$("#purchase-price-input").val("");return false;}
basePrice=price;if(priceLevel==="wholesale"&&purchase.wholesalePercent){basePrice-=basePrice*purchase.wholesalePercent/100;}
else if(priceLevel==="retail"&&purchase.retailPercent){basePrice-=basePrice*purchase.retailPercent/100;}
accumulative=false;}
var quantity=parseFloat($("#purchase-quantity-input").val());if(!quantity||quantity<0){return false;}
var time=parseInt($.datepicker.formatDate("@",$("#purchase-date-input").datepicker("getDate")),10);if(purchase.dateNextWeek&&time>purchase.dateNextWeek-oneDay&&!confirm("Add item for next week?")){return false;}
update(user,product,supplier,currentProduct.grower,price,currentProduct.price,quantity,time,accumulative,true);return false;}
update(user,product,supplier,currentProduct.grower,price,basePrice,quantity,time,accumulative,true);return false;}
function update(user,product,supplier,grower,price,basePrice,quantity,time,accumulative,updateGrid){var elapsed=new Date().getTime()-startTime;if(elapsed>oneDay){alert("Please reload the page before continuing");return false;}
var purchaseTime=purchase.date+elapsed;if((time>purchaseTime&&time-purchaseTime>oneDay)||(time<purchaseTime&&purchaseTime-time>oneDay)){purchaseTime=time;}
var itemTotal=quantity*price;var selectedRow=0;var newItem=true;if(!purchase.data[user]){purchase.data[user]=[];}
......
......@@ -944,7 +944,12 @@ if (!this.dobrado.purchase) {
}
var accumulative = true;
var supplier = currentProduct.user;
var price = currentProduct[purchase.buyerGroup[user]];
var priceLevel = purchase.buyerGroup[user];
if (!priceLevel) {
priceLevel = "retail";
}
var price = currentProduct[priceLevel];
var basePrice = currentProduct.price;
if (currentProduct.unit === "variable") {
price = parseFloat($("#purchase-price-input").val());
// When price is variable need to check for valid input.
......@@ -952,6 +957,13 @@ if (!this.dobrado.purchase) {
$("#purchase-price-input").val("");
return false;
}
basePrice = price;
if (priceLevel === "wholesale" && purchase.wholesalePercent) {
basePrice -= basePrice * purchase.wholesalePercent / 100;
}
else if (priceLevel === "retail" && purchase.retailPercent) {
basePrice -= basePrice * purchase.retailPercent / 100;
}
accumulative = false;
}
var quantity = parseFloat($("#purchase-quantity-input").val());
......@@ -969,7 +981,7 @@ if (!this.dobrado.purchase) {
}
update(user, product, supplier, currentProduct.grower, price,
currentProduct.price, quantity, time, accumulative, true);
basePrice, quantity, time, accumulative, true);
return false;
}
......
This diff is collapsed.
......@@ -114,6 +114,9 @@ if (!this.dobrado.sell) {
$("#purchase-form .add").button().click(add);
$("#purchase-form").keypress(addFromEnter);
// The change event gets called before the autocomplete updates, so delay.
$("#purchase-name-input").val("").change(function() {
setTimeout(function() { showUser(); }, 10);
});
$("#purchase-product-input").val("").change(function() {
setTimeout(function() { showProduct(); }, 10);
});
......@@ -372,6 +375,8 @@ if (!this.dobrado.sell) {
sell = JSON.parse(response);
sell.sparkID = sparkID;
sell.updateQuantity = updateQuantity;
$("#purchase-name-input").autocomplete({ source: sell.users,
select: showUser });
updateProducts();
// Also save the new purchase data to localStorage if available.
if (dobrado.localStorage()) {
......@@ -380,6 +385,25 @@ if (!this.dobrado.sell) {
});
}
function showUser(event, ui) {
var username = $("#purchase-name-input").val();
if (ui) {
username = ui.item.value;
}
if (username !== "" && $.inArray(username, sell.users) === -1) {
// If a new account was just created it won't be in sell.users.
alert("If an account was just created for " + username +
" please reload the page.");
$("#purchase-name-input").val("");
username = "";
}
// If a username is selected want to match it with the index when saving.
sell.userIndex[user] = username;
if (dobrado.localStorage()) {
localStorage.sell = JSON.stringify(sell);
}
}
function showPurchase(row) {
var data = sell.data[user][row];
$("#purchase-product-input").val(data.name);
......@@ -411,6 +435,13 @@ if (!this.dobrado.sell) {
}
function showProduct(event, ui) {
// Check if a username has been selected, otherwise use retail price.
var username = $("#purchase-name-input").val();
var price = "retail";
if (username !== "") {
price = sell.buyerGroup[username];
}
var productFound = false;
var product = $("#purchase-product-input").val();
if (ui) {
......@@ -424,11 +455,11 @@ if (!this.dobrado.sell) {
// Clear the quantity input when the product changes.
if (currentProduct.unit === "variable") {
$("#purchase-quantity-input").val("1").spinner("disable");
$("#purchase-price-input").val(item.retail.toFixed(2));
$("#purchase-price-input").val(item[price].toFixed(2));
$("#purchase-price-input").attr("readonly", false);
}
else {
$("#purchase-price-input").val("($" + item.retail.toFixed(2) + "/" +
$("#purchase-price-input").val("($" + item[price].toFixed(2) + "/" +
item.unit + ")");
$("#purchase-price-input").attr("readonly", true);
if (currentProduct.unit === "kg" && currentWeight !== "") {
......@@ -467,6 +498,13 @@ if (!this.dobrado.sell) {
return;
}
// Check if a username has been selected, otherwise use retail price.
var username = $("#purchase-name-input").val();
var price = "retail";
if (username !== "") {
price = sell.buyerGroup[username];
}
var quantity = 0;
if (ui && "value" in ui) {
// value is set for the 'spin' event, before the input field is updated.
......@@ -488,9 +526,9 @@ if (!this.dobrado.sell) {
}
if (currentProduct.unit !== "variable") {
var total = quantity * currentProduct.retail;
var total = quantity * currentProduct[price];
$("#purchase-price-input").val("$" + total.toFixed(2) + " @ ($" +
currentProduct.retail.toFixed(2) +
currentProduct[price].toFixed(2) +
"/" + currentProduct.unit + ")");
}
}
......@@ -571,7 +609,13 @@ if (!this.dobrado.sell) {
}
var accumulative = true;
var supplier = currentProduct.user;
var price = currentProduct.retail;
var priceLevel = "retail";
var username = $("#purchase-name-input").val();
if (username !== "") {
priceLevel = sell.buyerGroup[username];
}
var price = currentProduct[priceLevel];
var basePrice = currentProduct.price;
if (currentProduct.unit === "variable") {
price = parseFloat($("#purchase-price-input").val());
// When price is variable need to check for valid input.
......@@ -579,14 +623,20 @@ if (!this.dobrado.sell) {
$("#purchase-price-input").val("");
return false;
}
basePrice = price;
if (priceLevel === "wholesale" && sell.wholesalePercent) {
basePrice -= basePrice * sell.wholesalePercent / 100;
}
else if (priceLevel === "retail" && sell.retailPercent) {
basePrice -= basePrice * sell.retailPercent / 100;
}
accumulative = false;
}
var quantity = parseFloat($("#purchase-quantity-input").val());
if (!quantity || quantity < 0) {
return false;
}
update(product, supplier, price, currentProduct.price, quantity,
accumulative);
update(product, supplier, price, basePrice, quantity, accumulative);
return false;
}
......@@ -671,6 +721,7 @@ if (!this.dobrado.sell) {
}
$.post("/php/request.php", { request: "sell",
data: JSON.stringify(sell.data),
userIndex: JSON.stringify(sell.userIndex),
action: "save",
method: method,
url: location.href,
......@@ -691,17 +742,25 @@ if (!this.dobrado.sell) {
}
function save() {
var username = "";
if (sell.userIndex[user]) {
username = sell.userIndex[user];
}
// Load the payment dialog for non cash payments.
var method = $("#purchase-payment-input").val();
if (method && method !== "cash" && method !== "eftpos") {
if (method !== "cash" && method !== "eftpos" && method !== "account") {
$("#sell-checkout-message").html("Please enter your contact details:");
$("#sell-customer-details-form").show();
$("#sell-checkout-dialog").dialog("open");
}
else if (method === "account" && username === "") {
alert("Payment method 'account' can only be used for an existing user.");
}
else {
dobrado.log("Saving...", "info");
$.post("/php/request.php", { request: "sell",
data: JSON.stringify(sell.data),
userIndex: JSON.stringify(sell.userIndex),
action: "save",
method: method,
url: location.href,
......@@ -720,16 +779,19 @@ if (!this.dobrado.sell) {
$(".sell .save").button("option", "disabled", true);